diff --git a/.config/docker_example.env b/.config/docker_example.env index 4fe8e76b78..c61248da2e 100644 --- a/.config/docker_example.env +++ b/.config/docker_example.env @@ -1,5 +1,11 @@ +# misskey settings +# MISSKEY_URL=https://example.tld/ + # db settings POSTGRES_PASSWORD=example-misskey-pass +# DATABASE_PASSWORD=${POSTGRES_PASSWORD} POSTGRES_USER=example-misskey-user +# DATABASE_USER=${POSTGRES_USER} POSTGRES_DB=misskey +# DATABASE_DB=${POSTGRES_DB} DATABASE_URL="postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}" diff --git a/.config/docker_example.yml b/.config/docker_example.yml index 42ac18de1b..bd0ad2872a 100644 --- a/.config/docker_example.yml +++ b/.config/docker_example.yml @@ -6,6 +6,7 @@ #───┘ URL └───────────────────────────────────────────────────── # Final accessible URL seen by a user. +# You can set url from an environment variable instead. url: https://example.tld/ # ONCE YOU HAVE STARTED THE INSTANCE, DO NOT CHANGE THE @@ -38,9 +39,11 @@ db: port: 5432 # Database name + # You can set db from an environment variable instead. db: misskey # Auth + # You can set user and pass from environment variables instead. user: example-misskey-user pass: example-misskey-pass @@ -161,12 +164,12 @@ id: 'aidx' #clusterLimit: 1 # Job concurrency per worker -# deliverJobConcurrency: 128 -# inboxJobConcurrency: 16 +# deliverJobConcurrency: 16 +# inboxJobConcurrency: 4 # Job rate limiter # deliverJobPerSec: 128 -# inboxJobPerSec: 32 +# inboxJobPerSec: 64 # Job attempts # deliverJobMaxAttempts: 12 diff --git a/.config/example.yml b/.config/example.yml index b11cbd1373..0d525f61c4 100644 --- a/.config/example.yml +++ b/.config/example.yml @@ -230,15 +230,15 @@ id: 'aidx' #clusterLimit: 1 # Job concurrency per worker -#deliverJobConcurrency: 128 -#inboxJobConcurrency: 16 +#deliverJobConcurrency: 16 +#inboxJobConcurrency: 4 #relationshipJobConcurrency: 16 # What's relationshipJob?: # Follow, unfollow, block and unblock(ings) while following-imports, etc. or account migrations. # Job rate limiter -#deliverJobPerSec: 128 -#inboxJobPerSec: 32 +#deliverJobPerSec: 1024 +#inboxJobPerSec: 64 #relationshipJobPerSec: 64 # Job attempts diff --git a/.devcontainer/docker-compose.yml b/.devcontainer/compose.yml similarity index 93% rename from .devcontainer/docker-compose.yml rename to .devcontainer/compose.yml index 2809cd2ca4..d02d2a8f4a 100644 --- a/.devcontainer/docker-compose.yml +++ b/.devcontainer/compose.yml @@ -1,5 +1,3 @@ -version: '3.8' - services: app: build: @@ -8,6 +6,7 @@ services: volumes: - ../:/workspace:cached + - node_modules:/workspace/node_modules command: sleep infinity @@ -46,6 +45,7 @@ services: volumes: postgres-data: redis-data: + node_modules: networks: internal_network: diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 31b6212cb5..7ea23e314e 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,6 +1,6 @@ { "name": "Misskey", - "dockerComposeFile": "docker-compose.yml", + "dockerComposeFile": "compose.yml", "service": "app", "workspaceFolder": "/workspace", "features": { @@ -10,7 +10,7 @@ "ghcr.io/devcontainers-contrib/features/corepack:1": {} }, "forwardPorts": [3000], - "postCreateCommand": "sudo chmod 755 .devcontainer/init.sh && .devcontainer/init.sh", + "postCreateCommand": "/bin/bash .devcontainer/init.sh", "customizations": { "vscode": { "extensions": [ diff --git a/.devcontainer/devcontainer.yml b/.devcontainer/devcontainer.yml index beefcfd0a2..d74d741e02 100644 --- a/.devcontainer/devcontainer.yml +++ b/.devcontainer/devcontainer.yml @@ -157,12 +157,12 @@ id: 'aidx' #clusterLimit: 1 # Job concurrency per worker -# deliverJobConcurrency: 128 -# inboxJobConcurrency: 16 +# deliverJobConcurrency: 16 +# inboxJobConcurrency: 4 # Job rate limiter -# deliverJobPerSec: 128 -# inboxJobPerSec: 32 +# deliverJobPerSec: 1024 +# inboxJobPerSec: 64 # Job attempts # deliverJobMaxAttempts: 12 diff --git a/.devcontainer/init.sh b/.devcontainer/init.sh index 729e1a9d2d..55fb1e6fa6 100755 --- a/.devcontainer/init.sh +++ b/.devcontainer/init.sh @@ -2,7 +2,8 @@ set -xe -sudo chown -R node /workspace +sudo chown node node_modules +git config --global --add safe.directory /workspace git submodule update --init corepack install corepack enable diff --git a/.dockerignore b/.dockerignore index 1de0c7982b..f204349160 100644 --- a/.dockerignore +++ b/.dockerignore @@ -7,12 +7,11 @@ Dockerfile build/ built/ db/ -docker-compose.yml +.devcontainer/compose.yml node_modules/ packages/*/node_modules redis/ files/ -misskey-assets/ fluent-emojis/ .pnp.* @@ -28,4 +27,4 @@ fluent-emojis/ .idea/ packages/*/.vscode/ -packages/backend/test/docker-compose.yml +packages/backend/test/compose.yml diff --git a/.github/ISSUE_TEMPLATE/01_bug-report.yml b/.github/ISSUE_TEMPLATE/01_bug-report.yml index ac2b39cc12..315e712c30 100644 --- a/.github/ISSUE_TEMPLATE/01_bug-report.yml +++ b/.github/ISSUE_TEMPLATE/01_bug-report.yml @@ -53,8 +53,8 @@ body: Examples: * Model and OS of the device(s): MacBook Pro (14inch, 2021), macOS Ventura 13.4 * Browser: Chrome 113.0.5672.126 - * Server URL: misskey.io - * Misskey: 13.x.x + * Server URL: misskey.example.com + * Misskey: 2024.x.x value: | * Model and OS of the device(s): * Browser: @@ -74,11 +74,11 @@ body: Examples: * Installation Method or Hosting Service: docker compose, k8s/docker, systemd, "Misskey install shell script", development environment - * Misskey: 13.x.x + * Misskey: 2024.x.x * Node: 20.x.x * PostgreSQL: 15.x.x * Redis: 7.x.x - * OS and Architecture: Ubuntu 22.04.2 LTS aarch64 + * OS and Architecture: Ubuntu 24.04.2 LTS aarch64 value: | * Installation Method or Hosting Service: * Misskey: diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index e8b65dc3b9..5acad83336 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -2,3 +2,7 @@ contact_links: - name: 💬 Misskey official Discord url: https://discord.gg/Wp8gVStHW3 about: Chat freely about Misskey + # 仮 + - name: 💬 Start discussion + url: https://github.com/misskey-dev/misskey/discussions + about: The official forum to join conversation and ask question diff --git a/.github/workflows/api-misskey-js.yml b/.github/workflows/api-misskey-js.yml index 1b7b68b14f..e7db18316c 100644 --- a/.github/workflows/api-misskey-js.yml +++ b/.github/workflows/api-misskey-js.yml @@ -4,10 +4,11 @@ on: push: paths: - packages/misskey-js/** + - .github/workflows/api-misskey-js.yml pull_request: paths: - packages/misskey-js/** - + - .github/workflows/api-misskey-js.yml jobs: report: @@ -20,7 +21,7 @@ jobs: - run: corepack enable - name: Setup Node.js - uses: actions/setup-node@v4.0.2 + uses: actions/setup-node@v4.0.3 with: node-version-file: '.node-version' cache: 'pnpm' diff --git a/.github/workflows/changelog-check.yml b/.github/workflows/changelog-check.yml index f254af0d1f..d4e99f966e 100644 --- a/.github/workflows/changelog-check.yml +++ b/.github/workflows/changelog-check.yml @@ -14,7 +14,7 @@ jobs: - name: Checkout head uses: actions/checkout@v4.1.1 - name: Setup Node.js - uses: actions/setup-node@v4.0.2 + uses: actions/setup-node@v4.0.3 with: node-version-file: '.node-version' diff --git a/.github/workflows/check-misskey-js-autogen.yml b/.github/workflows/check-misskey-js-autogen.yml index 39acad8bc3..3a2a2d5f8d 100644 --- a/.github/workflows/check-misskey-js-autogen.yml +++ b/.github/workflows/check-misskey-js-autogen.yml @@ -28,7 +28,7 @@ jobs: - name: setup node id: setup-node - uses: actions/setup-node@v4.0.2 + uses: actions/setup-node@v4.0.3 with: node-version-file: '.node-version' cache: pnpm diff --git a/.github/workflows/check-misskey-js-version.yml b/.github/workflows/check-misskey-js-version.yml index 325a893605..99c29ac974 100644 --- a/.github/workflows/check-misskey-js-version.yml +++ b/.github/workflows/check-misskey-js-version.yml @@ -6,12 +6,13 @@ on: paths: - packages/misskey-js/package.json - package.json + - .github/workflows/check-misskey-js-version.yml pull_request: branches: [ develop ] paths: - packages/misskey-js/package.json - package.json - + - .github/workflows/check-misskey-js-version.yml jobs: check-version: # ルートの package.json と packages/misskey-js/package.json のバージョンが一致しているかを確認する diff --git a/.github/workflows/docker-develop.yml b/.github/workflows/docker-develop.yml index cb84849580..ac2b1b4d35 100644 --- a/.github/workflows/docker-develop.yml +++ b/.github/workflows/docker-develop.yml @@ -37,7 +37,7 @@ jobs: password: ${{ secrets.DOCKER_PASSWORD }} - name: Build and push by digest id: build - uses: docker/build-push-action@v5 + uses: docker/build-push-action@v6 with: context: . push: true diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 23c1bdbc16..db899ba386 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -48,7 +48,7 @@ jobs: password: ${{ secrets.DOCKER_PASSWORD }} - name: Build and Push to Docker Hub id: build - uses: docker/build-push-action@v5 + uses: docker/build-push-action@v6 with: context: . push: true diff --git a/.github/workflows/dockle.yml b/.github/workflows/dockle.yml index eee7a78fed..c3dba4213d 100644 --- a/.github/workflows/dockle.yml +++ b/.github/workflows/dockle.yml @@ -13,14 +13,16 @@ jobs: runs-on: ubuntu-latest env: DOCKER_CONTENT_TRUST: 1 + DOCKLE_VERSION: 0.4.14 steps: - uses: actions/checkout@v4.1.1 - - run: | - curl -L -o dockle.deb "https://github.com/goodwithtech/dockle/releases/download/v0.4.10/dockle_0.4.10_Linux-64bit.deb" + - name: Download and install dockle v${{ env.DOCKLE_VERSION }} + run: | + curl -L -o dockle.deb "https://github.com/goodwithtech/dockle/releases/download/v${DOCKLE_VERSION}/dockle_${DOCKLE_VERSION}_Linux-64bit.deb" sudo dpkg -i dockle.deb - run: | cp .config/docker_example.env .config/docker.env - cp ./docker-compose_example.yml ./docker-compose.yml + cp ./compose_example.yml ./compose.yml - run: | docker compose up -d web docker tag "$(docker compose images web | awk 'OFS=":" {print $4}' | tail -n +2)" misskey-web:latest diff --git a/.github/workflows/get-api-diff.yml b/.github/workflows/get-api-diff.yml index 9b9c8f11c4..4afafabf2e 100644 --- a/.github/workflows/get-api-diff.yml +++ b/.github/workflows/get-api-diff.yml @@ -9,7 +9,7 @@ on: paths: - packages/backend/** - .github/workflows/get-api-diff.yml - + - .github/workflows/get-api-diff.yml jobs: get-from-misskey: runs-on: ubuntu-latest @@ -34,7 +34,7 @@ jobs: - name: Install pnpm uses: pnpm/action-setup@v4 - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4.0.2 + uses: actions/setup-node@v4.0.3 with: node-version: ${{ matrix.node-version }} cache: 'pnpm' diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 76616ec5a7..c21fc95123 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -10,15 +10,16 @@ on: - packages/frontend/** - packages/sw/** - packages/misskey-js/** - - packages/shared/.eslintrc.js + - packages/shared/eslint.config.js + - .github/workflows/lint.yml pull_request: paths: - packages/backend/** - packages/frontend/** - packages/sw/** - packages/misskey-js/** - - packages/shared/.eslintrc.js - + - packages/shared/eslint.config.js + - .github/workflows/lint.yml jobs: pnpm_install: runs-on: ubuntu-latest @@ -28,7 +29,7 @@ jobs: fetch-depth: 0 submodules: true - uses: pnpm/action-setup@v4 - - uses: actions/setup-node@v4.0.2 + - uses: actions/setup-node@v4.0.3 with: node-version-file: '.node-version' cache: 'pnpm' @@ -39,6 +40,8 @@ jobs: needs: [pnpm_install] runs-on: ubuntu-latest continue-on-error: true + env: + eslint-cache-version: v1 strategy: matrix: workspace: @@ -52,13 +55,20 @@ jobs: fetch-depth: 0 submodules: true - uses: pnpm/action-setup@v4 - - uses: actions/setup-node@v4.0.2 + - uses: actions/setup-node@v4.0.3 with: node-version-file: '.node-version' cache: 'pnpm' - run: corepack enable - run: pnpm i --frozen-lockfile - - run: pnpm --filter ${{ matrix.workspace }} run eslint + - name: Restore eslint cache + uses: actions/cache@v4.0.2 + with: + path: node_modules/.cache/eslint + key: eslint-${{ env.eslint-cache-version }}-${{ hashFiles('/pnpm-lock.yaml') }}-${{ github.ref_name }}-${{ github.sha }} + restore-keys: | + eslint-${{ env.eslint-cache-version }}-${{ hashFiles('/pnpm-lock.yaml') }}- + - run: pnpm --filter ${{ matrix.workspace }} run eslint --cache --cache-location node_modules/.cache/eslint --cache-strategy content typecheck: needs: [pnpm_install] @@ -75,7 +85,7 @@ jobs: fetch-depth: 0 submodules: true - uses: pnpm/action-setup@v4 - - uses: actions/setup-node@v4.0.2 + - uses: actions/setup-node@v4.0.3 with: node-version-file: '.node-version' cache: 'pnpm' diff --git a/.github/workflows/locale.yml b/.github/workflows/locale.yml index de2247e772..95251bfe31 100644 --- a/.github/workflows/locale.yml +++ b/.github/workflows/locale.yml @@ -4,10 +4,11 @@ on: push: paths: - locales/** + - .github/workflows/locale.yml pull_request: paths: - locales/** - + - .github/workflows/locale.yml jobs: locale_verify: runs-on: ubuntu-latest @@ -18,7 +19,7 @@ jobs: fetch-depth: 0 submodules: true - uses: pnpm/action-setup@v4 - - uses: actions/setup-node@v4.0.2 + - uses: actions/setup-node@v4.0.3 with: node-version-file: '.node-version' cache: 'pnpm' diff --git a/.github/workflows/on-release-created.yml b/.github/workflows/on-release-created.yml index edfdab99e9..22c04ff297 100644 --- a/.github/workflows/on-release-created.yml +++ b/.github/workflows/on-release-created.yml @@ -26,7 +26,7 @@ jobs: - name: Install pnpm uses: pnpm/action-setup@v4 - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4.0.2 + uses: actions/setup-node@v4.0.3 with: node-version: ${{ matrix.node-version }} cache: 'pnpm' diff --git a/.github/workflows/release-edit-with-push.yml b/.github/workflows/release-edit-with-push.yml index 86ee0b3fb5..f86c1948f8 100644 --- a/.github/workflows/release-edit-with-push.yml +++ b/.github/workflows/release-edit-with-push.yml @@ -3,10 +3,10 @@ name: "Release Manager: sync changelog with PR" on: push: branches: - - release/** + - develop paths: - 'CHANGELOG.md' - + # - .github/workflows/release-edit-with-push.yml env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -20,24 +20,29 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - # headがrelease/かつopenのPRを1つ取得 + # headが$GITHUB_REF_NAME, baseが$STABLE_BRANCHかつopenのPRを1つ取得 - name: Get PR run: | - echo "pr_number=$(gh pr list --limit 1 --head "$GITHUB_REF_NAME" --json number --jq '.[] | .number')" >> $GITHUB_OUTPUT + echo "pr_number=$(gh pr list --limit 1 --search "head:$GITHUB_REF_NAME base:$STABLE_BRANCH is:open" --json number --jq '.[] | .number')" >> $GITHUB_OUTPUT id: get_pr + env: + STABLE_BRANCH: ${{ vars.STABLE_BRANCH }} - name: Get target version - uses: misskey-dev/release-manager-actions/.github/actions/get-target-version@v1 + if: steps.get_pr.outputs.pr_number != '' + uses: misskey-dev/release-manager-actions/.github/actions/get-target-version@v2 id: v # CHANGELOG.mdの内容を取得 - name: Get changelog - uses: misskey-dev/release-manager-actions/.github/actions/get-changelog@v1 + if: steps.get_pr.outputs.pr_number != '' + uses: misskey-dev/release-manager-actions/.github/actions/get-changelog@v2 with: version: ${{ steps.v.outputs.target_version }} id: changelog # PRのnotesを更新 - name: Update PR + if: steps.get_pr.outputs.pr_number != '' run: | gh pr edit "$PR_NUMBER" --body "$CHANGELOG" env: - CHANGELOG: ${{ steps.changelog.outputs.changelog }} PR_NUMBER: ${{ steps.get_pr.outputs.pr_number }} + CHANGELOG: ${{ steps.changelog.outputs.changelog }} diff --git a/.github/workflows/release-with-dispatch.yml b/.github/workflows/release-with-dispatch.yml index bc6448cb37..0936bc0ae8 100644 --- a/.github/workflows/release-with-dispatch.yml +++ b/.github/workflows/release-with-dispatch.yml @@ -33,18 +33,21 @@ jobs: pr_number: ${{ steps.get_pr.outputs.pr_number }} steps: - uses: actions/checkout@v4 - # headがrelease/かつopenのPRを1つ取得 + # headが$GITHUB_REF_NAME, baseが$STABLE_BRANCHかつopenのPRを1つ取得 - name: Get PRs run: | - echo "pr_number=$(gh pr list --limit 1 --search "head:release/ is:open" --json number --jq '.[] | .number')" >> $GITHUB_OUTPUT + echo "pr_number=$(gh pr list --limit 1 --search "head:$GITHUB_REF_NAME base:$STABLE_BRANCH is:open" --json number --jq '.[] | .number')" >> $GITHUB_OUTPUT id: get_pr + env: + STABLE_BRANCH: ${{ vars.STABLE_BRANCH }} merge: - uses: misskey-dev/release-manager-actions/.github/workflows/merge.yml@v1 + uses: misskey-dev/release-manager-actions/.github/workflows/merge.yml@v2 needs: get-pr if: ${{ needs.get-pr.outputs.pr_number != '' && inputs.merge == true }} with: pr_number: ${{ needs.get-pr.outputs.pr_number }} + user: 'github-actions[bot]' package_jsons_to_rewrite: ${{ vars.PACKAGE_JSONS_TO_REWRITE }} # Text to prepend to the changelog # The first line must be `## Unreleased` @@ -65,15 +68,14 @@ jobs: secrets: RELEASE_APP_ID: ${{ secrets.RELEASE_APP_ID }} RELEASE_APP_PRIVATE_KEY: ${{ secrets.RELEASE_APP_PRIVATE_KEY }} - RULESET_EDIT_APP_ID: ${{ secrets.RULESET_EDIT_APP_ID }} - RULESET_EDIT_APP_PRIVATE_KEY: ${{ secrets.RULESET_EDIT_APP_PRIVATE_KEY }} create-prerelease: - uses: misskey-dev/release-manager-actions/.github/workflows/create-prerelease.yml@v1 + uses: misskey-dev/release-manager-actions/.github/workflows/create-prerelease.yml@v2 needs: get-pr if: ${{ needs.get-pr.outputs.pr_number != '' && inputs.merge != true }} with: pr_number: ${{ needs.get-pr.outputs.pr_number }} + user: 'github-actions[bot]' package_jsons_to_rewrite: ${{ vars.PACKAGE_JSONS_TO_REWRITE }} use_external_app_to_release: ${{ vars.USE_RELEASE_APP == 'true' }} indent: ${{ vars.INDENT }} @@ -82,10 +84,11 @@ jobs: RELEASE_APP_PRIVATE_KEY: ${{ secrets.RELEASE_APP_PRIVATE_KEY }} create-target: - uses: misskey-dev/release-manager-actions/.github/workflows/create-target.yml@v1 + uses: misskey-dev/release-manager-actions/.github/workflows/create-target.yml@v2 needs: get-pr if: ${{ needs.get-pr.outputs.pr_number == '' }} with: + user: 'github-actions[bot]' # The script for version increment. # process.env.CURRENT_VERSION: The current version. # @@ -118,8 +121,7 @@ jobs: package_jsons_to_rewrite: ${{ vars.PACKAGE_JSONS_TO_REWRITE }} use_external_app_to_release: ${{ vars.USE_RELEASE_APP == 'true' }} indent: ${{ vars.INDENT }} + stable_branch: ${{ vars.STABLE_BRANCH }} secrets: RELEASE_APP_ID: ${{ secrets.RELEASE_APP_ID }} RELEASE_APP_PRIVATE_KEY: ${{ secrets.RELEASE_APP_PRIVATE_KEY }} - RULESET_EDIT_APP_ID: ${{ secrets.RULESET_EDIT_APP_ID }} - RULESET_EDIT_APP_PRIVATE_KEY: ${{ secrets.RULESET_EDIT_APP_PRIVATE_KEY }} diff --git a/.github/workflows/release-with-ready.yml b/.github/workflows/release-with-ready.yml index a0fad0e336..79b6ade012 100644 --- a/.github/workflows/release-with-ready.yml +++ b/.github/workflows/release-with-ready.yml @@ -16,23 +16,26 @@ jobs: check: runs-on: ubuntu-latest outputs: - ref: ${{ steps.get_pr.outputs.ref }} + head: ${{ steps.get_pr.outputs.head }} + base: ${{ steps.get_pr.outputs.base }} steps: - uses: actions/checkout@v4 # PR情報を取得 - name: Get PR run: | - pr_json=$(gh pr view "$PR_NUMBER" --json isDraft,headRefName) - echo "ref=$(echo $pr_json | jq -r '.headRefName')" >> $GITHUB_OUTPUT + pr_json=$(gh pr view "$PR_NUMBER" --json isDraft,headRefName,baseRefName) + echo "head=$(echo $pr_json | jq -r '.headRefName')" >> $GITHUB_OUTPUT + echo "base=$(echo $pr_json | jq -r '.baseRefName')" >> $GITHUB_OUTPUT id: get_pr env: PR_NUMBER: ${{ github.event.pull_request.number }} release: - uses: misskey-dev/release-manager-actions/.github/workflows/create-prerelease.yml@v1 + uses: misskey-dev/release-manager-actions/.github/workflows/create-prerelease.yml@v2 needs: check - if: startsWith(needs.check.outputs.ref, 'release/') + if: needs.check.outputs.head == github.event.repository.default_branch && needs.check.outputs.base == vars.STABLE_BRANCH with: pr_number: ${{ github.event.pull_request.number }} + user: 'github-actions[bot]' package_jsons_to_rewrite: ${{ vars.PACKAGE_JSONS_TO_REWRITE }} use_external_app_to_release: ${{ vars.USE_RELEASE_APP == 'true' }} indent: ${{ vars.INDENT }} diff --git a/.github/workflows/storybook.yml b/.github/workflows/storybook.yml index c52883ffdd..68452aacaf 100644 --- a/.github/workflows/storybook.yml +++ b/.github/workflows/storybook.yml @@ -36,7 +36,7 @@ jobs: - name: Install pnpm uses: pnpm/action-setup@v4 - name: Use Node.js 20.x - uses: actions/setup-node@v4.0.2 + uses: actions/setup-node@v4.0.3 with: node-version-file: '.node-version' cache: 'pnpm' @@ -88,7 +88,7 @@ jobs: if [ "$BRANCH" = "misskey-dev:$HEAD_REF" ]; then BRANCH="$HEAD_REF" fi - pnpm --filter frontend chromatic --exit-once-uploaded -d storybook-static --branch-name $BRANCH $(echo "$CHROMATIC_PARAMETER") + pnpm --filter frontend chromatic --exit-once-uploaded -d storybook-static --branch-name "$BRANCH" $(echo "$CHROMATIC_PARAMETER") env: HEAD_REF: ${{ github.event.pull_request.head.ref }} CHROMATIC_PROJECT_TOKEN: ${{ secrets.CHROMATIC_PROJECT_TOKEN }} diff --git a/.github/workflows/test-backend.yml b/.github/workflows/test-backend.yml index b1c54bb3e7..bfb79ef090 100644 --- a/.github/workflows/test-backend.yml +++ b/.github/workflows/test-backend.yml @@ -9,12 +9,13 @@ on: - packages/backend/** # for permissions - packages/misskey-js/** + - .github/workflows/test-backend.yml pull_request: paths: - packages/backend/** # for permissions - packages/misskey-js/** - + - .github/workflows/test-backend.yml jobs: unit: runs-on: ubuntu-latest @@ -45,7 +46,7 @@ jobs: - name: Install FFmpeg uses: FedericoCarboni/setup-ffmpeg@v3 - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4.0.2 + uses: actions/setup-node@v4.0.3 with: node-version: ${{ matrix.node-version }} cache: 'pnpm' @@ -92,7 +93,7 @@ jobs: - name: Install pnpm uses: pnpm/action-setup@v4 - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4.0.2 + uses: actions/setup-node@v4.0.3 with: node-version: ${{ matrix.node-version }} cache: 'pnpm' diff --git a/.github/workflows/test-frontend.yml b/.github/workflows/test-frontend.yml index 9d5053b82a..c17a9fd387 100644 --- a/.github/workflows/test-frontend.yml +++ b/.github/workflows/test-frontend.yml @@ -11,7 +11,7 @@ on: - packages/misskey-js/** # for e2e - packages/backend/** - + - .github/workflows/test-frontend.yml pull_request: paths: - packages/frontend/** @@ -19,7 +19,7 @@ on: - packages/misskey-js/** # for e2e - packages/backend/** - + - .github/workflows/test-frontend.yml jobs: vitest: runs-on: ubuntu-latest @@ -35,7 +35,7 @@ jobs: - name: Install pnpm uses: pnpm/action-setup@v4 - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4.0.2 + uses: actions/setup-node@v4.0.3 with: node-version: ${{ matrix.node-version }} cache: 'pnpm' @@ -90,7 +90,7 @@ jobs: - name: Install pnpm uses: pnpm/action-setup@v4 - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4.0.2 + uses: actions/setup-node@v4.0.3 with: node-version: ${{ matrix.node-version }} cache: 'pnpm' diff --git a/.github/workflows/test-misskey-js.yml b/.github/workflows/test-misskey-js.yml index 2589d908b8..6ee67e8735 100644 --- a/.github/workflows/test-misskey-js.yml +++ b/.github/workflows/test-misskey-js.yml @@ -8,11 +8,12 @@ on: branches: [ develop ] paths: - packages/misskey-js/** + - .github/workflows/test-misskey-js.yml pull_request: branches: [ develop ] paths: - packages/misskey-js/** - + - .github/workflows/test-misskey-js.yml jobs: test: @@ -30,7 +31,7 @@ jobs: - run: corepack enable - name: Setup Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4.0.2 + uses: actions/setup-node@v4.0.3 with: node-version: ${{ matrix.node-version }} cache: 'pnpm' diff --git a/.github/workflows/test-production.yml b/.github/workflows/test-production.yml index 7f8db65293..18d02ec030 100644 --- a/.github/workflows/test-production.yml +++ b/.github/workflows/test-production.yml @@ -25,7 +25,7 @@ jobs: - name: Install pnpm uses: pnpm/action-setup@v4 - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4.0.2 + uses: actions/setup-node@v4.0.3 with: node-version: ${{ matrix.node-version }} cache: 'pnpm' diff --git a/.github/workflows/validate-api-json.yml b/.github/workflows/validate-api-json.yml index 24340e7d81..90f2929a25 100644 --- a/.github/workflows/validate-api-json.yml +++ b/.github/workflows/validate-api-json.yml @@ -7,10 +7,11 @@ on: - develop paths: - packages/backend/** + - .github/workflows/validate-api-json.yml pull_request: paths: - packages/backend/** - + - .github/workflows/validate-api-json.yml jobs: validate-api-json: runs-on: ubuntu-latest @@ -26,7 +27,7 @@ jobs: - name: Install pnpm uses: pnpm/action-setup@v4 - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4.0.2 + uses: actions/setup-node@v4.0.3 with: node-version: ${{ matrix.node-version }} cache: 'pnpm' diff --git a/.gitignore b/.gitignore index bdc14fea0a..45170902b1 100644 --- a/.gitignore +++ b/.gitignore @@ -35,8 +35,8 @@ coverage !/.config/example.yml !/.config/docker_example.yml !/.config/docker_example.env -docker-compose.yml -!/.devcontainer/docker-compose.yml +.devcontainer/compose.yml +!/.devcontainer/compose.yml # misskey /build @@ -59,6 +59,7 @@ ormconfig.json temp /packages/frontend/src/**/*.stories.ts tsdoc-metadata.json +misskey-assets # blender backups *.blend1 diff --git a/.gitmodules b/.gitmodules index 225a69a652..3218575273 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,3 @@ -[submodule "misskey-assets"] - path = misskey-assets - url = https://github.com/misskey-dev/assets.git [submodule "fluent-emojis"] path = fluent-emojis url = https://github.com/misskey-dev/emojis.git diff --git a/CHANGELOG.md b/CHANGELOG.md index cb14b2ab2e..b9f0fbe1fc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,14 +1,91 @@ -## Unreleased +## 2024.7.0 + +### Note +- デッキUIの新着ノートをサウンドで通知する機能の追加(v2024.5.0)に伴い、以前から動作しなくなっていたクライアント設定内の「アンテナ受信」「チャンネル通知」サウンドを削除しました。 +- Streaming APIにて入力が不正な場合にはそのメッセージを無視するようになりました。 #14251 ### General +- Feat: 通報を受けた際、または解決した際に、予め登録した宛先に通知を飛ばせるように(mail or webhook) #13705 +- Feat: ユーザーのアイコン/バナーの変更可否をロールで設定可能に + - 変更不可となっていても、設定済みのものを解除してデフォルト画像に戻すことは出来ます +- Feat: 連合に使うHTTP SignaturesがEd25519鍵に対応するように #13464 + - Ed25519署名に対応するサーバーが増えると、deliverで要求されるサーバーリソースが削減されます + - ジョブキューのconfig設定のデフォルト値を変更しました。 + default.ymlでジョブキューの並列度を設定している場合は、従前よりもconcurrencyの値をより下げるとパフォーマンスが改善する可能性があります。 + * deliverJobConcurrency: 16 (←128) + * deliverJobPerSec: 1024 (←128) + * inboxJobConcurrency: 4 (←16) + * inboxJobPerSec: 64 (←32) - Feat: リバーシでリアクションを送りあえるように +- Fix: 配信停止したインスタンス一覧が見れなくなる問題を修正 +- Fix: Dockerコンテナの立ち上げ時に`pnpm`のインストールで固まることがある問題 +- Fix: デフォルトテーマに無効なテーマコードを入力するとUIが使用できなくなる問題を修正 ### Client -- +- Enhance: 内蔵APIドキュメントのデザイン・パフォーマンスを改善 +- Enhance: 非ログイン時に他サーバーに遷移するアクションを追加 +- Enhance: 非ログイン時のハイライトTLのデザインを改善 +- Enhance: フロントエンドのアクセシビリティ改善 + (Based on https://github.com/taiyme/misskey/pull/226) +- Enhance: サーバー情報ページ・お問い合わせページを改善 + (Cherry-picked from https://github.com/taiyme/misskey/pull/238) +- Enhance: AiScriptを0.19.0にアップデート +- Enhance: Allow negative delay for MFM animation elements (`tada`, `jelly`, `twitch`, `shake`, `spin`, `jump`, `bounce`, `rainbow`) +- Enhance: センシティブなメディアを開く際に確認ダイアログを出せるように +- Fix: `/about#federation` ページなどで各インスタンスのチャートが表示されなくなっていた問題を修正 +- Fix: ユーザーページの追加情報のラベルを投稿者のサーバーの絵文字で表示する (#13968) +- Fix: リバーシの対局を正しく共有できないことがある問題を修正 +- Fix: コントロールパネルでベースロールのポリシーを編集してもUI上では変更が反映されない問題を修正 +- Fix: アンテナの編集画面のボタンに隙間を追加 +- Fix: テーマプレビューが見れない問題を修正 +- Fix: ショートカットキーが連打できる問題を修正 + (Cherry-picked from https://github.com/taiyme/misskey/pull/234) +- Fix: MkSignin.vueのcredentialRequestからReactivityを削除(ProxyがPasskey認証処理に渡ることを避けるため) +- Fix: 「アニメーション画像を再生しない」がオンのときでもサーバーのバナー画像・背景画像がアニメーションしてしまう問題を修正 + (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/574) +- Fix: Twitchの埋め込みが開けない問題を修正 +- Fix: 子メニューの高さがウィンドウからはみ出ることがある問題を修正 +- Fix: 個人宛てのダイアログ形式のお知らせが即時表示されない問題を修正 +- Fix: 一部の画像がセンシティブ指定されているときに画面に何も表示されないことがあるのを修正 ### Server -- +- Feat: レートリミット制限に引っかかったときに`Retry-After`ヘッダーを返すように (#13949) +- Enhance: エンドポイント`clips/update`の必須項目を`clipId`のみに +- Enhance: エンドポイント`admin/roles/update`の必須項目を`roleId`のみに +- Enhance: エンドポイント`pages/update`の必須項目を`pageId`のみに +- Enhance: エンドポイント`gallery/posts/update`の必須項目を`postId`のみに +- Enhance: エンドポイント`i/webhook/update`の必須項目を`webhookId`のみに +- Enhance: エンドポイント`admin/ad/update`の必須項目を`id`のみに +- Enhance: `default.yml`内の`url`, `db.db`, `db.user`, `db.pass`を環境変数から読み込めるように +- Fix: チャート生成時にinstance.suspensionStateに置き換えられたinstance.isSuspendedが参照されてしまう問題を修正 +- Fix: ユーザーのフィードページのMFMをHTMLに展開するように (#14006) +- Fix: アンテナ・クリップ・リスト・ウェブフックがロールポリシーの上限より一つ多く作れてしまうのを修正 (#14036) +- Fix: notRespondingSinceが実装される前に不通になったインスタンスが自動的に配信停止にならない (#14059) +- Fix: FTT有効時、タイムライン用エンドポイントで`sinceId`にキャッシュ内最古のものより古いものを指定した場合に正しく結果が返ってこない問題を修正 +- Fix: 自分以外のクリップ内のノート個数が見えることがあるのを修正 +- Fix: 空文字列のリアクションはフォールバックされるように +- Fix: リノートにリアクションできないように +- Fix: ユーザー名の前後に空白文字列がある場合は省略するように +- Fix: プロフィール編集時に名前を空白文字列のみにできる問題を修正 +- Fix: ユーザ名のサジェスト時に表示される内容と順番を調整(以下の順番になります) #14149 + 1. フォロー中かつアクティブなユーザ + 2. フォロー中かつ非アクティブなユーザ + 3. フォローしていないアクティブなユーザ + 4. フォローしていない非アクティブなユーザ + また、自分自身のアカウントもサジェストされるようになりました。 +- Fix: 一般ユーザーから見たユーザーのバッジの一覧に公開されていないものが含まれることがある問題を修正 + (Cherry-picked from https://github.com/MisskeyIO/misskey/pull/652) +- Fix: ユーザーのリアクション一覧でミュート/ブロックが機能していなかった問題を修正 +- Fix: エラーメッセージの誤字を修正 (#14213) +- Fix: ソーシャルタイムラインにローカルタイムラインに表示される自分へのリプライが表示されない問題を修正 +- Fix: リノートのミュートが適用されるまでに時間がかかることがある問題を修正 + (Cherry-picked from https://github.com/Type4ny-Project/Type4ny/commit/e9601029b52e0ad43d9131b555b614e56c84ebc1) +- Fix: Steaming APIが不正なデータを受けた場合の動作が不安定である問題 #14251 + +### Misskey.js +- Feat: `/drive/files/create` のリクエストに対応(`multipart/form-data`に対応) +- Feat: `/admin/role/create` のロールポリシーの型を修正 ## 2024.5.0 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index dcb625626d..9a56345e6e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -106,6 +106,38 @@ If your language is not listed in Crowdin, please open an issue. ![Crowdin](https://d322cqt584bo4o.cloudfront.net/misskey/localized.svg) ## Development +### Setup +Before developing, you have to set up environment. Misskey requires Redis, PostgreSQL, and FFmpeg. + +You would want to install Meilisearch to experiment related features. Technically, meilisearch is not strict requirement, but some features and tests require it. + +There are a few ways to proceed. + +#### Use system-wide software +You could install them in system-wide (such as from package manager). + +#### Use `docker compose` +You could obtain middleware container by typing `docker compose -f $PROJECT_ROOT/compose.local-db.yml up -d`. + +#### Use Devcontainer +Devcontainer also has necessary setting. This method can be done by connecting from VSCode. + +Instead of running `pnpm` locally, you can use Dev Container to set up your development environment. +To use Dev Container, open the project directory on VSCode with Dev Containers installed. +**Note:** If you are using Windows, please clone the repository with WSL. Using Git for Windows will result in broken files due to the difference in how newlines are handled. + +It will run the following command automatically inside the container. +``` bash +git submodule update --init +pnpm install --frozen-lockfile +cp .devcontainer/devcontainer.yml .config/default.yml +pnpm build +pnpm migrate +``` + +After finishing the migration, you can proceed. + +### Start developing During development, it is useful to use the ``` @@ -135,26 +167,6 @@ MK_DEV_PREFER=backend pnpm dev - To change the port of Vite, specify with `VITE_PORT` environment variable. - HMR may not work in some environments such as Windows. -### Dev Container -Instead of running `pnpm` locally, you can use Dev Container to set up your development environment. -To use Dev Container, open the project directory on VSCode with Dev Containers installed. -**Note:** If you are using Windows, please clone the repository with WSL. Using Git for Windows will result in broken files due to the difference in how newlines are handled. - -It will run the following command automatically inside the container. -``` bash -git submodule update --init -pnpm install --frozen-lockfile -cp .devcontainer/devcontainer.yml .config/default.yml -pnpm build -pnpm migrate -``` - -After finishing the migration, run the `pnpm dev` command to start the development server. - -``` bash -pnpm dev -``` - ## Testing - Test codes are located in [`/packages/backend/test`](/packages/backend/test). @@ -165,7 +177,7 @@ cp .github/misskey/test.yml .config/ ``` Prepare DB/Redis for testing. ``` -docker compose -f packages/backend/test/docker-compose.yml up +docker compose -f packages/backend/test/compose.yml up ``` Alternatively, prepare an empty (data can be erased) DB and edit `.config/test.yml`. @@ -185,7 +197,7 @@ TODO ## Environment Variable - `MISSKEY_CONFIG_YML`: Specify the file path of config.yml instead of default.yml (e.g. `2nd.yml`). -- `MISSKEY_WEBFINGER_USE_HTTP`: If it's set true, WebFinger requests will be http instead of https, useful for testing federation between servers in localhost. NEVER USE IN PRODUCTION. +- `MISSKEY_USE_HTTP`: If it's set true, federation requests (like nodeinfo and webfinger) will be http instead of https, useful for testing federation between servers in localhost. NEVER USE IN PRODUCTION. (was `MISSKEY_WEBFINGER_USE_HTTP`) ## Continuous integration Misskey uses GitHub Actions for executing automated tests. diff --git a/Dockerfile b/Dockerfile index 9fc2d611cd..d6ca6b8cdf 100644 --- a/Dockerfile +++ b/Dockerfile @@ -82,6 +82,10 @@ RUN apt-get update \ USER misskey WORKDIR /misskey +# add package.json to add pnpm +COPY --chown=misskey:misskey ./package.json ./package.json +RUN corepack install + COPY --chown=misskey:misskey --from=target-builder /misskey/node_modules ./node_modules COPY --chown=misskey:misskey --from=target-builder /misskey/packages/backend/node_modules ./packages/backend/node_modules COPY --chown=misskey:misskey --from=target-builder /misskey/packages/misskey-js/node_modules ./packages/misskey-js/node_modules diff --git a/chart/files/default.yml b/chart/files/default.yml index f98b8ebfee..4017588fa0 100644 --- a/chart/files/default.yml +++ b/chart/files/default.yml @@ -178,12 +178,12 @@ id: "aidx" #clusterLimit: 1 # Job concurrency per worker -# deliverJobConcurrency: 128 -# inboxJobConcurrency: 16 +# deliverJobConcurrency: 16 +# inboxJobConcurrency: 4 # Job rate limiter -# deliverJobPerSec: 128 -# inboxJobPerSec: 32 +# deliverJobPerSec: 1024 +# inboxJobPerSec: 64 # Job attempts # deliverJobMaxAttempts: 12 diff --git a/docker-compose.local-db.yml b/compose.local-db.yml similarity index 98% rename from docker-compose.local-db.yml rename to compose.local-db.yml index 16ba4b49e1..3835cb23db 100644 --- a/docker-compose.local-db.yml +++ b/compose.local-db.yml @@ -1,5 +1,3 @@ -version: "3" - # このconfigは、 dockerでMisskey本体を起動せず、 redisとpostgresql などだけを起動します services: diff --git a/docker-compose_example.yml b/compose_example.yml similarity index 97% rename from docker-compose_example.yml rename to compose_example.yml index 5cebbe4164..336bd814a7 100644 --- a/docker-compose_example.yml +++ b/compose_example.yml @@ -1,5 +1,3 @@ -version: "3" - services: web: build: . @@ -19,6 +17,8 @@ services: networks: - internal_network - external_network + # env_file: + # - .config/docker.env volumes: - ./files:/misskey/files - ./.config:/misskey/.config:ro diff --git a/locales/index.d.ts b/locales/index.d.ts index c6d08504b6..0507fbb77b 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -736,6 +736,22 @@ export interface Locale extends ILocale { * リモートで表示 */ "showOnRemote": string; + /** + * リモートで続行 + */ + "continueOnRemote": string; + /** + * Misskey Hubからサーバーを選択 + */ + "chooseServerOnMisskeyHub": string; + /** + * サーバーのドメインを直接指定 + */ + "specifyServerHost": string; + /** + * ドメインを入力してください + */ + "inputHostName": string; /** * 全般 */ @@ -1921,9 +1937,13 @@ export interface Locale extends ILocale { */ "onlyOneFileCanBeAttached": string; /** - * 続行する前に、サインアップまたはサインインが必要です + * 続行する前に、登録またはログインが必要です */ "signinRequired": string; + /** + * 続行するには、お使いのサーバーに移動するか、このサーバーに登録・ログインする必要があります + */ + "signinOrContinueOnRemote": string; /** * 招待 */ @@ -4984,6 +5004,18 @@ export interface Locale extends ILocale { * お問い合わせ */ "inquiry": string; + /** + * もう一度お試しください。 + */ + "tryAgain": string; + /** + * センシティブなメディアを表示するとき確認する + */ + "confirmWhenRevealingSensitiveMedia": string; + /** + * センシティブなメディアです。表示しますか? + */ + "sensitiveMediaRevealConfirm": string; "_delivery": { /** * 配信状態 @@ -6594,6 +6626,10 @@ export interface Locale extends ILocale { * ファイルにNSFWを常に付与 */ "alwaysMarkNsfw": string; + /** + * アイコンとバナーの更新を許可 + */ + "canUpdateBioMedia": string; /** * ノートのピン留めの最大数 */ @@ -7515,14 +7551,6 @@ export interface Locale extends ILocale { * 通知 */ "notification": string; - /** - * アンテナ受信 - */ - "antenna": string; - /** - * チャンネル通知 - */ - "channel": string; /** * リアクション選択時 */ @@ -9305,6 +9333,10 @@ export interface Locale extends ILocale { * Webhookを作成 */ "createWebhook": string; + /** + * Webhookを編集 + */ + "modifyWebhook": string; /** * 名前 */ @@ -9351,6 +9383,72 @@ export interface Locale extends ILocale { */ "mention": string; }; + "_systemEvents": { + /** + * ユーザーから通報があったとき + */ + "abuseReport": string; + /** + * ユーザーからの通報を処理したとき + */ + "abuseReportResolved": string; + }; + /** + * Webhookを削除しますか? + */ + "deleteConfirm": string; + }; + "_abuseReport": { + "_notificationRecipient": { + /** + * 通報の通知先を追加 + */ + "createRecipient": string; + /** + * 通報の通知先を編集 + */ + "modifyRecipient": string; + /** + * 通知先の種類 + */ + "recipientType": string; + "_recipientType": { + /** + * メール + */ + "mail": string; + /** + * Webhook + */ + "webhook": string; + "_captions": { + /** + * モデレーター権限を持つユーザーのメールアドレスに通知を送ります(通報を受けた時のみ) + */ + "mail": string; + /** + * 指定したSystemWebhookに通知を送ります(通報を受けた時と通報を解決した時にそれぞれ発信) + */ + "webhook": string; + }; + }; + /** + * キーワード + */ + "keywords": string; + /** + * 通知先ユーザー + */ + "notifiedUser": string; + /** + * 使用するWebhook + */ + "notifiedWebhook": string; + /** + * 通知先を削除しますか? + */ + "deleteConfirm": string; + }; }; "_moderationLogTypes": { /** @@ -9497,6 +9595,30 @@ export interface Locale extends ILocale { * ユーザーのバナーを解除 */ "unsetUserBanner": string; + /** + * SystemWebhookを作成 + */ + "createSystemWebhook": string; + /** + * SystemWebhookを更新 + */ + "updateSystemWebhook": string; + /** + * SystemWebhookを削除 + */ + "deleteSystemWebhook": string; + /** + * 通報の通知先を作成 + */ + "createAbuseReportNotificationRecipient": string; + /** + * 通報の通知先を更新 + */ + "updateAbuseReportNotificationRecipient": string; + /** + * 通報の通知先を削除 + */ + "deleteAbuseReportNotificationRecipient": string; }; "_fileViewer": { /** @@ -9667,7 +9789,7 @@ export interface Locale extends ILocale { "_dataSaver": { "_media": { /** - * メディアの読み込み + * メディアの読み込みを無効化 */ "title": string; /** @@ -9677,7 +9799,7 @@ export interface Locale extends ILocale { }; "_avatar": { /** - * アイコン画像 + * アイコン画像のアニメーションを無効化 */ "title": string; /** @@ -9687,7 +9809,7 @@ export interface Locale extends ILocale { }; "_urlPreview": { /** - * URLプレビューのサムネイル + * URLプレビューのサムネイルを非表示 */ "title": string; /** @@ -9697,7 +9819,7 @@ export interface Locale extends ILocale { }; "_code": { /** - * コードハイライト + * コードハイライトを非表示 */ "title": string; /** diff --git a/locales/index.js b/locales/index.js index 650e552337..c2738884eb 100644 --- a/locales/index.js +++ b/locales/index.js @@ -52,7 +52,11 @@ const primaries = { const clean = (text) => text.replace(new RegExp(String.fromCodePoint(0x08), 'g'), ''); export function build() { - const locales = languages.reduce((a, c) => (a[c] = yaml.load(clean(fs.readFileSync(new URL(`${c}.yml`, import.meta.url), 'utf-8'))) || {}, a), {}); + // vitestの挙動を調整するため、一度ローカル変数化する必要がある + // https://github.com/vitest-dev/vitest/issues/3988#issuecomment-1686599577 + // https://github.com/misskey-dev/misskey/pull/14057#issuecomment-2192833785 + const metaUrl = import.meta.url; + const locales = languages.reduce((a, c) => (a[c] = yaml.load(clean(fs.readFileSync(new URL(`${c}.yml`, metaUrl), 'utf-8'))) || {}, a), {}); // 空文字列が入ることがあり、フォールバックが動作しなくなるのでプロパティごと消す const removeEmpty = (obj) => { diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index bf22312d5e..cb9aa564a4 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -180,6 +180,10 @@ addAccount: "アカウントを追加" reloadAccountsList: "アカウントリストの情報を更新" loginFailed: "ログインに失敗しました" showOnRemote: "リモートで表示" +continueOnRemote: "リモートで続行" +chooseServerOnMisskeyHub: "Misskey Hubからサーバーを選択" +specifyServerHost: "サーバーのドメインを直接指定" +inputHostName: "ドメインを入力してください" general: "全般" wallpaper: "壁紙" setWallpaper: "壁紙を設定" @@ -476,7 +480,8 @@ attachAsFileQuestion: "クリップボードのテキストが長いです。テ noMessagesYet: "まだチャットはありません" newMessageExists: "新しいメッセージがあります" onlyOneFileCanBeAttached: "メッセージに添付できるファイルはひとつです" -signinRequired: "続行する前に、サインアップまたはサインインが必要です" +signinRequired: "続行する前に、登録またはログインが必要です" +signinOrContinueOnRemote: "続行するには、お使いのサーバーに移動するか、このサーバーに登録・ログインする必要があります" invitations: "招待" invitationCode: "招待コード" checking: "確認しています" @@ -1242,6 +1247,9 @@ keepOriginalFilenameDescription: "この設定をオフにすると、アップ noDescription: "説明文はありません" alwaysConfirmFollow: "フォローの際常に確認する" inquiry: "お問い合わせ" +tryAgain: "もう一度お試しください。" +confirmWhenRevealingSensitiveMedia: "センシティブなメディアを表示するとき確認する" +sensitiveMediaRevealConfirm: "センシティブなメディアです。表示しますか?" _delivery: status: "配信状態" @@ -1705,6 +1713,7 @@ _role: canManageAvatarDecorations: "アバターデコレーションの管理" driveCapacity: "ドライブ容量" alwaysMarkNsfw: "ファイルにNSFWを常に付与" + canUpdateBioMedia: "アイコンとバナーの更新を許可" pinMax: "ノートのピン留めの最大数" antennaMax: "アンテナの作成可能数" wordMuteMax: "ワードミュートの最大文字数" @@ -1971,8 +1980,6 @@ _sfx: note: "ノート" noteMy: "ノート(自分)" notification: "通知" - antenna: "アンテナ受信" - channel: "チャンネル通知" reaction: "リアクション選択時" _soundSettings: @@ -2468,6 +2475,7 @@ _drivecleaner: _webhookSettings: createWebhook: "Webhookを作成" + modifyWebhook: "Webhookを編集" name: "名前" secret: "シークレット" events: "Webhookを実行するタイミング" @@ -2480,6 +2488,26 @@ _webhookSettings: renote: "Renoteされたとき" reaction: "リアクションがあったとき" mention: "メンションされたとき" + _systemEvents: + abuseReport: "ユーザーから通報があったとき" + abuseReportResolved: "ユーザーからの通報を処理したとき" + deleteConfirm: "Webhookを削除しますか?" + +_abuseReport: + _notificationRecipient: + createRecipient: "通報の通知先を追加" + modifyRecipient: "通報の通知先を編集" + recipientType: "通知先の種類" + _recipientType: + mail: "メール" + webhook: "Webhook" + _captions: + mail: "モデレーター権限を持つユーザーのメールアドレスに通知を送ります(通報を受けた時のみ)" + webhook: "指定したSystemWebhookに通知を送ります(通報を受けた時と通報を解決した時にそれぞれ発信)" + keywords: "キーワード" + notifiedUser: "通知先ユーザー" + notifiedWebhook: "使用するWebhook" + deleteConfirm: "通知先を削除しますか?" _moderationLogTypes: createRole: "ロールを作成" @@ -2518,6 +2546,12 @@ _moderationLogTypes: deleteAvatarDecoration: "アイコンデコレーションを削除" unsetUserAvatar: "ユーザーのアイコンを解除" unsetUserBanner: "ユーザーのバナーを解除" + createSystemWebhook: "SystemWebhookを作成" + updateSystemWebhook: "SystemWebhookを更新" + deleteSystemWebhook: "SystemWebhookを削除" + createAbuseReportNotificationRecipient: "通報の通知先を作成" + updateAbuseReportNotificationRecipient: "通報の通知先を更新" + deleteAbuseReportNotificationRecipient: "通報の通知先を削除" _fileViewer: title: "ファイルの詳細" @@ -2572,16 +2606,16 @@ _externalResourceInstaller: _dataSaver: _media: - title: "メディアの読み込み" + title: "メディアの読み込みを無効化" description: "画像・動画が自動で読み込まれるのを防止します。隠れている画像・動画はタップすると読み込まれます。" _avatar: - title: "アイコン画像" + title: "アイコン画像のアニメーションを無効化" description: "アイコン画像のアニメーションが停止します。アニメーション画像は通常の画像よりファイルサイズが大きいことがあるので、データ通信量をさらに削減できます。" _urlPreview: - title: "URLプレビューのサムネイル" + title: "URLプレビューのサムネイルを非表示" description: "URLプレビューのサムネイル画像が読み込まれなくなります。" _code: - title: "コードハイライト" + title: "コードハイライトを非表示" description: "MFMなどでコードハイライト記法が使われている場合、タップするまで読み込まれなくなります。コードハイライトではハイライトする言語ごとにその定義ファイルを読み込む必要がありますが、それらが自動で読み込まれなくなるため、通信量の削減が見込めます。" _hemisphere: diff --git a/misskey-assets b/misskey-assets deleted file mode 160000 index 0179793ec8..0000000000 --- a/misskey-assets +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 0179793ec891856d6f37a3be16ba4c22f67a81b5 diff --git a/package.json b/package.json index b1786e16f1..44466aaae6 100644 --- a/package.json +++ b/package.json @@ -1,12 +1,12 @@ { "name": "misskey", - "version": "2024.5.0", + "version": "2024.7.0-beta.1", "codename": "nasubi", "repository": { "type": "git", "url": "https://github.com/misskey-dev/misskey.git" }, - "packageManager": "pnpm@9.0.6", + "packageManager": "pnpm@9.5.0", "workspaces": [ "packages/frontend", "packages/backend", @@ -55,20 +55,22 @@ "js-yaml": "4.1.0", "postcss": "8.4.38", "tar": "6.2.1", - "terser": "5.30.3", - "typescript": "5.4.5", - "esbuild": "0.20.2", + "terser": "5.31.1", + "typescript": "5.5.3", + "esbuild": "0.22.0", "glob": "10.3.12" }, "devDependencies": { - "@types/node": "20.12.7", - "@typescript-eslint/eslint-plugin": "7.7.1", - "@typescript-eslint/parser": "7.7.1", + "@misskey-dev/eslint-plugin": "2.0.2", + "@types/node": "20.14.9", + "@typescript-eslint/eslint-plugin": "7.15.0", + "@typescript-eslint/parser": "7.15.0", "cross-env": "7.0.3", - "cypress": "13.7.3", - "eslint": "8.57.0", + "cypress": "13.13.0", + "eslint": "9.6.0", + "globals": "15.7.0", "ncp": "2.0.0", - "start-server-and-test": "2.0.3" + "start-server-and-test": "2.0.4" }, "optionalDependencies": { "@tensorflow/tfjs-core": "4.4.0" diff --git a/packages/backend/.eslintignore b/packages/backend/.eslintignore deleted file mode 100644 index 790eb90145..0000000000 --- a/packages/backend/.eslintignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -/built -/.eslintrc.js -/@types/**/* diff --git a/packages/backend/.eslintrc.cjs b/packages/backend/.eslintrc.cjs deleted file mode 100644 index f9fe4814e6..0000000000 --- a/packages/backend/.eslintrc.cjs +++ /dev/null @@ -1,32 +0,0 @@ -module.exports = { - parserOptions: { - tsconfigRootDir: __dirname, - project: ['./tsconfig.json', './test/tsconfig.json'], - }, - extends: [ - '../shared/.eslintrc.js', - ], - rules: { - 'import/order': ['warn', { - 'groups': ['builtin', 'external', 'internal', 'parent', 'sibling', 'index', 'object', 'type'], - 'pathGroups': [ - { - 'pattern': '@/**', - 'group': 'external', - 'position': 'after' - } - ], - }], - 'no-restricted-globals': [ - 'error', - { - 'name': '__dirname', - 'message': 'Not in ESModule. Use `import.meta.url` instead.' - }, - { - 'name': '__filename', - 'message': 'Not in ESModule. Use `import.meta.url` instead.' - } - ] - }, -}; diff --git a/packages/backend/assets/api-doc.html b/packages/backend/assets/api-doc.html new file mode 100644 index 0000000000..19e0349d47 --- /dev/null +++ b/packages/backend/assets/api-doc.html @@ -0,0 +1,20 @@ + + + + Misskey API + + + + + + + + + diff --git a/packages/backend/assets/redoc.html b/packages/backend/assets/redoc.html deleted file mode 100644 index 2557b4532e..0000000000 --- a/packages/backend/assets/redoc.html +++ /dev/null @@ -1,24 +0,0 @@ - - - - Misskey API - - - - - - - - - - - - - diff --git a/packages/backend/eslint.config.js b/packages/backend/eslint.config.js new file mode 100644 index 0000000000..4fd9f0cd51 --- /dev/null +++ b/packages/backend/eslint.config.js @@ -0,0 +1,46 @@ +import tsParser from '@typescript-eslint/parser'; +import sharedConfig from '../shared/eslint.config.js'; + +export default [ + ...sharedConfig, + { + ignores: ['**/node_modules', 'built', '@types/**/*', 'migration'], + }, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + parser: tsParser, + project: ['./tsconfig.json', './test/tsconfig.json'], + sourceType: 'module', + tsconfigRootDir: import.meta.dirname, + }, + }, + rules: { + 'import/order': ['warn', { + groups: [ + 'builtin', + 'external', + 'internal', + 'parent', + 'sibling', + 'index', + 'object', + 'type', + ], + pathGroups: [{ + pattern: '@/**', + group: 'external', + position: 'after', + }], + }], + 'no-restricted-globals': ['error', { + name: '__dirname', + message: 'Not in ESModule. Use `import.meta.url` instead.', + }, { + name: '__filename', + message: 'Not in ESModule. Use `import.meta.url` instead.', + }], + }, + }, +]; diff --git a/packages/backend/migration/1708980134301-APMultipleKeys.js b/packages/backend/migration/1708980134301-APMultipleKeys.js new file mode 100644 index 0000000000..ca55526c6e --- /dev/null +++ b/packages/backend/migration/1708980134301-APMultipleKeys.js @@ -0,0 +1,39 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +export class APMultipleKeys1708980134301 { + name = 'APMultipleKeys1708980134301' + + async up(queryRunner) { + await queryRunner.query(`DROP INDEX "public"."IDX_171e64971c780ebd23fae140bb"`); + await queryRunner.query(`ALTER TABLE "user_keypair" ADD "ed25519PublicKey" character varying(128)`); + await queryRunner.query(`ALTER TABLE "user_keypair" ADD "ed25519PrivateKey" character varying(128)`); + await queryRunner.query(`ALTER TABLE "user_publickey" DROP CONSTRAINT "FK_10c146e4b39b443ede016f6736d"`); + await queryRunner.query(`ALTER TABLE "user_publickey" DROP CONSTRAINT "PK_10c146e4b39b443ede016f6736d"`); + await queryRunner.query(`ALTER TABLE "user_publickey" ADD CONSTRAINT "PK_0db6a5fdb992323449edc8ee421" PRIMARY KEY ("userId", "keyId")`); + await queryRunner.query(`ALTER TABLE "user_publickey" DROP CONSTRAINT "PK_0db6a5fdb992323449edc8ee421"`); + await queryRunner.query(`ALTER TABLE "user_publickey" ADD CONSTRAINT "PK_171e64971c780ebd23fae140bba" PRIMARY KEY ("keyId")`); + await queryRunner.query(`ALTER TABLE "user_publickey" ADD CONSTRAINT "UQ_10c146e4b39b443ede016f6736d" UNIQUE ("userId")`); + await queryRunner.query(`CREATE INDEX "IDX_10c146e4b39b443ede016f6736" ON "user_publickey" ("userId") `); + await queryRunner.query(`ALTER TABLE "user_publickey" ADD CONSTRAINT "FK_10c146e4b39b443ede016f6736d" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "user_publickey" DROP CONSTRAINT "FK_10c146e4b39b443ede016f6736d"`); + await queryRunner.query(`DROP INDEX "public"."IDX_10c146e4b39b443ede016f6736"`); + await queryRunner.query(`ALTER TABLE "user_publickey" DROP CONSTRAINT "UQ_10c146e4b39b443ede016f6736d"`); + await queryRunner.query(`ALTER TABLE "user_publickey" DROP CONSTRAINT "PK_171e64971c780ebd23fae140bba"`); + await queryRunner.query(`ALTER TABLE "user_publickey" ADD CONSTRAINT "PK_0db6a5fdb992323449edc8ee421" PRIMARY KEY ("userId", "keyId")`); + await queryRunner.query(`ALTER TABLE "user_publickey" DROP CONSTRAINT "PK_0db6a5fdb992323449edc8ee421"`); + await queryRunner.query(`ALTER TABLE "user_publickey" ADD CONSTRAINT "PK_10c146e4b39b443ede016f6736d" PRIMARY KEY ("userId")`); + await queryRunner.query(`ALTER TABLE "user_publickey" ADD CONSTRAINT "FK_10c146e4b39b443ede016f6736d" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`); + await queryRunner.query(`ALTER TABLE "user_profile" ALTER COLUMN "followersVisibility" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "user_profile" ALTER COLUMN "followersVisibility" TYPE "public"."user_profile_followersVisibility_enum_old" USING "followersVisibility"::"text"::"public"."user_profile_followersVisibility_enum_old"`); + await queryRunner.query(`ALTER TABLE "user_profile" ALTER COLUMN "followersVisibility" SET DEFAULT 'public'`); + await queryRunner.query(`ALTER TABLE "user_keypair" DROP COLUMN "ed25519PrivateKey"`); + await queryRunner.query(`ALTER TABLE "user_keypair" DROP COLUMN "ed25519PublicKey"`); + await queryRunner.query(`CREATE UNIQUE INDEX "IDX_171e64971c780ebd23fae140bb" ON "user_publickey" ("keyId") `); + } +} diff --git a/packages/backend/migration/1709242519122-HttpSignImplLv.js b/packages/backend/migration/1709242519122-HttpSignImplLv.js new file mode 100644 index 0000000000..7748bae006 --- /dev/null +++ b/packages/backend/migration/1709242519122-HttpSignImplLv.js @@ -0,0 +1,16 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +export class HttpSignImplLv1709242519122 { + name = 'HttpSignImplLv1709242519122' + + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "instance" ADD "httpMessageSignaturesImplementationLevel" character varying(16) NOT NULL DEFAULT '00'`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "instance" DROP COLUMN "httpMessageSignaturesImplementationLevel"`); + } +} diff --git a/packages/backend/migration/1709269211718-APMultipleKeysFix1.js b/packages/backend/migration/1709269211718-APMultipleKeysFix1.js new file mode 100644 index 0000000000..d2011802f2 --- /dev/null +++ b/packages/backend/migration/1709269211718-APMultipleKeysFix1.js @@ -0,0 +1,16 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +export class APMultipleKeys1709269211718 { + name = 'APMultipleKeys1709269211718' + + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "user_publickey" DROP CONSTRAINT "UQ_10c146e4b39b443ede016f6736d"`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "user_publickey" ADD CONSTRAINT "UQ_10c146e4b39b443ede016f6736d" UNIQUE ("userId")`); + } +} diff --git a/packages/backend/migration/1713656541000-abuse-report-notification.js b/packages/backend/migration/1713656541000-abuse-report-notification.js new file mode 100644 index 0000000000..4a754f81e2 --- /dev/null +++ b/packages/backend/migration/1713656541000-abuse-report-notification.js @@ -0,0 +1,62 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +export class AbuseReportNotification1713656541000 { + name = 'AbuseReportNotification1713656541000' + + async up(queryRunner) { + await queryRunner.query(` + CREATE TABLE "system_webhook" ( + "id" varchar(32) NOT NULL, + "isActive" boolean NOT NULL DEFAULT true, + "updatedAt" timestamp with time zone NOT NULL DEFAULT CURRENT_TIMESTAMP, + "latestSentAt" timestamp with time zone NULL DEFAULT NULL, + "latestStatus" integer NULL DEFAULT NULL, + "name" varchar(255) NOT NULL, + "on" varchar(128) [] NOT NULL DEFAULT '{}'::character varying[], + "url" varchar(1024) NOT NULL, + "secret" varchar(1024) NOT NULL, + CONSTRAINT "PK_system_webhook_id" PRIMARY KEY ("id") + ); + CREATE INDEX "IDX_system_webhook_isActive" ON "system_webhook" ("isActive"); + CREATE INDEX "IDX_system_webhook_on" ON "system_webhook" USING gin ("on"); + + CREATE TABLE "abuse_report_notification_recipient" ( + "id" varchar(32) NOT NULL, + "isActive" boolean NOT NULL DEFAULT true, + "updatedAt" timestamp with time zone NOT NULL DEFAULT CURRENT_TIMESTAMP, + "name" varchar(255) NOT NULL, + "method" varchar(64) NOT NULL, + "userId" varchar(32) NULL DEFAULT NULL, + "systemWebhookId" varchar(32) NULL DEFAULT NULL, + CONSTRAINT "PK_abuse_report_notification_recipient_id" PRIMARY KEY ("id"), + CONSTRAINT "FK_abuse_report_notification_recipient_userId1" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION, + CONSTRAINT "FK_abuse_report_notification_recipient_userId2" FOREIGN KEY ("userId") REFERENCES "user_profile"("userId") ON DELETE CASCADE ON UPDATE NO ACTION, + CONSTRAINT "FK_abuse_report_notification_recipient_systemWebhookId" FOREIGN KEY ("systemWebhookId") REFERENCES "system_webhook"("id") ON DELETE CASCADE ON UPDATE NO ACTION + ); + CREATE INDEX "IDX_abuse_report_notification_recipient_isActive" ON "abuse_report_notification_recipient" ("isActive"); + CREATE INDEX "IDX_abuse_report_notification_recipient_method" ON "abuse_report_notification_recipient" ("method"); + CREATE INDEX "IDX_abuse_report_notification_recipient_userId" ON "abuse_report_notification_recipient" ("userId"); + CREATE INDEX "IDX_abuse_report_notification_recipient_systemWebhookId" ON "abuse_report_notification_recipient" ("systemWebhookId"); + `); + } + + async down(queryRunner) { + await queryRunner.query(` + ALTER TABLE "abuse_report_notification_recipient" DROP CONSTRAINT "FK_abuse_report_notification_recipient_userId1"; + ALTER TABLE "abuse_report_notification_recipient" DROP CONSTRAINT "FK_abuse_report_notification_recipient_userId2"; + ALTER TABLE "abuse_report_notification_recipient" DROP CONSTRAINT "FK_abuse_report_notification_recipient_systemWebhookId"; + DROP INDEX "IDX_abuse_report_notification_recipient_isActive"; + DROP INDEX "IDX_abuse_report_notification_recipient_method"; + DROP INDEX "IDX_abuse_report_notification_recipient_userId"; + DROP INDEX "IDX_abuse_report_notification_recipient_systemWebhookId"; + DROP TABLE "abuse_report_notification_recipient"; + + DROP INDEX "IDX_system_webhook_isActive"; + DROP INDEX "IDX_system_webhook_on"; + DROP TABLE "system_webhook"; + `); + } +} diff --git a/packages/backend/package.json b/packages/backend/package.json index e034f75dc5..893171ebd6 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -4,7 +4,7 @@ "private": true, "type": "module", "engines": { - "node": "^20.10.0" + "node": "^20.10.0 || ^22.0.0" }, "scripts": { "start": "node ./built/boot/entry.js", @@ -65,43 +65,43 @@ "utf-8-validate": "6.0.3" }, "dependencies": { - "@aws-sdk/client-s3": "3.412.0", - "@aws-sdk/lib-storage": "3.412.0", - "@bull-board/api": "5.17.0", - "@bull-board/fastify": "5.17.0", - "@bull-board/ui": "5.17.0", + "@aws-sdk/client-s3": "3.600.0", + "@aws-sdk/lib-storage": "3.600.0", + "@bull-board/api": "5.20.5", + "@bull-board/fastify": "5.20.5", + "@bull-board/ui": "5.20.5", "@discordapp/twemoji": "15.0.3", "@fastify/accepts": "4.3.0", "@fastify/cookie": "9.3.1", "@fastify/cors": "9.0.1", "@fastify/express": "3.0.0", "@fastify/http-proxy": "9.5.0", - "@fastify/multipart": "8.2.0", - "@fastify/static": "7.0.3", + "@fastify/multipart": "8.3.0", + "@fastify/static": "7.0.4", "@fastify/view": "9.1.0", + "@misskey-dev/node-http-message-signatures": "0.0.10", "@misskey-dev/sharp-read-bmp": "1.2.0", "@misskey-dev/summaly": "5.1.0", - "@napi-rs/canvas": "^0.1.52", - "@nestjs/common": "10.3.8", - "@nestjs/core": "10.3.8", - "@nestjs/testing": "10.3.8", - "@peertube/http-signature": "1.7.0", - "@sentry/node": "^8.5.0", - "@sentry/profiling-node": "^8.5.0", + "@napi-rs/canvas": "^0.1.53", + "@nestjs/common": "10.3.10", + "@nestjs/core": "10.3.10", + "@nestjs/testing": "10.3.10", + "@sentry/node": "8.13.0", + "@sentry/profiling-node": "8.13.0", "@simplewebauthn/server": "10.0.0", "@sinonjs/fake-timers": "11.2.2", "@smithy/node-http-handler": "2.5.0", "@swc/cli": "0.3.12", - "@swc/core": "1.4.17", + "@swc/core": "1.6.6", "@twemoji/parser": "15.1.1", "accepts": "1.3.8", - "ajv": "8.13.0", + "ajv": "8.16.0", "archiver": "7.0.1", "async-mutex": "0.5.0", "bcryptjs": "2.4.3", "blurhash": "2.0.5", "body-parser": "1.20.2", - "bullmq": "5.7.8", + "bullmq": "5.8.3", "cacheable-lookup": "7.0.0", "cbor": "9.0.2", "chalk": "5.3.0", @@ -112,27 +112,27 @@ "content-disposition": "0.5.4", "date-fns": "2.30.0", "deep-email-validator": "0.1.21", - "fastify": "4.26.2", + "fastify": "4.28.1", "fastify-raw-body": "4.3.0", "feed": "4.2.2", "file-type": "19.0.0", - "fluent-ffmpeg": "2.1.2", + "fluent-ffmpeg": "2.1.3", "form-data": "4.0.0", - "got": "14.2.1", + "got": "14.4.1", "happy-dom": "10.0.3", "hpagent": "1.2.0", "htmlescape": "1.1.1", "http-link-header": "1.1.3", "ioredis": "5.4.1", - "ip-cidr": "3.1.0", + "ip-cidr": "4.0.1", "ipaddr.js": "2.2.0", - "is-svg": "5.0.0", + "is-svg": "5.0.1", "js-yaml": "4.1.0", - "jsdom": "24.0.0", + "jsdom": "24.1.0", "json5": "2.2.3", "jsonld": "8.3.2", "jsrsasign": "11.1.0", - "meilisearch": "0.38.0", + "meilisearch": "0.41.0", "mfm-js": "0.24.0", "microformats-parser": "2.0.2", "mime-types": "2.1.35", @@ -142,24 +142,24 @@ "nanoid": "5.0.7", "nested-property": "4.0.0", "node-fetch": "3.3.2", - "nodemailer": "6.9.13", + "nodemailer": "6.9.14", "nsfwjs": "2.4.2", "oauth": "0.10.0", "oauth2orize": "1.12.0", "oauth2orize-pkce": "0.1.2", "os-utils": "0.0.14", - "otpauth": "9.2.3", + "otpauth": "9.3.1", "parse5": "7.1.2", - "pg": "8.11.5", + "pg": "8.12.0", "pkce-challenge": "4.1.0", "probe-image-size": "7.2.3", "promise-limit": "2.7.0", - "pug": "3.0.2", + "pug": "3.0.3", "punycode": "2.3.1", "qrcode": "1.5.3", "random-seed": "0.3.0", "ratelimiter": "3.4.1", - "re2": "1.20.10", + "re2": "1.21.3", "redis-lock": "0.1.4", "reflect-metadata": "0.2.2", "rename": "1.0.4", @@ -167,27 +167,26 @@ "rxjs": "7.8.1", "sanitize-html": "2.13.0", "secure-json-parse": "2.7.0", - "sharp": "0.33.3", + "sharp": "0.33.4", "slacc": "0.0.10", "strict-event-emitter-types": "2.0.0", "stringz": "2.1.0", - "systeminformation": "5.22.7", + "systeminformation": "5.22.11", "tinycolor2": "1.6.0", "tmp": "0.2.3", - "tsc-alias": "1.8.8", + "tsc-alias": "1.8.10", "tsconfig-paths": "4.2.0", "typeorm": "0.3.20", - "typescript": "5.4.5", + "typescript": "5.5.3", "ulid": "2.3.0", "vary": "1.1.2", "web-push": "3.6.7", - "ws": "8.17.0", + "ws": "8.17.1", "xev": "3.0.2" }, "devDependencies": { "@jest/globals": "29.7.0", - "@misskey-dev/eslint-plugin": "1.0.0", - "@nestjs/platform-express": "10.3.8", + "@nestjs/platform-express": "10.3.10", "@simplewebauthn/types": "10.0.0", "@swc/jest": "0.2.36", "@types/accepts": "1.3.7", @@ -197,22 +196,21 @@ "@types/color-convert": "2.0.3", "@types/content-disposition": "0.5.8", "@types/fluent-ffmpeg": "2.1.24", - "@types/htmlescape": "^1.1.3", - "@types/http-link-header": "1.0.5", + "@types/htmlescape": "1.1.3", + "@types/http-link-header": "1.0.7", "@types/jest": "29.5.12", "@types/js-yaml": "4.0.9", - "@types/jsdom": "21.1.6", - "@types/jsonld": "1.5.13", + "@types/jsdom": "21.1.7", + "@types/jsonld": "1.5.14", "@types/jsrsasign": "10.5.14", "@types/mime-types": "2.1.4", "@types/ms": "0.7.34", - "@types/node": "20.12.7", - "@types/node-fetch": "3.0.3", + "@types/node": "20.14.9", "@types/nodemailer": "6.4.15", - "@types/oauth": "0.9.4", + "@types/oauth": "0.9.5", "@types/oauth2orize": "1.11.5", "@types/oauth2orize-pkce": "0.1.2", - "@types/pg": "8.11.5", + "@types/pg": "8.11.6", "@types/pug": "2.0.10", "@types/punycode": "2.1.4", "@types/qrcode": "1.5.5", @@ -228,18 +226,17 @@ "@types/vary": "1.1.3", "@types/web-push": "3.6.3", "@types/ws": "8.5.10", - "@typescript-eslint/eslint-plugin": "7.7.1", - "@typescript-eslint/parser": "7.7.1", - "aws-sdk-client-mock": "3.0.1", + "@typescript-eslint/eslint-plugin": "7.15.0", + "@typescript-eslint/parser": "7.15.0", + "aws-sdk-client-mock": "4.0.1", "cross-env": "7.0.3", - "eslint": "8.57.0", "eslint-plugin-import": "2.29.1", - "execa": "8.0.1", - "fkill": "^9.0.0", + "execa": "9.2.0", + "fkill": "9.0.0", "jest": "29.7.0", "jest-mock": "29.7.0", - "nodemon": "3.1.0", + "nodemon": "3.1.4", "pid-port": "1.0.0", - "simple-oauth2": "5.0.0" + "simple-oauth2": "5.0.1" } } diff --git a/packages/backend/scripts/dev.mjs b/packages/backend/scripts/dev.mjs index 2d0de0f916..a3e0558abd 100644 --- a/packages/backend/scripts/dev.mjs +++ b/packages/backend/scripts/dev.mjs @@ -30,6 +30,7 @@ function execStart() { async function killProc() { if (backendProcess) { + backendProcess.catch(() => {}); // backendProcess.kill()によって発生する例外を無視するためにcatch()を呼び出す backendProcess.kill(); await new Promise(resolve => backendProcess.on('exit', resolve)); backendProcess = undefined; @@ -46,6 +47,7 @@ async function killProc() { ], { stdio: [process.stdin, process.stdout, process.stderr, 'ipc'], + serialization: "json", }) .on('message', async (message) => { if (message.type === 'exit') { diff --git a/packages/backend/src/@types/http-signature.d.ts b/packages/backend/src/@types/http-signature.d.ts deleted file mode 100644 index 75b62e55f0..0000000000 --- a/packages/backend/src/@types/http-signature.d.ts +++ /dev/null @@ -1,82 +0,0 @@ -/* - * SPDX-FileCopyrightText: syuilo and misskey-project - * SPDX-License-Identifier: AGPL-3.0-only - */ - -declare module '@peertube/http-signature' { - import type { IncomingMessage, ClientRequest } from 'node:http'; - - interface ISignature { - keyId: string; - algorithm: string; - headers: string[]; - signature: string; - } - - interface IOptions { - headers?: string[]; - algorithm?: string; - strict?: boolean; - authorizationHeaderName?: string; - } - - interface IParseRequestOptions extends IOptions { - clockSkew?: number; - } - - interface IParsedSignature { - scheme: string; - params: ISignature; - signingString: string; - algorithm: string; - keyId: string; - } - - type RequestSignerConstructorOptions = - IRequestSignerConstructorOptionsFromProperties | - IRequestSignerConstructorOptionsFromFunction; - - interface IRequestSignerConstructorOptionsFromProperties { - keyId: string; - key: string | Buffer; - algorithm?: string; - } - - interface IRequestSignerConstructorOptionsFromFunction { - sign?: (data: string, cb: (err: any, sig: ISignature) => void) => void; - } - - class RequestSigner { - constructor(options: RequestSignerConstructorOptions); - - public writeHeader(header: string, value: string): string; - - public writeDateHeader(): string; - - public writeTarget(method: string, path: string): void; - - public sign(cb: (err: any, authz: string) => void): void; - } - - interface ISignRequestOptions extends IOptions { - keyId: string; - key: string; - httpVersion?: string; - } - - export function parse(request: IncomingMessage, options?: IParseRequestOptions): IParsedSignature; - export function parseRequest(request: IncomingMessage, options?: IParseRequestOptions): IParsedSignature; - - export function sign(request: ClientRequest, options: ISignRequestOptions): boolean; - export function signRequest(request: ClientRequest, options: ISignRequestOptions): boolean; - export function createSigner(): RequestSigner; - export function isSigner(obj: any): obj is RequestSigner; - - export function sshKeyToPEM(key: string): string; - export function sshKeyFingerprint(key: string): string; - export function pemToRsaSSHKey(pem: string, comment: string): string; - - export function verify(parsedSignature: IParsedSignature, pubkey: string | Buffer): boolean; - export function verifySignature(parsedSignature: IParsedSignature, pubkey: string | Buffer): boolean; - export function verifyHMAC(parsedSignature: IParsedSignature, secret: string): boolean; -} diff --git a/packages/backend/src/NestLogger.ts b/packages/backend/src/NestLogger.ts index 80f1f7a024..d0be19664f 100644 --- a/packages/backend/src/NestLogger.ts +++ b/packages/backend/src/NestLogger.ts @@ -7,7 +7,7 @@ import { LoggerService } from '@nestjs/common'; import Logger from '@/logger.js'; const logger = new Logger('core', 'cyan'); -const nestLogger = logger.createSubLogger('nest', 'green', false); +const nestLogger = logger.createSubLogger('nest', 'green'); export class NestLogger implements LoggerService { /** diff --git a/packages/backend/src/boot/entry.ts b/packages/backend/src/boot/entry.ts index 04c6ca9723..25375c3015 100644 --- a/packages/backend/src/boot/entry.ts +++ b/packages/backend/src/boot/entry.ts @@ -25,7 +25,7 @@ Error.stackTraceLimit = Infinity; EventEmitter.defaultMaxListeners = 128; const logger = new Logger('core', 'cyan'); -const clusterLogger = logger.createSubLogger('cluster', 'orange', false); +const clusterLogger = logger.createSubLogger('cluster', 'orange'); const ev = new Xev(); //#region Events diff --git a/packages/backend/src/boot/master.ts b/packages/backend/src/boot/master.ts index 75e1a80cd1..4bc5c799cf 100644 --- a/packages/backend/src/boot/master.ts +++ b/packages/backend/src/boot/master.ts @@ -25,7 +25,7 @@ const _dirname = dirname(_filename); const meta = JSON.parse(fs.readFileSync(`${_dirname}/../../../../built/meta.json`, 'utf-8')); const logger = new Logger('core', 'cyan'); -const bootLogger = logger.createSubLogger('boot', 'magenta', false); +const bootLogger = logger.createSubLogger('boot', 'magenta'); const themeColor = chalk.hex('#86b300'); diff --git a/packages/backend/src/boot/worker.ts b/packages/backend/src/boot/worker.ts index d4a7cd56e5..5d4a15b29f 100644 --- a/packages/backend/src/boot/worker.ts +++ b/packages/backend/src/boot/worker.ts @@ -4,13 +4,36 @@ */ import cluster from 'node:cluster'; +import * as Sentry from '@sentry/node'; +import { nodeProfilingIntegration } from '@sentry/profiling-node'; import { envOption } from '@/env.js'; +import { loadConfig } from '@/config.js'; import { jobQueue, server } from './common.js'; /** * Init worker process */ export async function workerMain() { + const config = loadConfig(); + + if (config.sentryForBackend) { + Sentry.init({ + integrations: [ + ...(config.sentryForBackend.enableNodeProfiling ? [nodeProfilingIntegration()] : []), + ], + + // Performance Monitoring + tracesSampleRate: 1.0, // Capture 100% of the transactions + + // Set sampling rate for profiling - this is relative to tracesSampleRate + profilesSampleRate: 1.0, + + maxBreadcrumbs: 0, + + ...config.sentryForBackend.options, + }); + } + if (envOption.onlyServer) { await server(); } else if (envOption.onlyQueue) { diff --git a/packages/backend/src/config.ts b/packages/backend/src/config.ts index 0ac521d409..3e5a1e81cd 100644 --- a/packages/backend/src/config.ts +++ b/packages/backend/src/config.ts @@ -23,7 +23,7 @@ type RedisOptionsSource = Partial & { * 設定ファイルの型 */ type Source = { - url: string; + url?: string; port?: number; socket?: string; chmodSocket?: string; @@ -31,9 +31,9 @@ type Source = { db: { host: string; port: number; - db: string; - user: string; - pass: string; + db?: string; + user?: string; + pass?: string; disableCache?: boolean; extra?: { [x: string]: string }; }; @@ -202,13 +202,17 @@ export function loadConfig(): Config { : { 'src/_boot_.ts': { file: 'src/_boot_.ts' } }; const config = yaml.load(fs.readFileSync(path, 'utf-8')) as Source; - const url = tryCreateUrl(config.url); + const url = tryCreateUrl(config.url ?? process.env.MISSKEY_URL ?? ''); const version = meta.version; const host = url.host; const hostname = url.hostname; const scheme = url.protocol.replace(/:$/, ''); const wsScheme = scheme.replace('http', 'ws'); + const dbDb = config.db.db ?? process.env.DATABASE_DB ?? ''; + const dbUser = config.db.user ?? process.env.DATABASE_USER ?? ''; + const dbPass = config.db.pass ?? process.env.DATABASE_PASSWORD ?? ''; + const externalMediaProxy = config.mediaProxy ? config.mediaProxy.endsWith('/') ? config.mediaProxy.substring(0, config.mediaProxy.length - 1) : config.mediaProxy : null; @@ -231,7 +235,7 @@ export function loadConfig(): Config { apiUrl: `${scheme}://${host}/api`, authUrl: `${scheme}://${host}/auth`, driveUrl: `${scheme}://${host}/files`, - db: config.db, + db: { ...config.db, db: dbDb, user: dbUser, pass: dbPass }, dbReplications: config.dbReplications, dbSlaves: config.dbSlaves, meilisearch: config.meilisearch, @@ -259,7 +263,7 @@ export function loadConfig(): Config { deliverJobMaxAttempts: config.deliverJobMaxAttempts, inboxJobMaxAttempts: config.inboxJobMaxAttempts, proxyRemoteFiles: config.proxyRemoteFiles, - signToActivityPubGet: config.signToActivityPubGet, + signToActivityPubGet: config.signToActivityPubGet ?? true, mediaProxy: externalMediaProxy ?? internalMediaProxy, externalMediaProxyEnabled: externalMediaProxy !== null && externalMediaProxy !== internalMediaProxy, videoThumbnailGenerator: config.videoThumbnailGenerator ? diff --git a/packages/backend/src/const.ts b/packages/backend/src/const.ts index a238f4973a..c132cc7e7b 100644 --- a/packages/backend/src/const.ts +++ b/packages/backend/src/const.ts @@ -3,11 +3,17 @@ * SPDX-License-Identifier: AGPL-3.0-only */ +// dummy export const MAX_NOTE_TEXT_LENGTH = 3000; export const USER_ONLINE_THRESHOLD = 1000 * 60 * 10; // 10min export const USER_ACTIVE_THRESHOLD = 1000 * 60 * 60 * 24 * 3; // 3days +export const REMOTE_USER_CACHE_TTL = 1000 * 60 * 60 * 3; // 3hours +export const REMOTE_USER_MOVE_COOLDOWN = 1000 * 60 * 60 * 24 * 14; // 14days + +export const REMOTE_SERVER_CACHE_TTL = 1000 * 60 * 60 * 3; // 3hours + //#region hard limits // If you change DB_* values, you must also change the DB schema. diff --git a/packages/backend/src/core/AbuseReportNotificationService.ts b/packages/backend/src/core/AbuseReportNotificationService.ts new file mode 100644 index 0000000000..42e5931212 --- /dev/null +++ b/packages/backend/src/core/AbuseReportNotificationService.ts @@ -0,0 +1,405 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { Inject, Injectable, type OnApplicationShutdown } from '@nestjs/common'; +import { Brackets, In, IsNull, Not } from 'typeorm'; +import * as Redis from 'ioredis'; +import sanitizeHtml from 'sanitize-html'; +import { DI } from '@/di-symbols.js'; +import { bindThis } from '@/decorators.js'; +import { GlobalEvents, GlobalEventService } from '@/core/GlobalEventService.js'; +import type { + AbuseReportNotificationRecipientRepository, + MiAbuseReportNotificationRecipient, + MiAbuseUserReport, + MiUser, +} from '@/models/_.js'; +import { EmailService } from '@/core/EmailService.js'; +import { MetaService } from '@/core/MetaService.js'; +import { RoleService } from '@/core/RoleService.js'; +import { RecipientMethod } from '@/models/AbuseReportNotificationRecipient.js'; +import { ModerationLogService } from '@/core/ModerationLogService.js'; +import { SystemWebhookService } from '@/core/SystemWebhookService.js'; +import { IdService } from './IdService.js'; + +@Injectable() +export class AbuseReportNotificationService implements OnApplicationShutdown { + constructor( + @Inject(DI.abuseReportNotificationRecipientRepository) + private abuseReportNotificationRecipientRepository: AbuseReportNotificationRecipientRepository, + @Inject(DI.redisForSub) + private redisForSub: Redis.Redis, + private idService: IdService, + private roleService: RoleService, + private systemWebhookService: SystemWebhookService, + private emailService: EmailService, + private metaService: MetaService, + private moderationLogService: ModerationLogService, + private globalEventService: GlobalEventService, + ) { + this.redisForSub.on('message', this.onMessage); + } + + /** + * 管理者用Redisイベントを用いて{@link abuseReports}の内容を管理者各位に通知する. + * 通知先ユーザは{@link RoleService.getModeratorIds}の取得結果に依る. + * + * @see RoleService.getModeratorIds + * @see GlobalEventService.publishAdminStream + */ + @bindThis + public async notifyAdminStream(abuseReports: MiAbuseUserReport[]) { + if (abuseReports.length <= 0) { + return; + } + + const moderatorIds = await this.roleService.getModeratorIds(true, true); + + for (const moderatorId of moderatorIds) { + for (const abuseReport of abuseReports) { + this.globalEventService.publishAdminStream( + moderatorId, + 'newAbuseUserReport', + { + id: abuseReport.id, + targetUserId: abuseReport.targetUserId, + reporterId: abuseReport.reporterId, + comment: abuseReport.comment, + }, + ); + } + } + } + + /** + * Mailを用いて{@link abuseReports}の内容を管理者各位に通知する. + * メールアドレスの送信先は以下の通り. + * - モデレータ権限所有者ユーザ(設定画面からメールアドレスの設定を行っているユーザに限る) + * - metaテーブルに設定されているメールアドレス + * + * @see EmailService.sendEmail + */ + @bindThis + public async notifyMail(abuseReports: MiAbuseUserReport[]) { + if (abuseReports.length <= 0) { + return; + } + + const recipientEMailAddresses = await this.fetchEMailRecipients().then(it => it + .filter(it => it.isActive && it.userProfile?.emailVerified) + .map(it => it.userProfile?.email) + .filter(x => x != null), + ); + + // 送信先の鮮度を保つため、毎回取得する + const meta = await this.metaService.fetch(true); + recipientEMailAddresses.push( + ...(meta.email ? [meta.email] : []), + ); + + if (recipientEMailAddresses.length <= 0) { + return; + } + + for (const mailAddress of recipientEMailAddresses) { + await Promise.all( + abuseReports.map(it => { + // TODO: 送信処理はJobQueue化したい + return this.emailService.sendEmail( + mailAddress, + 'New Abuse Report', + sanitizeHtml(it.comment), + sanitizeHtml(it.comment), + ); + }), + ); + } + } + + /** + * SystemWebhookを用いて{@link abuseReports}の内容を管理者各位に通知する. + * ここではJobQueueへのエンキューのみを行うため、即時実行されない. + * + * @see SystemWebhookService.enqueueSystemWebhook + */ + @bindThis + public async notifySystemWebhook( + abuseReports: MiAbuseUserReport[], + type: 'abuseReport' | 'abuseReportResolved', + ) { + if (abuseReports.length <= 0) { + return; + } + + const recipientWebhookIds = await this.fetchWebhookRecipients() + .then(it => it + .filter(it => it.isActive && it.systemWebhookId && it.method === 'webhook') + .map(it => it.systemWebhookId) + .filter(x => x != null)); + for (const webhookId of recipientWebhookIds) { + await Promise.all( + abuseReports.map(it => { + return this.systemWebhookService.enqueueSystemWebhook( + webhookId, + type, + it, + ); + }), + ); + } + } + + /** + * 通報の通知先一覧を取得する. + * + * @param {Object} [params] クエリの取得条件 + * @param {Object} [params.method] 取得する通知先の通知方法 + * @param {Object} [opts] 動作時の詳細なオプション + * @param {boolean} [opts.removeUnauthorized] 副作用としてモデレータ権限を持たない送信先ユーザをDBから削除するかどうか(default: true) + * @param {boolean} [opts.joinUser] 通知先のユーザ情報をJOINするかどうか(default: false) + * @param {boolean} [opts.joinSystemWebhook] 通知先のSystemWebhook情報をJOINするかどうか(default: false) + * @see removeUnauthorizedRecipientUsers + */ + @bindThis + public async fetchRecipients( + params?: { + ids?: MiAbuseReportNotificationRecipient['id'][], + method?: RecipientMethod[], + }, + opts?: { + removeUnauthorized?: boolean, + joinUser?: boolean, + joinSystemWebhook?: boolean, + }, + ): Promise { + const query = this.abuseReportNotificationRecipientRepository.createQueryBuilder('recipient'); + + if (opts?.joinUser) { + query.innerJoinAndSelect('user', 'user', 'recipient.userId = user.id'); + query.innerJoinAndSelect('recipient.userProfile', 'userProfile'); + } + + if (opts?.joinSystemWebhook) { + query.innerJoinAndSelect('recipient.systemWebhook', 'systemWebhook'); + } + + if (params?.ids) { + query.andWhere({ id: In(params.ids) }); + } + + if (params?.method) { + query.andWhere(new Brackets(qb => { + if (params.method?.includes('email')) { + qb.orWhere({ method: 'email', userId: Not(IsNull()) }); + } + if (params.method?.includes('webhook')) { + qb.orWhere({ method: 'webhook', userId: IsNull() }); + } + })); + } + + const recipients = await query.getMany(); + if (recipients.length <= 0) { + return []; + } + + // アサイン有効期限切れはイベントで拾えないので、このタイミングでチェック及び削除(オプション) + return (opts?.removeUnauthorized ?? true) + ? await this.removeUnauthorizedRecipientUsers(recipients) + : recipients; + } + + /** + * EMailの通知先一覧を取得する. + * リレーション先の{@link MiUser}および{@link MiUserProfile}も同時に取得する. + * + * @param {Object} [opts] + * @param {boolean} [opts.removeUnauthorized] 副作用としてモデレータ権限を持たない送信先ユーザをDBから削除するかどうか(default: true) + * @see removeUnauthorizedRecipientUsers + */ + @bindThis + public async fetchEMailRecipients(opts?: { + removeUnauthorized?: boolean + }): Promise { + return this.fetchRecipients({ method: ['email'] }, { joinUser: true, ...opts }); + } + + /** + * Webhookの通知先一覧を取得する. + * リレーション先の{@link MiSystemWebhook}も同時に取得する. + */ + @bindThis + public fetchWebhookRecipients(): Promise { + return this.fetchRecipients({ method: ['webhook'] }, { joinSystemWebhook: true }); + } + + /** + * 通知先を作成する. + */ + @bindThis + public async createRecipient( + params: { + isActive: MiAbuseReportNotificationRecipient['isActive']; + name: MiAbuseReportNotificationRecipient['name']; + method: MiAbuseReportNotificationRecipient['method']; + userId: MiAbuseReportNotificationRecipient['userId']; + systemWebhookId: MiAbuseReportNotificationRecipient['systemWebhookId']; + }, + updater: MiUser, + ): Promise { + const id = this.idService.gen(); + await this.abuseReportNotificationRecipientRepository.insert({ + ...params, + id, + }); + + const created = await this.abuseReportNotificationRecipientRepository.findOneByOrFail({ id: id }); + + this.moderationLogService + .log(updater, 'createAbuseReportNotificationRecipient', { + recipientId: id, + recipient: created, + }) + .then(); + + return created; + } + + /** + * 通知先を更新する. + */ + @bindThis + public async updateRecipient( + params: { + id: MiAbuseReportNotificationRecipient['id']; + isActive: MiAbuseReportNotificationRecipient['isActive']; + name: MiAbuseReportNotificationRecipient['name']; + method: MiAbuseReportNotificationRecipient['method']; + userId: MiAbuseReportNotificationRecipient['userId']; + systemWebhookId: MiAbuseReportNotificationRecipient['systemWebhookId']; + }, + updater: MiUser, + ): Promise { + const beforeEntity = await this.abuseReportNotificationRecipientRepository.findOneByOrFail({ id: params.id }); + + await this.abuseReportNotificationRecipientRepository.update(params.id, { + isActive: params.isActive, + updatedAt: new Date(), + name: params.name, + method: params.method, + userId: params.userId, + systemWebhookId: params.systemWebhookId, + }); + + const afterEntity = await this.abuseReportNotificationRecipientRepository.findOneByOrFail({ id: params.id }); + + this.moderationLogService + .log(updater, 'updateAbuseReportNotificationRecipient', { + recipientId: params.id, + before: beforeEntity, + after: afterEntity, + }) + .then(); + + return afterEntity; + } + + /** + * 通知先を削除する. + */ + @bindThis + public async deleteRecipient( + id: MiAbuseReportNotificationRecipient['id'], + updater: MiUser, + ) { + const entity = await this.abuseReportNotificationRecipientRepository.findBy({ id }); + + await this.abuseReportNotificationRecipientRepository.delete(id); + + this.moderationLogService + .log(updater, 'deleteAbuseReportNotificationRecipient', { + recipientId: id, + recipient: entity, + }) + .then(); + } + + /** + * モデレータ権限を持たない(*1)通知先ユーザを削除する. + * + * *1: 以下の両方を満たすものの事を言う + * - 通知先にユーザIDが設定されている + * - 付与ロールにモデレータ権限がない or アサインの有効期限が切れている + * + * @param recipients 通知先一覧の配列 + * @returns {@lisk recipients}からモデレータ権限を持たない通知先を削除した配列 + */ + @bindThis + private async removeUnauthorizedRecipientUsers(recipients: MiAbuseReportNotificationRecipient[]): Promise { + const userRecipients = recipients.filter(it => it.userId !== null); + const recipientUserIds = new Set(userRecipients.map(it => it.userId).filter(x => x != null)); + if (recipientUserIds.size <= 0) { + // ユーザが通知先として設定されていない場合、この関数での処理を行うべきレコードが無い + return recipients; + } + + // モデレータ権限の有無で通知先設定を振り分ける + const authorizedUserIds = await this.roleService.getModeratorIds(true, true); + const authorizedUserRecipients = Array.of(); + const unauthorizedUserRecipients = Array.of(); + for (const recipient of userRecipients) { + // eslint-disable-next-line + if (authorizedUserIds.includes(recipient.userId!)) { + authorizedUserRecipients.push(recipient); + } else { + unauthorizedUserRecipients.push(recipient); + } + } + + // モデレータ権限を持たない通知先をDBから削除する + if (unauthorizedUserRecipients.length > 0) { + await this.abuseReportNotificationRecipientRepository.delete(unauthorizedUserRecipients.map(it => it.id)); + } + const nonUserRecipients = recipients.filter(it => it.userId === null); + return [...nonUserRecipients, ...authorizedUserRecipients].sort((a, b) => a.id.localeCompare(b.id)); + } + + @bindThis + private async onMessage(_: string, data: string): Promise { + const obj = JSON.parse(data); + if (obj.channel !== 'internal') { + return; + } + + const { type } = obj.message as GlobalEvents['internal']['payload']; + switch (type) { + case 'roleUpdated': + case 'roleDeleted': + case 'userRoleUnassigned': { + // 場合によってはキャッシュ更新よりも先にここが呼ばれてしまう可能性があるのでnextTickで遅延実行 + process.nextTick(async () => { + const recipients = await this.abuseReportNotificationRecipientRepository.findBy({ + userId: Not(IsNull()), + }); + await this.removeUnauthorizedRecipientUsers(recipients); + }); + break; + } + default: { + break; + } + } + } + + @bindThis + public dispose(): void { + this.redisForSub.off('message', this.onMessage); + } + + @bindThis + public onApplicationShutdown(signal?: string | undefined): void { + this.dispose(); + } +} diff --git a/packages/backend/src/core/AbuseReportService.ts b/packages/backend/src/core/AbuseReportService.ts new file mode 100644 index 0000000000..69c51509ba --- /dev/null +++ b/packages/backend/src/core/AbuseReportService.ts @@ -0,0 +1,128 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { Inject, Injectable } from '@nestjs/common'; +import { In } from 'typeorm'; +import { DI } from '@/di-symbols.js'; +import { bindThis } from '@/decorators.js'; +import type { AbuseUserReportsRepository, MiAbuseUserReport, MiUser, UsersRepository } from '@/models/_.js'; +import { AbuseReportNotificationService } from '@/core/AbuseReportNotificationService.js'; +import { QueueService } from '@/core/QueueService.js'; +import { InstanceActorService } from '@/core/InstanceActorService.js'; +import { ApRendererService } from '@/core/activitypub/ApRendererService.js'; +import { ModerationLogService } from '@/core/ModerationLogService.js'; +import { IdService } from './IdService.js'; + +@Injectable() +export class AbuseReportService { + constructor( + @Inject(DI.abuseUserReportsRepository) + private abuseUserReportsRepository: AbuseUserReportsRepository, + @Inject(DI.usersRepository) + private usersRepository: UsersRepository, + private idService: IdService, + private abuseReportNotificationService: AbuseReportNotificationService, + private queueService: QueueService, + private instanceActorService: InstanceActorService, + private apRendererService: ApRendererService, + private moderationLogService: ModerationLogService, + ) { + } + + /** + * ユーザからの通報をDBに記録し、その内容を下記の手段で管理者各位に通知する. + * - 管理者用Redisイベント + * - EMail(モデレータ権限所有者ユーザ+metaテーブルに設定されているメールアドレス) + * - SystemWebhook + * + * @param params 通報内容. もし複数件の通報に対応した時のために、あらかじめ複数件を処理できる前提で考える + * @see AbuseReportNotificationService.notify + */ + @bindThis + public async report(params: { + targetUserId: MiAbuseUserReport['targetUserId'], + targetUserHost: MiAbuseUserReport['targetUserHost'], + reporterId: MiAbuseUserReport['reporterId'], + reporterHost: MiAbuseUserReport['reporterHost'], + comment: string, + }[]) { + const entities = params.map(param => { + return { + id: this.idService.gen(), + targetUserId: param.targetUserId, + targetUserHost: param.targetUserHost, + reporterId: param.reporterId, + reporterHost: param.reporterHost, + comment: param.comment, + }; + }); + + const reports = Array.of(); + for (const entity of entities) { + const report = await this.abuseUserReportsRepository.insertOne(entity); + reports.push(report); + } + + return Promise.all([ + this.abuseReportNotificationService.notifyAdminStream(reports), + this.abuseReportNotificationService.notifySystemWebhook(reports, 'abuseReport'), + this.abuseReportNotificationService.notifyMail(reports), + ]); + } + + /** + * 通報を解決し、その内容を下記の手段で管理者各位に通知する. + * - SystemWebhook + * + * @param params 通報内容. もし複数件の通報に対応した時のために、あらかじめ複数件を処理できる前提で考える + * @param operator 通報を処理したユーザ + * @see AbuseReportNotificationService.notify + */ + @bindThis + public async resolve( + params: { + reportId: string; + forward: boolean; + }[], + operator: MiUser, + ) { + const paramsMap = new Map(params.map(it => [it.reportId, it])); + const reports = await this.abuseUserReportsRepository.findBy({ + id: In(params.map(it => it.reportId)), + }); + + for (const report of reports) { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const ps = paramsMap.get(report.id)!; + + await this.abuseUserReportsRepository.update(report.id, { + resolved: true, + assigneeId: operator.id, + forwarded: ps.forward && report.targetUserHost !== null, + }); + + if (ps.forward && report.targetUserHost != null) { + const actor = await this.instanceActorService.getInstanceActor(); + const targetUser = await this.usersRepository.findOneByOrFail({ id: report.targetUserId }); + + // eslint-disable-next-line + const flag = this.apRendererService.renderFlag(actor, targetUser.uri!, report.comment); + const contextAssignedFlag = this.apRendererService.addContext(flag); + this.queueService.deliver(actor, contextAssignedFlag, targetUser.inbox, false); + } + + this.moderationLogService + .log(operator, 'resolveAbuseReport', { + reportId: report.id, + report: report, + forwarded: ps.forward && report.targetUserHost !== null, + }) + .then(); + } + + return this.abuseUserReportsRepository.findBy({ id: In(reports.map(it => it.id)) }) + .then(reports => this.abuseReportNotificationService.notifySystemWebhook(reports, 'abuseReportResolved')); + } +} diff --git a/packages/backend/src/core/AccountUpdateService.ts b/packages/backend/src/core/AccountUpdateService.ts index 69a57b4854..ca0864f679 100644 --- a/packages/backend/src/core/AccountUpdateService.ts +++ b/packages/backend/src/core/AccountUpdateService.ts @@ -3,7 +3,8 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import { Inject, Injectable } from '@nestjs/common'; +import { Inject, Injectable, OnModuleInit } from '@nestjs/common'; +import { ModuleRef } from '@nestjs/core'; import { DI } from '@/di-symbols.js'; import type { UsersRepository } from '@/models/_.js'; import type { MiUser } from '@/models/User.js'; @@ -12,30 +13,44 @@ import { RelayService } from '@/core/RelayService.js'; import { ApDeliverManagerService } from '@/core/activitypub/ApDeliverManagerService.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { bindThis } from '@/decorators.js'; +import type { PrivateKeyWithPem } from '@misskey-dev/node-http-message-signatures'; @Injectable() -export class AccountUpdateService { +export class AccountUpdateService implements OnModuleInit { + private apDeliverManagerService: ApDeliverManagerService; constructor( + private moduleRef: ModuleRef, + @Inject(DI.usersRepository) private usersRepository: UsersRepository, private userEntityService: UserEntityService, private apRendererService: ApRendererService, - private apDeliverManagerService: ApDeliverManagerService, private relayService: RelayService, ) { } + async onModuleInit() { + this.apDeliverManagerService = this.moduleRef.get(ApDeliverManagerService.name); + } + @bindThis - public async publishToFollowers(userId: MiUser['id']) { + /** + * Deliver account update to followers + * @param userId user id + * @param deliverKey optional. Private key to sign the deliver. + */ + public async publishToFollowers(userId: MiUser['id'], deliverKey?: PrivateKeyWithPem) { const user = await this.usersRepository.findOneBy({ id: userId }); if (user == null) throw new Error('user not found'); // フォロワーがリモートユーザーかつ投稿者がローカルユーザーならUpdateを配信 if (this.userEntityService.isLocalUser(user)) { const content = this.apRendererService.addContext(this.apRendererService.renderUpdate(await this.apRendererService.renderPerson(user), user)); - this.apDeliverManagerService.deliverToFollowers(user, content); - this.relayService.deliverToRelays(user, content); + await Promise.allSettled([ + this.apDeliverManagerService.deliverToFollowers(user, content, deliverKey), + this.relayService.deliverToRelays(user, content, deliverKey), + ]); } } } diff --git a/packages/backend/src/core/ClipService.ts b/packages/backend/src/core/ClipService.ts index 9fd1ebad87..929a9db064 100644 --- a/packages/backend/src/core/ClipService.ts +++ b/packages/backend/src/core/ClipService.ts @@ -41,7 +41,7 @@ export class ClipService { const currentCount = await this.clipsRepository.countBy({ userId: me.id, }); - if (currentCount > (await this.roleService.getUserPolicies(me.id)).clipLimit) { + if (currentCount >= (await this.roleService.getUserPolicies(me.id)).clipLimit) { throw new ClipService.TooManyClipsError(); } @@ -102,7 +102,7 @@ export class ClipService { const currentCount = await this.clipNotesRepository.countBy({ clipId: clip.id, }); - if (currentCount > (await this.roleService.getUserPolicies(me.id)).noteEachClipsLimit) { + if (currentCount >= (await this.roleService.getUserPolicies(me.id)).noteEachClipsLimit) { throw new ClipService.TooManyClipNotesError(); } diff --git a/packages/backend/src/core/CoreModule.ts b/packages/backend/src/core/CoreModule.ts index be80df6f1c..c9427bbeb7 100644 --- a/packages/backend/src/core/CoreModule.ts +++ b/packages/backend/src/core/CoreModule.ts @@ -5,6 +5,14 @@ import { Module } from '@nestjs/common'; import { FanoutTimelineEndpointService } from '@/core/FanoutTimelineEndpointService.js'; +import { AbuseReportService } from '@/core/AbuseReportService.js'; +import { SystemWebhookEntityService } from '@/core/entities/SystemWebhookEntityService.js'; +import { + AbuseReportNotificationRecipientEntityService, +} from '@/core/entities/AbuseReportNotificationRecipientEntityService.js'; +import { AbuseReportNotificationService } from '@/core/AbuseReportNotificationService.js'; +import { SystemWebhookService } from '@/core/SystemWebhookService.js'; +import { UserSearchService } from '@/core/UserSearchService.js'; import { AccountMoveService } from './AccountMoveService.js'; import { AccountUpdateService } from './AccountUpdateService.js'; import { AiService } from './AiService.js'; @@ -53,10 +61,11 @@ import { UserFollowingService } from './UserFollowingService.js'; import { UserKeypairService } from './UserKeypairService.js'; import { UserListService } from './UserListService.js'; import { UserMutingService } from './UserMutingService.js'; +import { UserRenoteMutingService } from './UserRenoteMutingService.js'; import { UserSuspendService } from './UserSuspendService.js'; import { UserAuthService } from './UserAuthService.js'; import { VideoProcessingService } from './VideoProcessingService.js'; -import { WebhookService } from './WebhookService.js'; +import { UserWebhookService } from './UserWebhookService.js'; import { ProxyAccountService } from './ProxyAccountService.js'; import { UtilityService } from './UtilityService.js'; import { FileInfoService } from './FileInfoService.js'; @@ -144,6 +153,8 @@ import type { Provider } from '@nestjs/common'; //#region 文字列ベースでのinjection用(循環参照対応のため) const $LoggerService: Provider = { provide: 'LoggerService', useExisting: LoggerService }; +const $AbuseReportService: Provider = { provide: 'AbuseReportService', useExisting: AbuseReportService }; +const $AbuseReportNotificationService: Provider = { provide: 'AbuseReportNotificationService', useExisting: AbuseReportNotificationService }; const $AccountMoveService: Provider = { provide: 'AccountMoveService', useExisting: AccountMoveService }; const $AccountUpdateService: Provider = { provide: 'AccountUpdateService', useExisting: AccountUpdateService }; const $AiService: Provider = { provide: 'AiService', useExisting: AiService }; @@ -193,10 +204,13 @@ const $UserFollowingService: Provider = { provide: 'UserFollowingService', useEx const $UserKeypairService: Provider = { provide: 'UserKeypairService', useExisting: UserKeypairService }; const $UserListService: Provider = { provide: 'UserListService', useExisting: UserListService }; const $UserMutingService: Provider = { provide: 'UserMutingService', useExisting: UserMutingService }; +const $UserRenoteMutingService: Provider = { provide: 'UserRenoteMutingService', useExisting: UserRenoteMutingService }; +const $UserSearchService: Provider = { provide: 'UserSearchService', useExisting: UserSearchService }; const $UserSuspendService: Provider = { provide: 'UserSuspendService', useExisting: UserSuspendService }; const $UserAuthService: Provider = { provide: 'UserAuthService', useExisting: UserAuthService }; const $VideoProcessingService: Provider = { provide: 'VideoProcessingService', useExisting: VideoProcessingService }; -const $WebhookService: Provider = { provide: 'WebhookService', useExisting: WebhookService }; +const $UserWebhookService: Provider = { provide: 'UserWebhookService', useExisting: UserWebhookService }; +const $SystemWebhookService: Provider = { provide: 'SystemWebhookService', useExisting: SystemWebhookService }; const $UtilityService: Provider = { provide: 'UtilityService', useExisting: UtilityService }; const $FileInfoService: Provider = { provide: 'FileInfoService', useExisting: FileInfoService }; const $SearchService: Provider = { provide: 'SearchService', useExisting: SearchService }; @@ -225,6 +239,7 @@ const $ChartManagementService: Provider = { provide: 'ChartManagementService', u const $AbuseUserReportEntityService: Provider = { provide: 'AbuseUserReportEntityService', useExisting: AbuseUserReportEntityService }; const $AnnouncementEntityService: Provider = { provide: 'AnnouncementEntityService', useExisting: AnnouncementEntityService }; +const $AbuseReportNotificationRecipientEntityService: Provider = { provide: 'AbuseReportNotificationRecipientEntityService', useExisting: AbuseReportNotificationRecipientEntityService }; const $AntennaEntityService: Provider = { provide: 'AntennaEntityService', useExisting: AntennaEntityService }; const $AppEntityService: Provider = { provide: 'AppEntityService', useExisting: AppEntityService }; const $AuthSessionEntityService: Provider = { provide: 'AuthSessionEntityService', useExisting: AuthSessionEntityService }; @@ -258,6 +273,7 @@ const $FlashLikeEntityService: Provider = { provide: 'FlashLikeEntityService', u const $RoleEntityService: Provider = { provide: 'RoleEntityService', useExisting: RoleEntityService }; const $ReversiGameEntityService: Provider = { provide: 'ReversiGameEntityService', useExisting: ReversiGameEntityService }; const $MetaEntityService: Provider = { provide: 'MetaEntityService', useExisting: MetaEntityService }; +const $SystemWebhookEntityService: Provider = { provide: 'SystemWebhookEntityService', useExisting: SystemWebhookEntityService }; const $ApAudienceService: Provider = { provide: 'ApAudienceService', useExisting: ApAudienceService }; const $ApDbResolverService: Provider = { provide: 'ApDbResolverService', useExisting: ApDbResolverService }; @@ -285,6 +301,8 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting ], providers: [ LoggerService, + AbuseReportService, + AbuseReportNotificationService, AccountMoveService, AccountUpdateService, AiService, @@ -334,10 +352,13 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting UserKeypairService, UserListService, UserMutingService, + UserRenoteMutingService, + UserSearchService, UserSuspendService, UserAuthService, VideoProcessingService, - WebhookService, + UserWebhookService, + SystemWebhookService, UtilityService, FileInfoService, SearchService, @@ -366,6 +387,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting AbuseUserReportEntityService, AnnouncementEntityService, + AbuseReportNotificationRecipientEntityService, AntennaEntityService, AppEntityService, AuthSessionEntityService, @@ -399,6 +421,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting RoleEntityService, ReversiGameEntityService, MetaEntityService, + SystemWebhookEntityService, ApAudienceService, ApDbResolverService, @@ -422,6 +445,8 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting //#region 文字列ベースでのinjection用(循環参照対応のため) $LoggerService, + $AbuseReportService, + $AbuseReportNotificationService, $AccountMoveService, $AccountUpdateService, $AiService, @@ -471,10 +496,13 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting $UserKeypairService, $UserListService, $UserMutingService, + $UserRenoteMutingService, + $UserSearchService, $UserSuspendService, $UserAuthService, $VideoProcessingService, - $WebhookService, + $UserWebhookService, + $SystemWebhookService, $UtilityService, $FileInfoService, $SearchService, @@ -503,6 +531,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting $AbuseUserReportEntityService, $AnnouncementEntityService, + $AbuseReportNotificationRecipientEntityService, $AntennaEntityService, $AppEntityService, $AuthSessionEntityService, @@ -536,6 +565,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting $RoleEntityService, $ReversiGameEntityService, $MetaEntityService, + $SystemWebhookEntityService, $ApAudienceService, $ApDbResolverService, @@ -560,6 +590,8 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting exports: [ QueueModule, LoggerService, + AbuseReportService, + AbuseReportNotificationService, AccountMoveService, AccountUpdateService, AiService, @@ -609,10 +641,13 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting UserKeypairService, UserListService, UserMutingService, + UserRenoteMutingService, + UserSearchService, UserSuspendService, UserAuthService, VideoProcessingService, - WebhookService, + UserWebhookService, + SystemWebhookService, UtilityService, FileInfoService, SearchService, @@ -640,6 +675,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting AbuseUserReportEntityService, AnnouncementEntityService, + AbuseReportNotificationRecipientEntityService, AntennaEntityService, AppEntityService, AuthSessionEntityService, @@ -673,6 +709,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting RoleEntityService, ReversiGameEntityService, MetaEntityService, + SystemWebhookEntityService, ApAudienceService, ApDbResolverService, @@ -696,6 +733,8 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting //#region 文字列ベースでのinjection用(循環参照対応のため) $LoggerService, + $AbuseReportService, + $AbuseReportNotificationService, $AccountMoveService, $AccountUpdateService, $AiService, @@ -745,10 +784,13 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting $UserKeypairService, $UserListService, $UserMutingService, + $UserRenoteMutingService, + $UserSearchService, $UserSuspendService, $UserAuthService, $VideoProcessingService, - $WebhookService, + $UserWebhookService, + $SystemWebhookService, $UtilityService, $FileInfoService, $SearchService, @@ -776,6 +818,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting $AbuseUserReportEntityService, $AnnouncementEntityService, + $AbuseReportNotificationRecipientEntityService, $AntennaEntityService, $AppEntityService, $AuthSessionEntityService, @@ -809,6 +852,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting $RoleEntityService, $ReversiGameEntityService, $MetaEntityService, + $SystemWebhookEntityService, $ApAudienceService, $ApDbResolverService, diff --git a/packages/backend/src/core/CreateSystemUserService.ts b/packages/backend/src/core/CreateSystemUserService.ts index 6c5b0f6a36..60ddc9cde2 100644 --- a/packages/backend/src/core/CreateSystemUserService.ts +++ b/packages/backend/src/core/CreateSystemUserService.ts @@ -7,7 +7,7 @@ import { randomUUID } from 'node:crypto'; import { Inject, Injectable } from '@nestjs/common'; import bcrypt from 'bcryptjs'; import { IsNull, DataSource } from 'typeorm'; -import { genRsaKeyPair } from '@/misc/gen-key-pair.js'; +import { genRSAAndEd25519KeyPair } from '@/misc/gen-key-pair.js'; import { MiUser } from '@/models/User.js'; import { MiUserProfile } from '@/models/UserProfile.js'; import { IdService } from '@/core/IdService.js'; @@ -38,7 +38,7 @@ export class CreateSystemUserService { // Generate secret const secret = generateNativeUserToken(); - const keyPair = await genRsaKeyPair(); + const keyPair = await genRSAAndEd25519KeyPair(); let account!: MiUser; @@ -64,9 +64,8 @@ export class CreateSystemUserService { }).then(x => transactionalEntityManager.findOneByOrFail(MiUser, x.identifiers[0])); await transactionalEntityManager.insert(MiUserKeypair, { - publicKey: keyPair.publicKey, - privateKey: keyPair.privateKey, userId: account.id, + ...keyPair, }); await transactionalEntityManager.insert(MiUserProfile, { diff --git a/packages/backend/src/core/EmailService.ts b/packages/backend/src/core/EmailService.ts index 08f8f80a6e..435dbbae28 100644 --- a/packages/backend/src/core/EmailService.ts +++ b/packages/backend/src/core/EmailService.ts @@ -16,6 +16,7 @@ import type { UserProfilesRepository } from '@/models/_.js'; import { LoggerService } from '@/core/LoggerService.js'; import { bindThis } from '@/decorators.js'; import { HttpRequestService } from '@/core/HttpRequestService.js'; +import { QueueService } from '@/core/QueueService.js'; @Injectable() export class EmailService { @@ -32,6 +33,7 @@ export class EmailService { private loggerService: LoggerService, private utilityService: UtilityService, private httpRequestService: HttpRequestService, + private queueService: QueueService, ) { this.logger = this.loggerService.getLogger('email'); } diff --git a/packages/backend/src/core/FanoutTimelineEndpointService.ts b/packages/backend/src/core/FanoutTimelineEndpointService.ts index d5058f37c2..b05af99c5e 100644 --- a/packages/backend/src/core/FanoutTimelineEndpointService.ts +++ b/packages/backend/src/core/FanoutTimelineEndpointService.ts @@ -55,9 +55,6 @@ export class FanoutTimelineEndpointService { @bindThis private async getMiNotes(ps: TimelineOptions): Promise { - let noteIds: string[]; - let shouldFallbackToDb = false; - // 呼び出し元と以下の処理をシンプルにするためにdbFallbackを置き換える if (!ps.useDbFallback) ps.dbFallback = () => Promise.resolve([]); @@ -67,12 +64,11 @@ export class FanoutTimelineEndpointService { const redisResult = await this.fanoutTimelineService.getMulti(ps.redisTimelines, ps.untilId, ps.sinceId); // TODO: いい感じにgetMulti内でソート済だからuniqするときにredisResultが全てソート済なのを利用して再ソートを避けたい - const redisResultIds = Array.from(new Set(redisResult.flat(1))); + const redisResultIds = Array.from(new Set(redisResult.flat(1))).sort(idCompare); - redisResultIds.sort(idCompare); - noteIds = redisResultIds.slice(0, ps.limit); - - shouldFallbackToDb = shouldFallbackToDb || (noteIds.length === 0); + let noteIds = redisResultIds.slice(0, ps.limit); + const oldestNoteId = ascending ? redisResultIds[0] : redisResultIds[redisResultIds.length - 1]; + const shouldFallbackToDb = noteIds.length === 0 || ps.sinceId != null && ps.sinceId < oldestNoteId; if (!shouldFallbackToDb) { let filter = ps.noteFilter ?? (_note => true); diff --git a/packages/backend/src/core/FederatedInstanceService.ts b/packages/backend/src/core/FederatedInstanceService.ts index 6799f2c5bb..7aeeb78178 100644 --- a/packages/backend/src/core/FederatedInstanceService.ts +++ b/packages/backend/src/core/FederatedInstanceService.ts @@ -40,6 +40,7 @@ export class FederatedInstanceService implements OnApplicationShutdown { firstRetrievedAt: new Date(parsed.firstRetrievedAt), latestRequestReceivedAt: parsed.latestRequestReceivedAt ? new Date(parsed.latestRequestReceivedAt) : null, infoUpdatedAt: parsed.infoUpdatedAt ? new Date(parsed.infoUpdatedAt) : null, + notRespondingSince: parsed.notRespondingSince ? new Date(parsed.notRespondingSince) : null, }; }, }); diff --git a/packages/backend/src/core/FetchInstanceMetadataService.ts b/packages/backend/src/core/FetchInstanceMetadataService.ts index aa16468ecb..dc53c8711d 100644 --- a/packages/backend/src/core/FetchInstanceMetadataService.ts +++ b/packages/backend/src/core/FetchInstanceMetadataService.ts @@ -15,6 +15,7 @@ import { LoggerService } from '@/core/LoggerService.js'; import { HttpRequestService } from '@/core/HttpRequestService.js'; import { bindThis } from '@/decorators.js'; import { FederatedInstanceService } from '@/core/FederatedInstanceService.js'; +import { REMOTE_SERVER_CACHE_TTL } from '@/const.js'; import type { DOMWindow } from 'jsdom'; type NodeInfo = { @@ -24,6 +25,7 @@ type NodeInfo = { version?: unknown; }; metadata?: { + httpMessageSignaturesImplementationLevel?: unknown, name?: unknown; nodeName?: unknown; nodeDescription?: unknown; @@ -39,6 +41,7 @@ type NodeInfo = { @Injectable() export class FetchInstanceMetadataService { private logger: Logger; + private httpColon = 'https://'; constructor( private httpRequestService: HttpRequestService, @@ -48,6 +51,7 @@ export class FetchInstanceMetadataService { private redisClient: Redis.Redis, ) { this.logger = this.loggerService.getLogger('metadata', 'cyan'); + this.httpColon = process.env.MISSKEY_USE_HTTP?.toLowerCase() === 'true' ? 'http://' : 'https://'; } @bindThis @@ -59,7 +63,7 @@ export class FetchInstanceMetadataService { return await this.redisClient.set( `fetchInstanceMetadata:mutex:v2:${host}`, '1', 'EX', 30, // 30秒したら自動でロック解除 https://github.com/misskey-dev/misskey/issues/13506#issuecomment-1975375395 - 'GET' // 古い値を返す(なかったらnull) + 'GET', // 古い値を返す(なかったらnull) ); } @@ -73,23 +77,24 @@ export class FetchInstanceMetadataService { public async fetchInstanceMetadata(instance: MiInstance, force = false): Promise { const host = instance.host; - // finallyでunlockされてしまうのでtry内でロックチェックをしない - // (returnであってもfinallyは実行される) - if (!force && await this.tryLock(host) === '1') { - // 1が返ってきていたらロックされているという意味なので、何もしない - return; + if (!force) { + // キャッシュ有効チェックはロック取得前に行う + const _instance = await this.federatedInstanceService.fetch(host); + const now = Date.now(); + if (_instance && _instance.infoUpdatedAt != null && (now - _instance.infoUpdatedAt.getTime() < REMOTE_SERVER_CACHE_TTL)) { + this.logger.debug(`Skip because updated recently ${_instance.infoUpdatedAt.toJSON()}`); + return; + } + + // finallyでunlockされてしまうのでtry内でロックチェックをしない + // (returnであってもfinallyは実行される) + if (await this.tryLock(host) === '1') { + // 1が返ってきていたら他にロックされているという意味なので、何もしない + return; + } } try { - if (!force) { - const _instance = await this.federatedInstanceService.fetch(host); - const now = Date.now(); - if (_instance && _instance.infoUpdatedAt && (now - _instance.infoUpdatedAt.getTime() < 1000 * 60 * 60 * 24)) { - // unlock at the finally caluse - return; - } - } - this.logger.info(`Fetching metadata of ${instance.host} ...`); const [info, dom, manifest] = await Promise.all([ @@ -118,6 +123,14 @@ export class FetchInstanceMetadataService { updates.openRegistrations = info.openRegistrations; updates.maintainerName = info.metadata ? info.metadata.maintainer ? (info.metadata.maintainer.name ?? null) : null : null; updates.maintainerEmail = info.metadata ? info.metadata.maintainer ? (info.metadata.maintainer.email ?? null) : null : null; + if (info.metadata && info.metadata.httpMessageSignaturesImplementationLevel && ( + info.metadata.httpMessageSignaturesImplementationLevel === '01' || + info.metadata.httpMessageSignaturesImplementationLevel === '11' + )) { + updates.httpMessageSignaturesImplementationLevel = info.metadata.httpMessageSignaturesImplementationLevel; + } else { + updates.httpMessageSignaturesImplementationLevel = '00'; + } } if (name) updates.name = name; @@ -129,6 +142,12 @@ export class FetchInstanceMetadataService { await this.federatedInstanceService.update(instance.id, updates); this.logger.succ(`Successfuly updated metadata of ${instance.host}`); + this.logger.debug('Updated metadata:', { + info: !!info, + dom: !!dom, + manifest: !!manifest, + updates, + }); } catch (e) { this.logger.error(`Failed to update metadata of ${instance.host}: ${e}`); } finally { @@ -141,7 +160,7 @@ export class FetchInstanceMetadataService { this.logger.info(`Fetching nodeinfo of ${instance.host} ...`); try { - const wellknown = await this.httpRequestService.getJson('https://' + instance.host + '/.well-known/nodeinfo') + const wellknown = await this.httpRequestService.getJson(this.httpColon + instance.host + '/.well-known/nodeinfo') .catch(err => { if (err.statusCode === 404) { throw new Error('No nodeinfo provided'); @@ -184,7 +203,7 @@ export class FetchInstanceMetadataService { private async fetchDom(instance: MiInstance): Promise { this.logger.info(`Fetching HTML of ${instance.host} ...`); - const url = 'https://' + instance.host; + const url = this.httpColon + instance.host; const html = await this.httpRequestService.getHtml(url); @@ -196,7 +215,7 @@ export class FetchInstanceMetadataService { @bindThis private async fetchManifest(instance: MiInstance): Promise | null> { - const url = 'https://' + instance.host; + const url = this.httpColon + instance.host; const manifestUrl = url + '/manifest.json'; @@ -207,7 +226,7 @@ export class FetchInstanceMetadataService { @bindThis private async fetchFaviconUrl(instance: MiInstance, doc: DOMWindow['document'] | null): Promise { - const url = 'https://' + instance.host; + const url = this.httpColon + instance.host; if (doc) { // https://github.com/misskey-dev/misskey/pull/8220#issuecomment-1025104043 @@ -234,12 +253,12 @@ export class FetchInstanceMetadataService { @bindThis private async fetchIconUrl(instance: MiInstance, doc: DOMWindow['document'] | null, manifest: Record | null): Promise { if (manifest && manifest.icons && manifest.icons.length > 0 && manifest.icons[0].src) { - const url = 'https://' + instance.host; + const url = this.httpColon + instance.host; return (new URL(manifest.icons[0].src, url)).href; } if (doc) { - const url = 'https://' + instance.host; + const url = this.httpColon + instance.host; // https://github.com/misskey-dev/misskey/pull/8220#issuecomment-1025104043 const links = Array.from(doc.getElementsByTagName('link')).reverse(); diff --git a/packages/backend/src/core/GlobalEventService.ts b/packages/backend/src/core/GlobalEventService.ts index 4adf8ac197..9e94f67703 100644 --- a/packages/backend/src/core/GlobalEventService.ts +++ b/packages/backend/src/core/GlobalEventService.ts @@ -18,6 +18,7 @@ import type { MiAbuseUserReport } from '@/models/AbuseUserReport.js'; import type { MiSignin } from '@/models/Signin.js'; import type { MiPage } from '@/models/Page.js'; import type { MiWebhook } from '@/models/Webhook.js'; +import type { MiSystemWebhook } from '@/models/SystemWebhook.js'; import type { MiMeta } from '@/models/Meta.js'; import { MiAvatarDecoration, MiReversiGame, MiRole, MiRoleAssignment } from '@/models/_.js'; import type { Packed } from '@/misc/json-schema.js'; @@ -212,6 +213,10 @@ type SerializedAll = { [K in keyof T]: Serialized; }; +type UndefinedAsNullAll = { + [K in keyof T]: T[K] extends undefined ? null : T[K]; +} + export interface InternalEventTypes { userChangeSuspendedState: { id: MiUser['id']; isSuspended: MiUser['isSuspended']; }; userChangeDeletedState: { id: MiUser['id']; isDeleted: MiUser['isDeleted']; }; @@ -231,6 +236,9 @@ export interface InternalEventTypes { webhookCreated: MiWebhook; webhookDeleted: MiWebhook; webhookUpdated: MiWebhook; + systemWebhookCreated: MiSystemWebhook; + systemWebhookDeleted: MiSystemWebhook; + systemWebhookUpdated: MiSystemWebhook; antennaCreated: MiAntenna; antennaDeleted: MiAntenna; antennaUpdated: MiAntenna; @@ -245,45 +253,48 @@ export interface InternalEventTypes { unmute: { muterId: MiUser['id']; muteeId: MiUser['id']; }; userListMemberAdded: { userListId: MiUserList['id']; memberId: MiUser['id']; }; userListMemberRemoved: { userListId: MiUserList['id']; memberId: MiUser['id']; }; + userKeypairUpdated: { userId: MiUser['id']; }; } +type EventTypesToEventPayload = EventUnionFromDictionary>>; + // name/messages(spec) pairs dictionary export type GlobalEvents = { internal: { name: 'internal'; - payload: EventUnionFromDictionary>; + payload: EventTypesToEventPayload; }; broadcast: { name: 'broadcast'; - payload: EventUnionFromDictionary>; + payload: EventTypesToEventPayload; }; main: { name: `mainStream:${MiUser['id']}`; - payload: EventUnionFromDictionary>; + payload: EventTypesToEventPayload; }; drive: { name: `driveStream:${MiUser['id']}`; - payload: EventUnionFromDictionary>; + payload: EventTypesToEventPayload; }; note: { name: `noteStream:${MiNote['id']}`; - payload: EventUnionFromDictionary>; + payload: EventTypesToEventPayload; }; userList: { name: `userListStream:${MiUserList['id']}`; - payload: EventUnionFromDictionary>; + payload: EventTypesToEventPayload; }; roleTimeline: { name: `roleTimelineStream:${MiRole['id']}`; - payload: EventUnionFromDictionary>; + payload: EventTypesToEventPayload; }; antenna: { name: `antennaStream:${MiAntenna['id']}`; - payload: EventUnionFromDictionary>; + payload: EventTypesToEventPayload; }; admin: { name: `adminStream:${MiUser['id']}`; - payload: EventUnionFromDictionary>; + payload: EventTypesToEventPayload; }; notes: { name: 'notesStream'; @@ -291,11 +302,11 @@ export type GlobalEvents = { }; reversi: { name: `reversiStream:${MiUser['id']}`; - payload: EventUnionFromDictionary>; + payload: EventTypesToEventPayload; }; reversiGame: { name: `reversiGameStream:${MiReversiGame['id']}`; - payload: EventUnionFromDictionary>; + payload: EventTypesToEventPayload; }; }; diff --git a/packages/backend/src/core/HttpRequestService.ts b/packages/backend/src/core/HttpRequestService.ts index 7f3cac7c58..4249c158d7 100644 --- a/packages/backend/src/core/HttpRequestService.ts +++ b/packages/backend/src/core/HttpRequestService.ts @@ -70,7 +70,7 @@ export class HttpRequestService { localAddress: config.outgoingAddress, }); - const maxSockets = Math.max(256, config.deliverJobConcurrency ?? 128); + const maxSockets = Math.max(256, config.deliverJobConcurrency ?? 16); this.httpAgent = config.proxy ? new HttpProxyAgent({ diff --git a/packages/backend/src/core/LoggerService.ts b/packages/backend/src/core/LoggerService.ts index 96d9b09992..f102461a50 100644 --- a/packages/backend/src/core/LoggerService.ts +++ b/packages/backend/src/core/LoggerService.ts @@ -15,7 +15,7 @@ export class LoggerService { } @bindThis - public getLogger(domain: string, color?: KEYWORD | undefined, store?: boolean) { - return new Logger(domain, color, store); + public getLogger(domain: string, color?: KEYWORD | undefined) { + return new Logger(domain, color); } } diff --git a/packages/backend/src/core/MfmService.ts b/packages/backend/src/core/MfmService.ts index 9786f8b8bb..74536c68f5 100644 --- a/packages/backend/src/core/MfmService.ts +++ b/packages/backend/src/core/MfmService.ts @@ -13,10 +13,12 @@ import { intersperse } from '@/misc/prelude/array.js'; import { normalizeForSearch } from '@/misc/normalize-for-search.js'; import type { IMentionedRemoteUsers } from '@/models/Note.js'; import { bindThis } from '@/decorators.js'; -import * as TreeAdapter from '../../node_modules/parse5/dist/tree-adapters/default.js'; +import type { DefaultTreeAdapterMap } from 'parse5'; import type * as mfm from 'mfm-js'; -const treeAdapter = TreeAdapter.defaultTreeAdapter; +const treeAdapter = parse5.defaultTreeAdapter; +type Node = DefaultTreeAdapterMap['node']; +type ChildNode = DefaultTreeAdapterMap['childNode']; const urlRegex = /^https?:\/\/[\w\/:%#@$&?!()\[\]~.,=+\-]+/; const urlRegexFull = /^https?:\/\/[\w\/:%#@$&?!()\[\]~.,=+\-]+$/; @@ -46,7 +48,7 @@ export class MfmService { return text.trim(); - function getText(node: TreeAdapter.Node): string { + function getText(node: Node): string { if (treeAdapter.isTextNode(node)) return node.value; if (!treeAdapter.isElementNode(node)) return ''; if (node.nodeName === 'br') return '\n'; @@ -58,7 +60,7 @@ export class MfmService { return ''; } - function appendChildren(childNodes: TreeAdapter.ChildNode[]): void { + function appendChildren(childNodes: ChildNode[]): void { if (childNodes) { for (const n of childNodes) { analyze(n); @@ -66,14 +68,16 @@ export class MfmService { } } - function analyze(node: TreeAdapter.Node) { + function analyze(node: Node) { if (treeAdapter.isTextNode(node)) { text += node.value; return; } // Skip comment or document type node - if (!treeAdapter.isElementNode(node)) return; + if (!treeAdapter.isElementNode(node)) { + return; + } switch (node.nodeName) { case 'br': { @@ -81,8 +85,7 @@ export class MfmService { break; } - case 'a': - { + case 'a': { const txt = getText(node); const rel = node.attrs.find(x => x.name === 'rel'); const href = node.attrs.find(x => x.name === 'href'); @@ -90,7 +93,7 @@ export class MfmService { // ハッシュタグ if (normalizedHashtagNames && href && normalizedHashtagNames.has(normalizeForSearch(txt))) { text += txt; - // メンション + // メンション } else if (txt.startsWith('@') && !(rel && rel.value.startsWith('me '))) { const part = txt.split('@'); @@ -102,7 +105,7 @@ export class MfmService { } else if (part.length === 3) { text += txt; } - // その他 + // その他 } else { const generateLink = () => { if (!href && !txt) { @@ -130,8 +133,7 @@ export class MfmService { break; } - case 'h1': - { + case 'h1': { text += '【'; appendChildren(node.childNodes); text += '】\n'; @@ -139,16 +141,14 @@ export class MfmService { } case 'b': - case 'strong': - { + case 'strong': { text += '**'; appendChildren(node.childNodes); text += '**'; break; } - case 'small': - { + case 'small': { text += ''; appendChildren(node.childNodes); text += ''; @@ -156,8 +156,7 @@ export class MfmService { } case 's': - case 'del': - { + case 'del': { text += '~~'; appendChildren(node.childNodes); text += '~~'; @@ -165,8 +164,7 @@ export class MfmService { } case 'i': - case 'em': - { + case 'em': { text += ''; appendChildren(node.childNodes); text += ''; @@ -207,8 +205,7 @@ export class MfmService { case 'h3': case 'h4': case 'h5': - case 'h6': - { + case 'h6': { text += '\n\n'; appendChildren(node.childNodes); break; @@ -221,8 +218,7 @@ export class MfmService { case 'article': case 'li': case 'dt': - case 'dd': - { + case 'dd': { text += '\n'; appendChildren(node.childNodes); break; diff --git a/packages/backend/src/core/NoteCreateService.ts b/packages/backend/src/core/NoteCreateService.ts index e5580f36d1..a2c3aaa701 100644 --- a/packages/backend/src/core/NoteCreateService.ts +++ b/packages/backend/src/core/NoteCreateService.ts @@ -38,7 +38,7 @@ import InstanceChart from '@/core/chart/charts/instance.js'; import ActiveUsersChart from '@/core/chart/charts/active-users.js'; import { GlobalEventService } from '@/core/GlobalEventService.js'; import { NotificationService } from '@/core/NotificationService.js'; -import { WebhookService } from '@/core/WebhookService.js'; +import { UserWebhookService } from '@/core/UserWebhookService.js'; import { HashtagService } from '@/core/HashtagService.js'; import { AntennaService } from '@/core/AntennaService.js'; import { QueueService } from '@/core/QueueService.js'; @@ -59,7 +59,6 @@ import { UtilityService } from '@/core/UtilityService.js'; import { UserBlockingService } from '@/core/UserBlockingService.js'; import { isReply } from '@/misc/is-reply.js'; import { trackPromise } from '@/misc/promise-tracker.js'; -import { isNotNull } from '@/misc/is-not-null.js'; import { IdentifiableError } from '@/misc/identifiable-error.js'; type NotificationType = 'reply' | 'renote' | 'quote' | 'mention'; @@ -205,7 +204,7 @@ export class NoteCreateService implements OnApplicationShutdown { private federatedInstanceService: FederatedInstanceService, private hashtagService: HashtagService, private antennaService: AntennaService, - private webhookService: WebhookService, + private webhookService: UserWebhookService, private featuredService: FeaturedService, private remoteUserResolveService: RemoteUserResolveService, private apDeliverManagerService: ApDeliverManagerService, @@ -606,7 +605,7 @@ export class NoteCreateService implements OnApplicationShutdown { this.webhookService.getActiveWebhooks().then(webhooks => { webhooks = webhooks.filter(x => x.userId === user.id && x.on.includes('note')); for (const webhook of webhooks) { - this.queueService.webhookDeliver(webhook, 'note', { + this.queueService.userWebhookDeliver(webhook, 'note', { note: noteObj, }); } @@ -633,7 +632,7 @@ export class NoteCreateService implements OnApplicationShutdown { const webhooks = (await this.webhookService.getActiveWebhooks()).filter(x => x.userId === data.reply!.userId && x.on.includes('reply')); for (const webhook of webhooks) { - this.queueService.webhookDeliver(webhook, 'reply', { + this.queueService.userWebhookDeliver(webhook, 'reply', { note: noteObj, }); } @@ -656,7 +655,7 @@ export class NoteCreateService implements OnApplicationShutdown { const webhooks = (await this.webhookService.getActiveWebhooks()).filter(x => x.userId === data.renote!.userId && x.on.includes('renote')); for (const webhook of webhooks) { - this.queueService.webhookDeliver(webhook, 'renote', { + this.queueService.userWebhookDeliver(webhook, 'renote', { note: noteObj, }); } @@ -788,7 +787,7 @@ export class NoteCreateService implements OnApplicationShutdown { const webhooks = (await this.webhookService.getActiveWebhooks()).filter(x => x.userId === u.id && x.on.includes('mention')); for (const webhook of webhooks) { - this.queueService.webhookDeliver(webhook, 'mention', { + this.queueService.userWebhookDeliver(webhook, 'mention', { note: detailPackedNote, }); } @@ -839,7 +838,7 @@ export class NoteCreateService implements OnApplicationShutdown { const mentions = extractMentions(tokens); let mentionedUsers = (await Promise.all(mentions.map(m => this.remoteUserResolveService.resolveUser(m.username, m.host ?? user.host).catch(() => null), - ))).filter(isNotNull); + ))).filter(x => x != null); // Drop duplicate users mentionedUsers = mentionedUsers.filter((u, i, self) => diff --git a/packages/backend/src/core/QueueModule.ts b/packages/backend/src/core/QueueModule.ts index 216734e9e5..b10b8e5899 100644 --- a/packages/backend/src/core/QueueModule.ts +++ b/packages/backend/src/core/QueueModule.ts @@ -7,10 +7,17 @@ import { Inject, Module, OnApplicationShutdown } from '@nestjs/common'; import * as Bull from 'bullmq'; import { DI } from '@/di-symbols.js'; import type { Config } from '@/config.js'; -import { QUEUE, baseQueueOptions } from '@/queue/const.js'; +import { baseQueueOptions, QUEUE } from '@/queue/const.js'; import { allSettled } from '@/misc/promise-tracker.js'; +import { + DeliverJobData, + EndedPollNotificationJobData, + InboxJobData, + RelationshipJobData, + UserWebhookDeliverJobData, + SystemWebhookDeliverJobData, +} from '../queue/types.js'; import type { Provider } from '@nestjs/common'; -import type { DeliverJobData, InboxJobData, EndedPollNotificationJobData, WebhookDeliverJobData, RelationshipJobData } from '../queue/types.js'; export type SystemQueue = Bull.Queue>; export type EndedPollNotificationQueue = Bull.Queue; @@ -19,7 +26,8 @@ export type InboxQueue = Bull.Queue; export type DbQueue = Bull.Queue; export type RelationshipQueue = Bull.Queue; export type ObjectStorageQueue = Bull.Queue; -export type WebhookDeliverQueue = Bull.Queue; +export type UserWebhookDeliverQueue = Bull.Queue; +export type SystemWebhookDeliverQueue = Bull.Queue; const $system: Provider = { provide: 'queue:system', @@ -63,9 +71,15 @@ const $objectStorage: Provider = { inject: [DI.config], }; -const $webhookDeliver: Provider = { - provide: 'queue:webhookDeliver', - useFactory: (config: Config) => new Bull.Queue(QUEUE.WEBHOOK_DELIVER, baseQueueOptions(config, QUEUE.WEBHOOK_DELIVER)), +const $userWebhookDeliver: Provider = { + provide: 'queue:userWebhookDeliver', + useFactory: (config: Config) => new Bull.Queue(QUEUE.USER_WEBHOOK_DELIVER, baseQueueOptions(config, QUEUE.USER_WEBHOOK_DELIVER)), + inject: [DI.config], +}; + +const $systemWebhookDeliver: Provider = { + provide: 'queue:systemWebhookDeliver', + useFactory: (config: Config) => new Bull.Queue(QUEUE.SYSTEM_WEBHOOK_DELIVER, baseQueueOptions(config, QUEUE.SYSTEM_WEBHOOK_DELIVER)), inject: [DI.config], }; @@ -80,7 +94,8 @@ const $webhookDeliver: Provider = { $db, $relationship, $objectStorage, - $webhookDeliver, + $userWebhookDeliver, + $systemWebhookDeliver, ], exports: [ $system, @@ -90,7 +105,8 @@ const $webhookDeliver: Provider = { $db, $relationship, $objectStorage, - $webhookDeliver, + $userWebhookDeliver, + $systemWebhookDeliver, ], }) export class QueueModule implements OnApplicationShutdown { @@ -102,7 +118,8 @@ export class QueueModule implements OnApplicationShutdown { @Inject('queue:db') public dbQueue: DbQueue, @Inject('queue:relationship') public relationshipQueue: RelationshipQueue, @Inject('queue:objectStorage') public objectStorageQueue: ObjectStorageQueue, - @Inject('queue:webhookDeliver') public webhookDeliverQueue: WebhookDeliverQueue, + @Inject('queue:userWebhookDeliver') public userWebhookDeliverQueue: UserWebhookDeliverQueue, + @Inject('queue:systemWebhookDeliver') public systemWebhookDeliverQueue: SystemWebhookDeliverQueue, ) {} public async dispose(): Promise { @@ -117,7 +134,8 @@ export class QueueModule implements OnApplicationShutdown { this.dbQueue.close(), this.relationshipQueue.close(), this.objectStorageQueue.close(), - this.webhookDeliverQueue.close(), + this.userWebhookDeliverQueue.close(), + this.systemWebhookDeliverQueue.close(), ]); } diff --git a/packages/backend/src/core/QueueService.ts b/packages/backend/src/core/QueueService.ts index c258a22927..dd3f2182b4 100644 --- a/packages/backend/src/core/QueueService.ts +++ b/packages/backend/src/core/QueueService.ts @@ -8,15 +8,32 @@ import { Inject, Injectable } from '@nestjs/common'; import type { IActivity } from '@/core/activitypub/type.js'; import type { MiDriveFile } from '@/models/DriveFile.js'; import type { MiWebhook, webhookEventTypes } from '@/models/Webhook.js'; +import type { MiSystemWebhook, SystemWebhookEventType } from '@/models/SystemWebhook.js'; import type { Config } from '@/config.js'; import { DI } from '@/di-symbols.js'; import { bindThis } from '@/decorators.js'; import type { Antenna } from '@/server/api/endpoints/i/import-antennas.js'; -import type { DbQueue, DeliverQueue, EndedPollNotificationQueue, InboxQueue, ObjectStorageQueue, RelationshipQueue, SystemQueue, WebhookDeliverQueue } from './QueueModule.js'; -import type { DbJobData, DeliverJobData, RelationshipJobData, ThinUser } from '../queue/types.js'; -import type httpSignature from '@peertube/http-signature'; +import type { + DbJobData, + DeliverJobData, + RelationshipJobData, + SystemWebhookDeliverJobData, + ThinUser, + UserWebhookDeliverJobData, +} from '../queue/types.js'; +import type { + DbQueue, + DeliverQueue, + EndedPollNotificationQueue, + InboxQueue, + ObjectStorageQueue, + RelationshipQueue, + SystemQueue, + UserWebhookDeliverQueue, + SystemWebhookDeliverQueue, +} from './QueueModule.js'; +import { genRFC3230DigestHeader, type PrivateKeyWithPem, type ParsedSignature } from '@misskey-dev/node-http-message-signatures'; import type * as Bull from 'bullmq'; -import { ApRequestCreator } from '@/core/activitypub/ApRequestService.js'; @Injectable() export class QueueService { @@ -31,7 +48,8 @@ export class QueueService { @Inject('queue:db') public dbQueue: DbQueue, @Inject('queue:relationship') public relationshipQueue: RelationshipQueue, @Inject('queue:objectStorage') public objectStorageQueue: ObjectStorageQueue, - @Inject('queue:webhookDeliver') public webhookDeliverQueue: WebhookDeliverQueue, + @Inject('queue:userWebhookDeliver') public userWebhookDeliverQueue: UserWebhookDeliverQueue, + @Inject('queue:systemWebhookDeliver') public systemWebhookDeliverQueue: SystemWebhookDeliverQueue, ) { this.systemQueue.add('tickCharts', { }, { @@ -71,21 +89,21 @@ export class QueueService { } @bindThis - public deliver(user: ThinUser, content: IActivity | null, to: string | null, isSharedInbox: boolean) { + public async deliver(user: ThinUser, content: IActivity | null, to: string | null, isSharedInbox: boolean, privateKey?: PrivateKeyWithPem) { if (content == null) return null; if (to == null) return null; const contentBody = JSON.stringify(content); - const digest = ApRequestCreator.createDigest(contentBody); const data: DeliverJobData = { user: { id: user.id, }, content: contentBody, - digest, + digest: await genRFC3230DigestHeader(contentBody, 'SHA-256'), to, isSharedInbox, + privateKey: privateKey && { keyId: privateKey.keyId, privateKeyPem: privateKey.privateKeyPem }, }; return this.deliverQueue.add(to, data, { @@ -103,13 +121,13 @@ export class QueueService { * @param user `{ id: string; }` この関数ではThinUserに変換しないので前もって変換してください * @param content IActivity | null * @param inboxes `Map` / key: to (inbox url), value: isSharedInbox (whether it is sharedInbox) + * @param forceMainKey boolean | undefined, force to use main (rsa) key * @returns void */ @bindThis - public async deliverMany(user: ThinUser, content: IActivity | null, inboxes: Map) { + public async deliverMany(user: ThinUser, content: IActivity | null, inboxes: Map, privateKey?: PrivateKeyWithPem) { if (content == null) return null; const contentBody = JSON.stringify(content); - const digest = ApRequestCreator.createDigest(contentBody); const opts = { attempts: this.config.deliverJobMaxAttempts ?? 12, @@ -125,9 +143,9 @@ export class QueueService { data: { user, content: contentBody, - digest, to: d[0], isSharedInbox: d[1], + privateKey: privateKey && { keyId: privateKey.keyId, privateKeyPem: privateKey.privateKeyPem }, } as DeliverJobData, opts, }))); @@ -136,7 +154,7 @@ export class QueueService { } @bindThis - public inbox(activity: IActivity, signature: httpSignature.IParsedSignature) { + public inbox(activity: IActivity, signature: ParsedSignature | null) { const data = { activity: activity, signature, @@ -431,9 +449,13 @@ export class QueueService { }); } + /** + * @see UserWebhookDeliverJobData + * @see WebhookDeliverProcessorService + */ @bindThis - public webhookDeliver(webhook: MiWebhook, type: typeof webhookEventTypes[number], content: unknown) { - const data = { + public userWebhookDeliver(webhook: MiWebhook, type: typeof webhookEventTypes[number], content: unknown) { + const data: UserWebhookDeliverJobData = { type, content, webhookId: webhook.id, @@ -444,7 +466,33 @@ export class QueueService { eventId: randomUUID(), }; - return this.webhookDeliverQueue.add(webhook.id, data, { + return this.userWebhookDeliverQueue.add(webhook.id, data, { + attempts: 4, + backoff: { + type: 'custom', + }, + removeOnComplete: true, + removeOnFail: true, + }); + } + + /** + * @see SystemWebhookDeliverJobData + * @see WebhookDeliverProcessorService + */ + @bindThis + public systemWebhookDeliver(webhook: MiSystemWebhook, type: SystemWebhookEventType, content: unknown) { + const data: SystemWebhookDeliverJobData = { + type, + content, + webhookId: webhook.id, + to: webhook.url, + secret: webhook.secret, + createdAt: Date.now(), + eventId: randomUUID(), + }; + + return this.systemWebhookDeliverQueue.add(webhook.id, data, { attempts: 4, backoff: { type: 'custom', diff --git a/packages/backend/src/core/ReactionService.ts b/packages/backend/src/core/ReactionService.ts index 60cc5a0d12..d2d93de7e8 100644 --- a/packages/backend/src/core/ReactionService.ts +++ b/packages/backend/src/core/ReactionService.ts @@ -29,6 +29,7 @@ import { CustomEmojiService } from '@/core/CustomEmojiService.js'; import { RoleService } from '@/core/RoleService.js'; import { FeaturedService } from '@/core/FeaturedService.js'; import { trackPromise } from '@/misc/promise-tracker.js'; +import { isQuote, isRenote } from '@/misc/is-renote.js'; const FALLBACK = '\u2764'; const PER_NOTE_REACTION_USER_PAIR_CACHE_MAX = 16; @@ -117,11 +118,16 @@ export class ReactionService { throw new IdentifiableError('68e9d2d1-48bf-42c2-b90a-b20e09fd3d48', 'Note not accessible for you.'); } + // Check if note is Renote + if (isRenote(note) && !isQuote(note)) { + throw new IdentifiableError('12c35529-3c79-4327-b1cc-e2cf63a71925', 'You cannot react to Renote.'); + } + let reaction = _reaction ?? FALLBACK; if (note.reactionAcceptance === 'likeOnly' || ((note.reactionAcceptance === 'likeOnlyForRemote' || note.reactionAcceptance === 'nonSensitiveOnlyForLocalLikeOnlyForRemote') && (user.host != null))) { reaction = '\u2764'; - } else if (_reaction) { + } else if (_reaction != null) { const custom = reaction.match(isCustomEmojiRegexp); if (custom) { const reacterHost = this.utilityService.toPunyNullable(user.host); diff --git a/packages/backend/src/core/RelayService.ts b/packages/backend/src/core/RelayService.ts index 8dd3d64f5b..ad01f98902 100644 --- a/packages/backend/src/core/RelayService.ts +++ b/packages/backend/src/core/RelayService.ts @@ -16,6 +16,8 @@ import { ApRendererService } from '@/core/activitypub/ApRendererService.js'; import { DI } from '@/di-symbols.js'; import { deepClone } from '@/misc/clone.js'; import { bindThis } from '@/decorators.js'; +import { UserKeypairService } from './UserKeypairService.js'; +import type { PrivateKeyWithPem } from '@misskey-dev/node-http-message-signatures'; const ACTOR_USERNAME = 'relay.actor' as const; @@ -34,6 +36,7 @@ export class RelayService { private queueService: QueueService, private createSystemUserService: CreateSystemUserService, private apRendererService: ApRendererService, + private userKeypairService: UserKeypairService, ) { this.relaysCache = new MemorySingleCache(1000 * 60 * 10); } @@ -111,7 +114,7 @@ export class RelayService { } @bindThis - public async deliverToRelays(user: { id: MiUser['id']; host: null; }, activity: any): Promise { + public async deliverToRelays(user: { id: MiUser['id']; host: null; }, activity: any, privateKey?: PrivateKeyWithPem): Promise { if (activity == null) return; const relays = await this.relaysCache.fetch(() => this.relaysRepository.findBy({ @@ -121,11 +124,9 @@ export class RelayService { const copy = deepClone(activity); if (!copy.to) copy.to = ['https://www.w3.org/ns/activitystreams#Public']; + privateKey = privateKey ?? await this.userKeypairService.getLocalUserPrivateKeyPem(user.id); + const signed = await this.apRendererService.attachLdSignature(copy, privateKey); - const signed = await this.apRendererService.attachLdSignature(copy, user); - - for (const relay of relays) { - this.queueService.deliver(user, signed, relay.inbox, false); - } + this.queueService.deliverMany(user, signed, new Map(relays.map(({ inbox }) => [inbox, false])), privateKey); } } diff --git a/packages/backend/src/core/RoleService.ts b/packages/backend/src/core/RoleService.ts index d6eea70297..94026fd503 100644 --- a/packages/backend/src/core/RoleService.ts +++ b/packages/backend/src/core/RoleService.ts @@ -47,6 +47,7 @@ export type RolePolicies = { canHideAds: boolean; driveCapacityMb: number; alwaysMarkNsfw: boolean; + canUpdateBioMedia: boolean; pinLimit: number; antennaLimit: number; wordMuteLimit: number; @@ -75,6 +76,7 @@ export const DEFAULT_POLICIES: RolePolicies = { canHideAds: false, driveCapacityMb: 100, alwaysMarkNsfw: false, + canUpdateBioMedia: true, pinLimit: 5, antennaLimit: 5, wordMuteLimit: 200, @@ -376,6 +378,7 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit { canHideAds: calc('canHideAds', vs => vs.some(v => v === true)), driveCapacityMb: calc('driveCapacityMb', vs => Math.max(...vs)), alwaysMarkNsfw: calc('alwaysMarkNsfw', vs => vs.some(v => v === true)), + canUpdateBioMedia: calc('canUpdateBioMedia', vs => vs.some(v => v === true)), pinLimit: calc('pinLimit', vs => Math.max(...vs)), antennaLimit: calc('antennaLimit', vs => Math.max(...vs)), wordMuteLimit: calc('wordMuteLimit', vs => Math.max(...vs)), @@ -410,14 +413,32 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit { } @bindThis - public async getModeratorIds(includeAdmins = true): Promise { + public async getModeratorIds(includeAdmins = true, excludeExpire = false): Promise { const roles = await this.rolesCache.fetch(() => this.rolesRepository.findBy({})); - const moderatorRoles = includeAdmins ? roles.filter(r => r.isModerator || r.isAdministrator) : roles.filter(r => r.isModerator); - const assigns = moderatorRoles.length > 0 ? await this.roleAssignmentsRepository.findBy({ - roleId: In(moderatorRoles.map(r => r.id)), - }) : []; + const moderatorRoles = includeAdmins + ? roles.filter(r => r.isModerator || r.isAdministrator) + : roles.filter(r => r.isModerator); + // TODO: isRootなアカウントも含める - return assigns.map(a => a.userId); + const assigns = moderatorRoles.length > 0 + ? await this.roleAssignmentsRepository.findBy({ roleId: In(moderatorRoles.map(r => r.id)) }) + : []; + + const now = Date.now(); + const result = [ + // Setを経由して重複を除去(ユーザIDは重複する可能性があるので) + ...new Set( + assigns + .filter(it => + (excludeExpire) + ? (it.expiresAt == null || it.expiresAt.getTime() > now) + : true, + ) + .map(a => a.userId), + ), + ]; + + return result.sort((x, y) => x.localeCompare(y)); } @bindThis diff --git a/packages/backend/src/core/SignupService.ts b/packages/backend/src/core/SignupService.ts index 5522ecd6cc..54c6170062 100644 --- a/packages/backend/src/core/SignupService.ts +++ b/packages/backend/src/core/SignupService.ts @@ -3,7 +3,6 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import { generateKeyPair } from 'node:crypto'; import { Inject, Injectable } from '@nestjs/common'; import bcrypt from 'bcryptjs'; import { DataSource, IsNull } from 'typeorm'; @@ -21,6 +20,7 @@ import { bindThis } from '@/decorators.js'; import UsersChart from '@/core/chart/charts/users.js'; import { UtilityService } from '@/core/UtilityService.js'; import { MetaService } from '@/core/MetaService.js'; +import { genRSAAndEd25519KeyPair } from '@/misc/gen-key-pair.js'; @Injectable() export class SignupService { @@ -93,22 +93,7 @@ export class SignupService { } } - const keyPair = await new Promise((res, rej) => - generateKeyPair('rsa', { - modulusLength: 2048, - publicKeyEncoding: { - type: 'spki', - format: 'pem', - }, - privateKeyEncoding: { - type: 'pkcs8', - format: 'pem', - cipher: undefined, - passphrase: undefined, - }, - }, (err, publicKey, privateKey) => - err ? rej(err) : res([publicKey, privateKey]), - )); + const keyPair = await genRSAAndEd25519KeyPair(); let account!: MiUser; @@ -131,9 +116,8 @@ export class SignupService { })); await transactionalEntityManager.save(new MiUserKeypair({ - publicKey: keyPair[0], - privateKey: keyPair[1], userId: account.id, + ...keyPair, })); await transactionalEntityManager.save(new MiUserProfile({ diff --git a/packages/backend/src/core/SystemWebhookService.ts b/packages/backend/src/core/SystemWebhookService.ts new file mode 100644 index 0000000000..bc6851f788 --- /dev/null +++ b/packages/backend/src/core/SystemWebhookService.ts @@ -0,0 +1,233 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { Inject, Injectable } from '@nestjs/common'; +import * as Redis from 'ioredis'; +import type { MiUser, SystemWebhooksRepository } from '@/models/_.js'; +import { DI } from '@/di-symbols.js'; +import { bindThis } from '@/decorators.js'; +import { GlobalEvents, GlobalEventService } from '@/core/GlobalEventService.js'; +import { MiSystemWebhook, type SystemWebhookEventType } from '@/models/SystemWebhook.js'; +import { IdService } from '@/core/IdService.js'; +import { QueueService } from '@/core/QueueService.js'; +import { ModerationLogService } from '@/core/ModerationLogService.js'; +import { LoggerService } from '@/core/LoggerService.js'; +import Logger from '@/logger.js'; +import type { OnApplicationShutdown } from '@nestjs/common'; + +@Injectable() +export class SystemWebhookService implements OnApplicationShutdown { + private logger: Logger; + private activeSystemWebhooksFetched = false; + private activeSystemWebhooks: MiSystemWebhook[] = []; + + constructor( + @Inject(DI.redisForSub) + private redisForSub: Redis.Redis, + @Inject(DI.systemWebhooksRepository) + private systemWebhooksRepository: SystemWebhooksRepository, + private idService: IdService, + private queueService: QueueService, + private moderationLogService: ModerationLogService, + private loggerService: LoggerService, + private globalEventService: GlobalEventService, + ) { + this.redisForSub.on('message', this.onMessage); + this.logger = this.loggerService.getLogger('webhook'); + } + + @bindThis + public async fetchActiveSystemWebhooks() { + if (!this.activeSystemWebhooksFetched) { + this.activeSystemWebhooks = await this.systemWebhooksRepository.findBy({ + isActive: true, + }); + this.activeSystemWebhooksFetched = true; + } + + return this.activeSystemWebhooks; + } + + /** + * SystemWebhook の一覧を取得する. + */ + @bindThis + public async fetchSystemWebhooks(params?: { + ids?: MiSystemWebhook['id'][]; + isActive?: MiSystemWebhook['isActive']; + on?: MiSystemWebhook['on']; + }): Promise { + const query = this.systemWebhooksRepository.createQueryBuilder('systemWebhook'); + if (params) { + if (params.ids && params.ids.length > 0) { + query.andWhere('systemWebhook.id IN (:...ids)', { ids: params.ids }); + } + if (params.isActive !== undefined) { + query.andWhere('systemWebhook.isActive = :isActive', { isActive: params.isActive }); + } + if (params.on && params.on.length > 0) { + query.andWhere(':on <@ systemWebhook.on', { on: params.on }); + } + } + + return query.getMany(); + } + + /** + * SystemWebhook を作成する. + */ + @bindThis + public async createSystemWebhook( + params: { + isActive: MiSystemWebhook['isActive']; + name: MiSystemWebhook['name']; + on: MiSystemWebhook['on']; + url: MiSystemWebhook['url']; + secret: MiSystemWebhook['secret']; + }, + updater: MiUser, + ): Promise { + const id = this.idService.gen(); + await this.systemWebhooksRepository.insert({ + ...params, + id, + }); + + const webhook = await this.systemWebhooksRepository.findOneByOrFail({ id }); + this.globalEventService.publishInternalEvent('systemWebhookCreated', webhook); + this.moderationLogService + .log(updater, 'createSystemWebhook', { + systemWebhookId: webhook.id, + webhook: webhook, + }) + .then(); + + return webhook; + } + + /** + * SystemWebhook を更新する. + */ + @bindThis + public async updateSystemWebhook( + params: { + id: MiSystemWebhook['id']; + isActive: MiSystemWebhook['isActive']; + name: MiSystemWebhook['name']; + on: MiSystemWebhook['on']; + url: MiSystemWebhook['url']; + secret: MiSystemWebhook['secret']; + }, + updater: MiUser, + ): Promise { + const beforeEntity = await this.systemWebhooksRepository.findOneByOrFail({ id: params.id }); + await this.systemWebhooksRepository.update(beforeEntity.id, { + updatedAt: new Date(), + isActive: params.isActive, + name: params.name, + on: params.on, + url: params.url, + secret: params.secret, + }); + + const afterEntity = await this.systemWebhooksRepository.findOneByOrFail({ id: beforeEntity.id }); + this.globalEventService.publishInternalEvent('systemWebhookUpdated', afterEntity); + this.moderationLogService + .log(updater, 'updateSystemWebhook', { + systemWebhookId: beforeEntity.id, + before: beforeEntity, + after: afterEntity, + }) + .then(); + + return afterEntity; + } + + /** + * SystemWebhook を削除する. + */ + @bindThis + public async deleteSystemWebhook(id: MiSystemWebhook['id'], updater: MiUser) { + const webhook = await this.systemWebhooksRepository.findOneByOrFail({ id }); + await this.systemWebhooksRepository.delete(id); + + this.globalEventService.publishInternalEvent('systemWebhookDeleted', webhook); + this.moderationLogService + .log(updater, 'deleteSystemWebhook', { + systemWebhookId: webhook.id, + webhook, + }) + .then(); + } + + /** + * SystemWebhook をWebhook配送キューに追加する + * @see QueueService.systemWebhookDeliver + */ + @bindThis + public async enqueueSystemWebhook(webhook: MiSystemWebhook | MiSystemWebhook['id'], type: SystemWebhookEventType, content: unknown) { + const webhookEntity = typeof webhook === 'string' + ? (await this.fetchActiveSystemWebhooks()).find(a => a.id === webhook) + : webhook; + if (!webhookEntity || !webhookEntity.isActive) { + this.logger.info(`Webhook is not active or not found : ${webhook}`); + return; + } + + if (!webhookEntity.on.includes(type)) { + this.logger.info(`Webhook ${webhookEntity.id} is not listening to ${type}`); + return; + } + + return this.queueService.systemWebhookDeliver(webhookEntity, type, content); + } + + @bindThis + private async onMessage(_: string, data: string): Promise { + const obj = JSON.parse(data); + if (obj.channel !== 'internal') { + return; + } + + const { type, body } = obj.message as GlobalEvents['internal']['payload']; + switch (type) { + case 'systemWebhookCreated': { + if (body.isActive) { + this.activeSystemWebhooks.push(MiSystemWebhook.deserialize(body)); + } + break; + } + case 'systemWebhookUpdated': { + if (body.isActive) { + const i = this.activeSystemWebhooks.findIndex(a => a.id === body.id); + if (i > -1) { + this.activeSystemWebhooks[i] = MiSystemWebhook.deserialize(body); + } else { + this.activeSystemWebhooks.push(MiSystemWebhook.deserialize(body)); + } + } else { + this.activeSystemWebhooks = this.activeSystemWebhooks.filter(a => a.id !== body.id); + } + break; + } + case 'systemWebhookDeleted': { + this.activeSystemWebhooks = this.activeSystemWebhooks.filter(a => a.id !== body.id); + break; + } + default: + break; + } + } + + @bindThis + public dispose(): void { + this.redisForSub.off('message', this.onMessage); + } + + @bindThis + public onApplicationShutdown(signal?: string | undefined): void { + this.dispose(); + } +} diff --git a/packages/backend/src/core/UserBlockingService.ts b/packages/backend/src/core/UserBlockingService.ts index 96f389b54c..2f1310b8ef 100644 --- a/packages/backend/src/core/UserBlockingService.ts +++ b/packages/backend/src/core/UserBlockingService.ts @@ -16,7 +16,7 @@ import Logger from '@/logger.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { ApRendererService } from '@/core/activitypub/ApRendererService.js'; import { LoggerService } from '@/core/LoggerService.js'; -import { WebhookService } from '@/core/WebhookService.js'; +import { UserWebhookService } from '@/core/UserWebhookService.js'; import { bindThis } from '@/decorators.js'; import { CacheService } from '@/core/CacheService.js'; import { UserFollowingService } from '@/core/UserFollowingService.js'; @@ -46,7 +46,7 @@ export class UserBlockingService implements OnModuleInit { private idService: IdService, private queueService: QueueService, private globalEventService: GlobalEventService, - private webhookService: WebhookService, + private webhookService: UserWebhookService, private apRendererService: ApRendererService, private loggerService: LoggerService, ) { @@ -121,7 +121,7 @@ export class UserBlockingService implements OnModuleInit { const webhooks = (await this.webhookService.getActiveWebhooks()).filter(x => x.userId === follower.id && x.on.includes('unfollow')); for (const webhook of webhooks) { - this.queueService.webhookDeliver(webhook, 'unfollow', { + this.queueService.userWebhookDeliver(webhook, 'unfollow', { user: packed, }); } diff --git a/packages/backend/src/core/UserFollowingService.ts b/packages/backend/src/core/UserFollowingService.ts index 406ea04031..267a6a3f1b 100644 --- a/packages/backend/src/core/UserFollowingService.ts +++ b/packages/backend/src/core/UserFollowingService.ts @@ -16,7 +16,7 @@ import { isDuplicateKeyValueError } from '@/misc/is-duplicate-key-value-error.js import type { Packed } from '@/misc/json-schema.js'; import InstanceChart from '@/core/chart/charts/instance.js'; import { FederatedInstanceService } from '@/core/FederatedInstanceService.js'; -import { WebhookService } from '@/core/WebhookService.js'; +import { UserWebhookService } from '@/core/UserWebhookService.js'; import { NotificationService } from '@/core/NotificationService.js'; import { DI } from '@/di-symbols.js'; import type { FollowingsRepository, FollowRequestsRepository, InstancesRepository, UserProfilesRepository, UsersRepository } from '@/models/_.js'; @@ -82,7 +82,7 @@ export class UserFollowingService implements OnModuleInit { private metaService: MetaService, private notificationService: NotificationService, private federatedInstanceService: FederatedInstanceService, - private webhookService: WebhookService, + private webhookService: UserWebhookService, private apRendererService: ApRendererService, private accountMoveService: AccountMoveService, private fanoutTimelineService: FanoutTimelineService, @@ -331,7 +331,7 @@ export class UserFollowingService implements OnModuleInit { const webhooks = (await this.webhookService.getActiveWebhooks()).filter(x => x.userId === follower.id && x.on.includes('follow')); for (const webhook of webhooks) { - this.queueService.webhookDeliver(webhook, 'follow', { + this.queueService.userWebhookDeliver(webhook, 'follow', { user: packed, }); } @@ -345,7 +345,7 @@ export class UserFollowingService implements OnModuleInit { const webhooks = (await this.webhookService.getActiveWebhooks()).filter(x => x.userId === followee.id && x.on.includes('followed')); for (const webhook of webhooks) { - this.queueService.webhookDeliver(webhook, 'followed', { + this.queueService.userWebhookDeliver(webhook, 'followed', { user: packed, }); } @@ -398,7 +398,7 @@ export class UserFollowingService implements OnModuleInit { const webhooks = (await this.webhookService.getActiveWebhooks()).filter(x => x.userId === follower.id && x.on.includes('unfollow')); for (const webhook of webhooks) { - this.queueService.webhookDeliver(webhook, 'unfollow', { + this.queueService.userWebhookDeliver(webhook, 'unfollow', { user: packed, }); } @@ -740,7 +740,7 @@ export class UserFollowingService implements OnModuleInit { const webhooks = (await this.webhookService.getActiveWebhooks()).filter(x => x.userId === follower.id && x.on.includes('unfollow')); for (const webhook of webhooks) { - this.queueService.webhookDeliver(webhook, 'unfollow', { + this.queueService.userWebhookDeliver(webhook, 'unfollow', { user: packedFollowee, }); } diff --git a/packages/backend/src/core/UserKeypairService.ts b/packages/backend/src/core/UserKeypairService.ts index 51ac99179a..aa90f1e209 100644 --- a/packages/backend/src/core/UserKeypairService.ts +++ b/packages/backend/src/core/UserKeypairService.ts @@ -5,41 +5,184 @@ import { Inject, Injectable, OnApplicationShutdown } from '@nestjs/common'; import * as Redis from 'ioredis'; +import { genEd25519KeyPair, importPrivateKey, PrivateKey, PrivateKeyWithPem } from '@misskey-dev/node-http-message-signatures'; import type { MiUser } from '@/models/User.js'; import type { UserKeypairsRepository } from '@/models/_.js'; -import { RedisKVCache } from '@/misc/cache.js'; +import { RedisKVCache, MemoryKVCache } from '@/misc/cache.js'; import type { MiUserKeypair } from '@/models/UserKeypair.js'; import { DI } from '@/di-symbols.js'; import { bindThis } from '@/decorators.js'; +import { GlobalEventService, GlobalEvents } from '@/core/GlobalEventService.js'; +import { UserEntityService } from '@/core/entities/UserEntityService.js'; +import type { webcrypto } from 'node:crypto'; @Injectable() export class UserKeypairService implements OnApplicationShutdown { - private cache: RedisKVCache; + private keypairEntityCache: RedisKVCache; + private privateKeyObjectCache: MemoryKVCache; constructor( @Inject(DI.redis) private redisClient: Redis.Redis, - + @Inject(DI.redisForSub) + private redisForSub: Redis.Redis, @Inject(DI.userKeypairsRepository) private userKeypairsRepository: UserKeypairsRepository, + + private globalEventService: GlobalEventService, + private userEntityService: UserEntityService, ) { - this.cache = new RedisKVCache(this.redisClient, 'userKeypair', { + this.keypairEntityCache = new RedisKVCache(this.redisClient, 'userKeypair', { lifetime: 1000 * 60 * 60 * 24, // 24h memoryCacheLifetime: Infinity, fetcher: (key) => this.userKeypairsRepository.findOneByOrFail({ userId: key }), toRedisConverter: (value) => JSON.stringify(value), fromRedisConverter: (value) => JSON.parse(value), }); + this.privateKeyObjectCache = new MemoryKVCache(1000 * 60 * 60 * 1); + + this.redisForSub.on('message', this.onMessage); } @bindThis public async getUserKeypair(userId: MiUser['id']): Promise { - return await this.cache.fetch(userId); + return await this.keypairEntityCache.fetch(userId); + } + + /** + * Get private key [Only PrivateKeyWithPem for queue data etc.] + * @param userIdOrHint user id or MiUserKeypair + * @param preferType + * If ed25519-like(`ed25519`, `01`, `11`) is specified, ed25519 keypair will be returned if exists. + * Otherwise, main keypair will be returned. + * @returns + */ + @bindThis + public async getLocalUserPrivateKeyPem( + userIdOrHint: MiUser['id'] | MiUserKeypair, + preferType?: string, + ): Promise { + const keypair = typeof userIdOrHint === 'string' ? await this.getUserKeypair(userIdOrHint) : userIdOrHint; + if ( + preferType && ['01', '11', 'ed25519'].includes(preferType.toLowerCase()) && + keypair.ed25519PublicKey != null && keypair.ed25519PrivateKey != null + ) { + return { + keyId: `${this.userEntityService.genLocalUserUri(keypair.userId)}#ed25519-key`, + privateKeyPem: keypair.ed25519PrivateKey, + }; + } + return { + keyId: `${this.userEntityService.genLocalUserUri(keypair.userId)}#main-key`, + privateKeyPem: keypair.privateKey, + }; + } + + /** + * Get private key [Only PrivateKey for ap request] + * Using cache due to performance reasons of `crypto.subtle.importKey` + * @param userIdOrHint user id, MiUserKeypair, or PrivateKeyWithPem + * @param preferType + * If ed25519-like(`ed25519`, `01`, `11`) is specified, ed25519 keypair will be returned if exists. + * Otherwise, main keypair will be returned. (ignored if userIdOrHint is PrivateKeyWithPem) + * @returns + */ + @bindThis + public async getLocalUserPrivateKey( + userIdOrHint: MiUser['id'] | MiUserKeypair | PrivateKeyWithPem, + preferType?: string, + ): Promise { + if (typeof userIdOrHint === 'object' && 'privateKeyPem' in userIdOrHint) { + // userIdOrHint is PrivateKeyWithPem + return { + keyId: userIdOrHint.keyId, + privateKey: await this.privateKeyObjectCache.fetch(userIdOrHint.keyId, async () => { + return await importPrivateKey(userIdOrHint.privateKeyPem); + }), + }; + } + + const userId = typeof userIdOrHint === 'string' ? userIdOrHint : userIdOrHint.userId; + const getKeypair = () => typeof userIdOrHint === 'string' ? this.getUserKeypair(userId) : userIdOrHint; + + if (preferType && ['01', '11', 'ed25519'].includes(preferType.toLowerCase())) { + const keyId = `${this.userEntityService.genLocalUserUri(userId)}#ed25519-key`; + const fetched = await this.privateKeyObjectCache.fetchMaybe(keyId, async () => { + const keypair = await getKeypair(); + if (keypair.ed25519PublicKey != null && keypair.ed25519PrivateKey != null) { + return await importPrivateKey(keypair.ed25519PrivateKey); + } + return; + }); + if (fetched) { + return { + keyId, + privateKey: fetched, + }; + } + } + + const keyId = `${this.userEntityService.genLocalUserUri(userId)}#main-key`; + return { + keyId, + privateKey: await this.privateKeyObjectCache.fetch(keyId, async () => { + const keypair = await getKeypair(); + return await importPrivateKey(keypair.privateKey); + }), + }; } + @bindThis + public async refresh(userId: MiUser['id']): Promise { + return await this.keypairEntityCache.refresh(userId); + } + + /** + * If DB has ed25519 keypair, refresh cache and return it. + * If not, create, save and return ed25519 keypair. + * @param userId user id + * @returns MiUserKeypair if keypair is created, void if keypair is already exists + */ + @bindThis + public async refreshAndPrepareEd25519KeyPair(userId: MiUser['id']): Promise { + await this.refresh(userId); + const keypair = await this.keypairEntityCache.fetch(userId); + if (keypair.ed25519PublicKey != null) { + return; + } + + const ed25519 = await genEd25519KeyPair(); + await this.userKeypairsRepository.update({ userId }, { + ed25519PublicKey: ed25519.publicKey, + ed25519PrivateKey: ed25519.privateKey, + }); + this.globalEventService.publishInternalEvent('userKeypairUpdated', { userId }); + const result = { + ...keypair, + ed25519PublicKey: ed25519.publicKey, + ed25519PrivateKey: ed25519.privateKey, + }; + this.keypairEntityCache.set(userId, result); + return result; + } + + @bindThis + private async onMessage(_: string, data: string): Promise { + const obj = JSON.parse(data); + + if (obj.channel === 'internal') { + const { type, body } = obj.message as GlobalEvents['internal']['payload']; + switch (type) { + case 'userKeypairUpdated': { + this.refresh(body.userId); + break; + } + } + } + } @bindThis public dispose(): void { - this.cache.dispose(); + this.keypairEntityCache.dispose(); } @bindThis diff --git a/packages/backend/src/core/UserListService.ts b/packages/backend/src/core/UserListService.ts index bbdcfed738..6333356fe9 100644 --- a/packages/backend/src/core/UserListService.ts +++ b/packages/backend/src/core/UserListService.ts @@ -95,7 +95,7 @@ export class UserListService implements OnApplicationShutdown, OnModuleInit { const currentCount = await this.userListMembershipsRepository.countBy({ userListId: list.id, }); - if (currentCount > (await this.roleService.getUserPolicies(me.id)).userEachUserListsLimit) { + if (currentCount >= (await this.roleService.getUserPolicies(me.id)).userEachUserListsLimit) { throw new UserListService.TooManyUsersError(); } diff --git a/packages/backend/src/core/UserRenoteMutingService.ts b/packages/backend/src/core/UserRenoteMutingService.ts new file mode 100644 index 0000000000..bdc5e23f4b --- /dev/null +++ b/packages/backend/src/core/UserRenoteMutingService.ts @@ -0,0 +1,52 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project , Type4ny-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { Inject, Injectable } from '@nestjs/common'; +import { In } from 'typeorm'; +import type { RenoteMutingsRepository } from '@/models/_.js'; +import type { MiRenoteMuting } from '@/models/RenoteMuting.js'; + +import { IdService } from '@/core/IdService.js'; +import type { MiUser } from '@/models/User.js'; +import { DI } from '@/di-symbols.js'; +import { bindThis } from '@/decorators.js'; +import { CacheService } from '@/core/CacheService.js'; + +@Injectable() +export class UserRenoteMutingService { + constructor( + @Inject(DI.renoteMutingsRepository) + private renoteMutingsRepository: RenoteMutingsRepository, + + private idService: IdService, + private cacheService: CacheService, + ) { + } + + @bindThis + public async mute(user: MiUser, target: MiUser, expiresAt: Date | null = null): Promise { + await this.renoteMutingsRepository.insert({ + id: this.idService.gen(), + muterId: user.id, + muteeId: target.id, + }); + + await this.cacheService.renoteMutingsCache.refresh(user.id); + } + + @bindThis + public async unmute(mutings: MiRenoteMuting[]): Promise { + if (mutings.length === 0) return; + + await this.renoteMutingsRepository.delete({ + id: In(mutings.map(m => m.id)), + }); + + const muterIds = [...new Set(mutings.map(m => m.muterId))]; + for (const muterId of muterIds) { + await this.cacheService.renoteMutingsCache.refresh(muterId); + } + } +} diff --git a/packages/backend/src/core/UserSearchService.ts b/packages/backend/src/core/UserSearchService.ts new file mode 100644 index 0000000000..0d03cf6ee0 --- /dev/null +++ b/packages/backend/src/core/UserSearchService.ts @@ -0,0 +1,205 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { Inject, Injectable } from '@nestjs/common'; +import { Brackets, SelectQueryBuilder } from 'typeorm'; +import { DI } from '@/di-symbols.js'; +import { type FollowingsRepository, MiUser, type UsersRepository } from '@/models/_.js'; +import { bindThis } from '@/decorators.js'; +import { sqlLikeEscape } from '@/misc/sql-like-escape.js'; +import type { Config } from '@/config.js'; +import { UserEntityService } from '@/core/entities/UserEntityService.js'; +import { Packed } from '@/misc/json-schema.js'; + +function defaultActiveThreshold() { + return new Date(Date.now() - 1000 * 60 * 60 * 24 * 30); +} + +@Injectable() +export class UserSearchService { + constructor( + @Inject(DI.config) + private config: Config, + @Inject(DI.usersRepository) + private usersRepository: UsersRepository, + @Inject(DI.followingsRepository) + private followingsRepository: FollowingsRepository, + private userEntityService: UserEntityService, + ) { + } + + /** + * ユーザ名とホスト名によるユーザ検索を行う. + * + * - 検索結果には優先順位がつけられており、以下の順序で検索が行われる. + * 1. フォローしているユーザのうち、一定期間以内(※)に更新されたユーザ + * 2. フォローしているユーザのうち、一定期間以内に更新されていないユーザ + * 3. フォローしていないユーザのうち、一定期間以内に更新されたユーザ + * 4. フォローしていないユーザのうち、一定期間以内に更新されていないユーザ + * - ログインしていない場合は、以下の順序で検索が行われる. + * 1. 一定期間以内に更新されたユーザ + * 2. 一定期間以内に更新されていないユーザ + * - それぞれの検索結果はユーザ名の昇順でソートされる. + * - 動作的には先に登場した検索結果の登場位置が優先される(条件的にユーザIDが重複することはないが). + * (1で既にヒットしていた場合、2, 3, 4でヒットしても無視される) + * - ユーザ名とホスト名の検索条件はそれぞれ前方一致で検索される. + * - ユーザ名の検索は大文字小文字を区別しない. + * - ホスト名の検索は大文字小文字を区別しない. + * - 検索結果は最大で {@link opts.limit} 件までとなる. + * + * ※一定期間とは {@link params.activeThreshold} で指定された日時から現在までの期間を指す. + * + * @param params 検索条件. + * @param opts 関数の動作を制御するオプション. + * @param me 検索を実行するユーザの情報. 未ログインの場合は指定しない. + * @see {@link UserSearchService#buildSearchUserQueries} + * @see {@link UserSearchService#buildSearchUserNoLoginQueries} + */ + @bindThis + public async search( + params: { + username?: string | null, + host?: string | null, + activeThreshold?: Date, + }, + opts?: { + limit?: number, + detail?: boolean, + }, + me?: MiUser | null, + ): Promise[]> { + const queries = me ? this.buildSearchUserQueries(me, params) : this.buildSearchUserNoLoginQueries(params); + + let resultSet = new Set(); + const limit = opts?.limit ?? 10; + for (const query of queries) { + const ids = await query + .select('user.id') + .limit(limit - resultSet.size) + .orderBy('user.usernameLower', 'ASC') + .getRawMany<{ user_id: MiUser['id'] }>() + .then(res => res.map(x => x.user_id)); + + resultSet = new Set([...resultSet, ...ids]); + if (resultSet.size >= limit) { + break; + } + } + + return this.userEntityService.packMany<'UserLite' | 'UserDetailed'>( + [...resultSet].slice(0, limit), + me, + { schema: opts?.detail ? 'UserDetailed' : 'UserLite' }, + ); + } + + /** + * ログイン済みユーザによる検索実行時のクエリ一覧を構築する. + * @param me + * @param params + * @private + */ + @bindThis + private buildSearchUserQueries( + me: MiUser, + params: { + username?: string | null, + host?: string | null, + activeThreshold?: Date, + }, + ) { + // デフォルト30日以内に更新されたユーザーをアクティブユーザーとする + const activeThreshold = params.activeThreshold ?? defaultActiveThreshold(); + + const followingUserQuery = this.followingsRepository.createQueryBuilder('following') + .select('following.followeeId') + .where('following.followerId = :followerId', { followerId: me.id }); + + const activeFollowingUsersQuery = this.generateUserQueryBuilder(params) + .andWhere(`user.id IN (${followingUserQuery.getQuery()})`) + .andWhere('user.updatedAt > :activeThreshold', { activeThreshold }); + activeFollowingUsersQuery.setParameters(followingUserQuery.getParameters()); + + const inactiveFollowingUsersQuery = this.generateUserQueryBuilder(params) + .andWhere(`user.id IN (${followingUserQuery.getQuery()})`) + .andWhere(new Brackets(qb => { + qb + .where('user.updatedAt IS NULL') + .orWhere('user.updatedAt <= :activeThreshold', { activeThreshold }); + })); + inactiveFollowingUsersQuery.setParameters(followingUserQuery.getParameters()); + + // 自分自身がヒットするとしたらここ + const activeUserQuery = this.generateUserQueryBuilder(params) + .andWhere(`user.id NOT IN (${followingUserQuery.getQuery()})`) + .andWhere('user.updatedAt > :activeThreshold', { activeThreshold }); + activeUserQuery.setParameters(followingUserQuery.getParameters()); + + const inactiveUserQuery = this.generateUserQueryBuilder(params) + .andWhere(`user.id NOT IN (${followingUserQuery.getQuery()})`) + .andWhere('user.updatedAt <= :activeThreshold', { activeThreshold }); + inactiveUserQuery.setParameters(followingUserQuery.getParameters()); + + return [activeFollowingUsersQuery, inactiveFollowingUsersQuery, activeUserQuery, inactiveUserQuery]; + } + + /** + * ログインしていないユーザによる検索実行時のクエリ一覧を構築する. + * @param params + * @private + */ + @bindThis + private buildSearchUserNoLoginQueries(params: { + username?: string | null, + host?: string | null, + activeThreshold?: Date, + }) { + // デフォルト30日以内に更新されたユーザーをアクティブユーザーとする + const activeThreshold = params.activeThreshold ?? defaultActiveThreshold(); + + const activeUserQuery = this.generateUserQueryBuilder(params) + .andWhere(new Brackets(qb => { + qb + .where('user.updatedAt IS NULL') + .orWhere('user.updatedAt > :activeThreshold', { activeThreshold }); + })); + + const inactiveUserQuery = this.generateUserQueryBuilder(params) + .andWhere('user.updatedAt <= :activeThreshold', { activeThreshold }); + + return [activeUserQuery, inactiveUserQuery]; + } + + /** + * ユーザ検索クエリで共通する抽出条件をあらかじめ設定したクエリビルダを生成する. + * @param params + * @private + */ + @bindThis + private generateUserQueryBuilder(params: { + username?: string | null, + host?: string | null, + }): SelectQueryBuilder { + const userQuery = this.usersRepository.createQueryBuilder('user'); + + if (params.username) { + userQuery.andWhere('user.usernameLower LIKE :username', { username: sqlLikeEscape(params.username.toLowerCase()) + '%' }); + } + + if (params.host) { + if (params.host === this.config.hostname || params.host === '.') { + userQuery.andWhere('user.host IS NULL'); + } else { + userQuery.andWhere('user.host LIKE :host', { + host: sqlLikeEscape(params.host.toLowerCase()) + '%', + }); + } + } + + userQuery.andWhere('user.isSuspended = FALSE'); + + return userQuery; + } +} diff --git a/packages/backend/src/core/UserSuspendService.ts b/packages/backend/src/core/UserSuspendService.ts index d594a223f4..fc5a68c72e 100644 --- a/packages/backend/src/core/UserSuspendService.ts +++ b/packages/backend/src/core/UserSuspendService.ts @@ -3,27 +3,23 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import { Inject, Injectable } from '@nestjs/common'; -import { Not, IsNull } from 'typeorm'; -import type { FollowingsRepository } from '@/models/_.js'; +import { Injectable } from '@nestjs/common'; import type { MiUser } from '@/models/User.js'; -import { QueueService } from '@/core/QueueService.js'; import { GlobalEventService } from '@/core/GlobalEventService.js'; -import { DI } from '@/di-symbols.js'; import { ApRendererService } from '@/core/activitypub/ApRendererService.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { bindThis } from '@/decorators.js'; +import { UserKeypairService } from './UserKeypairService.js'; +import { ApDeliverManagerService } from './activitypub/ApDeliverManagerService.js'; @Injectable() export class UserSuspendService { constructor( - @Inject(DI.followingsRepository) - private followingsRepository: FollowingsRepository, - private userEntityService: UserEntityService, - private queueService: QueueService, private globalEventService: GlobalEventService, private apRendererService: ApRendererService, + private userKeypairService: UserKeypairService, + private apDeliverManagerService: ApDeliverManagerService, ) { } @@ -32,28 +28,12 @@ export class UserSuspendService { this.globalEventService.publishInternalEvent('userChangeSuspendedState', { id: user.id, isSuspended: true }); if (this.userEntityService.isLocalUser(user)) { - // 知り得る全SharedInboxにDelete配信 const content = this.apRendererService.addContext(this.apRendererService.renderDelete(this.userEntityService.genLocalUserUri(user.id), user)); - - const queue: string[] = []; - - const followings = await this.followingsRepository.find({ - where: [ - { followerSharedInbox: Not(IsNull()) }, - { followeeSharedInbox: Not(IsNull()) }, - ], - select: ['followerSharedInbox', 'followeeSharedInbox'], - }); - - const inboxes = followings.map(x => x.followerSharedInbox ?? x.followeeSharedInbox); - - for (const inbox of inboxes) { - if (inbox != null && !queue.includes(inbox)) queue.push(inbox); - } - - for (const inbox of queue) { - this.queueService.deliver(user, content, inbox, true); - } + const manager = this.apDeliverManagerService.createDeliverManager(user, content); + manager.addAllKnowingSharedInboxRecipe(); + // process deliver時にはキーペアが消去されているはずなので、ここで挿入する + const privateKey = await this.userKeypairService.getLocalUserPrivateKeyPem(user.id, 'main'); + manager.execute({ privateKey }); } } @@ -62,28 +42,12 @@ export class UserSuspendService { this.globalEventService.publishInternalEvent('userChangeSuspendedState', { id: user.id, isSuspended: false }); if (this.userEntityService.isLocalUser(user)) { - // 知り得る全SharedInboxにUndo Delete配信 const content = this.apRendererService.addContext(this.apRendererService.renderUndo(this.apRendererService.renderDelete(this.userEntityService.genLocalUserUri(user.id), user), user)); - - const queue: string[] = []; - - const followings = await this.followingsRepository.find({ - where: [ - { followerSharedInbox: Not(IsNull()) }, - { followeeSharedInbox: Not(IsNull()) }, - ], - select: ['followerSharedInbox', 'followeeSharedInbox'], - }); - - const inboxes = followings.map(x => x.followerSharedInbox ?? x.followeeSharedInbox); - - for (const inbox of inboxes) { - if (inbox != null && !queue.includes(inbox)) queue.push(inbox); - } - - for (const inbox of queue) { - this.queueService.deliver(user as any, content, inbox, true); - } + const manager = this.apDeliverManagerService.createDeliverManager(user, content); + manager.addAllKnowingSharedInboxRecipe(); + // process deliver時にはキーペアが消去されているはずなので、ここで挿入する + const privateKey = await this.userKeypairService.getLocalUserPrivateKeyPem(user.id, 'main'); + manager.execute({ privateKey }); } } } diff --git a/packages/backend/src/core/UserWebhookService.ts b/packages/backend/src/core/UserWebhookService.ts new file mode 100644 index 0000000000..e96bfeea95 --- /dev/null +++ b/packages/backend/src/core/UserWebhookService.ts @@ -0,0 +1,99 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { Inject, Injectable } from '@nestjs/common'; +import * as Redis from 'ioredis'; +import type { WebhooksRepository } from '@/models/_.js'; +import type { MiWebhook } from '@/models/Webhook.js'; +import { DI } from '@/di-symbols.js'; +import { bindThis } from '@/decorators.js'; +import { GlobalEvents } from '@/core/GlobalEventService.js'; +import type { OnApplicationShutdown } from '@nestjs/common'; + +@Injectable() +export class UserWebhookService implements OnApplicationShutdown { + private activeWebhooksFetched = false; + private activeWebhooks: MiWebhook[] = []; + + constructor( + @Inject(DI.redisForSub) + private redisForSub: Redis.Redis, + @Inject(DI.webhooksRepository) + private webhooksRepository: WebhooksRepository, + ) { + this.redisForSub.on('message', this.onMessage); + } + + @bindThis + public async getActiveWebhooks() { + if (!this.activeWebhooksFetched) { + this.activeWebhooks = await this.webhooksRepository.findBy({ + active: true, + }); + this.activeWebhooksFetched = true; + } + + return this.activeWebhooks; + } + + @bindThis + private async onMessage(_: string, data: string): Promise { + const obj = JSON.parse(data); + if (obj.channel !== 'internal') { + return; + } + + const { type, body } = obj.message as GlobalEvents['internal']['payload']; + switch (type) { + case 'webhookCreated': { + if (body.active) { + this.activeWebhooks.push({ // TODO: このあたりのデシリアライズ処理は各modelファイル内に関数としてexportしたい + ...body, + latestSentAt: body.latestSentAt ? new Date(body.latestSentAt) : null, + user: null, // joinなカラムは通常取ってこないので + }); + } + break; + } + case 'webhookUpdated': { + if (body.active) { + const i = this.activeWebhooks.findIndex(a => a.id === body.id); + if (i > -1) { + this.activeWebhooks[i] = { // TODO: このあたりのデシリアライズ処理は各modelファイル内に関数としてexportしたい + ...body, + latestSentAt: body.latestSentAt ? new Date(body.latestSentAt) : null, + user: null, // joinなカラムは通常取ってこないので + }; + } else { + this.activeWebhooks.push({ // TODO: このあたりのデシリアライズ処理は各modelファイル内に関数としてexportしたい + ...body, + latestSentAt: body.latestSentAt ? new Date(body.latestSentAt) : null, + user: null, // joinなカラムは通常取ってこないので + }); + } + } else { + this.activeWebhooks = this.activeWebhooks.filter(a => a.id !== body.id); + } + break; + } + case 'webhookDeleted': { + this.activeWebhooks = this.activeWebhooks.filter(a => a.id !== body.id); + break; + } + default: + break; + } + } + + @bindThis + public dispose(): void { + this.redisForSub.off('message', this.onMessage); + } + + @bindThis + public onApplicationShutdown(signal?: string | undefined): void { + this.dispose(); + } +} diff --git a/packages/backend/src/core/WebfingerService.ts b/packages/backend/src/core/WebfingerService.ts index 374536a741..aa1144778c 100644 --- a/packages/backend/src/core/WebfingerService.ts +++ b/packages/backend/src/core/WebfingerService.ts @@ -46,7 +46,7 @@ export class WebfingerService { const m = query.match(mRegex); if (m) { const hostname = m[2]; - const useHttp = process.env.MISSKEY_WEBFINGER_USE_HTTP && process.env.MISSKEY_WEBFINGER_USE_HTTP.toLowerCase() === 'true'; + const useHttp = process.env.MISSKEY_USE_HTTP && process.env.MISSKEY_USE_HTTP.toLowerCase() === 'true'; return `http${useHttp ? '' : 's'}://${hostname}/.well-known/webfinger?${urlQuery({ resource: `acct:${query}` })}`; } diff --git a/packages/backend/src/core/WebhookService.ts b/packages/backend/src/core/WebhookService.ts deleted file mode 100644 index 6be34977b0..0000000000 --- a/packages/backend/src/core/WebhookService.ts +++ /dev/null @@ -1,97 +0,0 @@ -/* - * SPDX-FileCopyrightText: syuilo and misskey-project - * SPDX-License-Identifier: AGPL-3.0-only - */ - -import { Inject, Injectable } from '@nestjs/common'; -import * as Redis from 'ioredis'; -import type { WebhooksRepository } from '@/models/_.js'; -import type { MiWebhook } from '@/models/Webhook.js'; -import { DI } from '@/di-symbols.js'; -import { bindThis } from '@/decorators.js'; -import type { GlobalEvents } from '@/core/GlobalEventService.js'; -import type { OnApplicationShutdown } from '@nestjs/common'; - -@Injectable() -export class WebhookService implements OnApplicationShutdown { - private webhooksFetched = false; - private webhooks: MiWebhook[] = []; - - constructor( - @Inject(DI.redisForSub) - private redisForSub: Redis.Redis, - - @Inject(DI.webhooksRepository) - private webhooksRepository: WebhooksRepository, - ) { - //this.onMessage = this.onMessage.bind(this); - this.redisForSub.on('message', this.onMessage); - } - - @bindThis - public async getActiveWebhooks() { - if (!this.webhooksFetched) { - this.webhooks = await this.webhooksRepository.findBy({ - active: true, - }); - this.webhooksFetched = true; - } - - return this.webhooks; - } - - @bindThis - private async onMessage(_: string, data: string): Promise { - const obj = JSON.parse(data); - - if (obj.channel === 'internal') { - const { type, body } = obj.message as GlobalEvents['internal']['payload']; - switch (type) { - case 'webhookCreated': - if (body.active) { - this.webhooks.push({ // TODO: このあたりのデシリアライズ処理は各modelファイル内に関数としてexportしたい - ...body, - latestSentAt: body.latestSentAt ? new Date(body.latestSentAt) : null, - user: null, // joinなカラムは通常取ってこないので - }); - } - break; - case 'webhookUpdated': - if (body.active) { - const i = this.webhooks.findIndex(a => a.id === body.id); - if (i > -1) { - this.webhooks[i] = { // TODO: このあたりのデシリアライズ処理は各modelファイル内に関数としてexportしたい - ...body, - latestSentAt: body.latestSentAt ? new Date(body.latestSentAt) : null, - user: null, // joinなカラムは通常取ってこないので - }; - } else { - this.webhooks.push({ // TODO: このあたりのデシリアライズ処理は各modelファイル内に関数としてexportしたい - ...body, - latestSentAt: body.latestSentAt ? new Date(body.latestSentAt) : null, - user: null, // joinなカラムは通常取ってこないので - }); - } - } else { - this.webhooks = this.webhooks.filter(a => a.id !== body.id); - } - break; - case 'webhookDeleted': - this.webhooks = this.webhooks.filter(a => a.id !== body.id); - break; - default: - break; - } - } - } - - @bindThis - public dispose(): void { - this.redisForSub.off('message', this.onMessage); - } - - @bindThis - public onApplicationShutdown(signal?: string | undefined): void { - this.dispose(); - } -} diff --git a/packages/backend/src/core/activitypub/ApAudienceService.ts b/packages/backend/src/core/activitypub/ApAudienceService.ts index 0fccc7b950..5a5a76f7d6 100644 --- a/packages/backend/src/core/activitypub/ApAudienceService.ts +++ b/packages/backend/src/core/activitypub/ApAudienceService.ts @@ -8,7 +8,6 @@ import promiseLimit from 'promise-limit'; import type { MiRemoteUser, MiUser } from '@/models/User.js'; import { concat, unique } from '@/misc/prelude/array.js'; import { bindThis } from '@/decorators.js'; -import { isNotNull } from '@/misc/is-not-null.js'; import { getApIds } from './type.js'; import { ApPersonService } from './models/ApPersonService.js'; import type { ApObject } from './type.js'; @@ -41,7 +40,7 @@ export class ApAudienceService { const limit = promiseLimit(2); const mentionedUsers = (await Promise.all( others.map(id => limit(() => this.apPersonService.resolvePerson(id, resolver).catch(() => null))), - )).filter(isNotNull); + )).filter(x => x != null); if (toGroups.public.length > 0) { return { diff --git a/packages/backend/src/core/activitypub/ApDbResolverService.ts b/packages/backend/src/core/activitypub/ApDbResolverService.ts index f6b70ead44..973394683f 100644 --- a/packages/backend/src/core/activitypub/ApDbResolverService.ts +++ b/packages/backend/src/core/activitypub/ApDbResolverService.ts @@ -5,7 +5,7 @@ import { Inject, Injectable, OnApplicationShutdown } from '@nestjs/common'; import { DI } from '@/di-symbols.js'; -import type { NotesRepository, UserPublickeysRepository, UsersRepository } from '@/models/_.js'; +import type { MiUser, NotesRepository, UserPublickeysRepository, UsersRepository } from '@/models/_.js'; import type { Config } from '@/config.js'; import { MemoryKVCache } from '@/misc/cache.js'; import type { MiUserPublickey } from '@/models/UserPublickey.js'; @@ -13,9 +13,12 @@ import { CacheService } from '@/core/CacheService.js'; import type { MiNote } from '@/models/Note.js'; import { bindThis } from '@/decorators.js'; import { MiLocalUser, MiRemoteUser } from '@/models/User.js'; +import Logger from '@/logger.js'; import { getApId } from './type.js'; import { ApPersonService } from './models/ApPersonService.js'; +import { ApLoggerService } from './ApLoggerService.js'; import type { IObject } from './type.js'; +import { UtilityService } from '../UtilityService.js'; export type UriParseResult = { /** wether the URI was generated by us */ @@ -35,8 +38,8 @@ export type UriParseResult = { @Injectable() export class ApDbResolverService implements OnApplicationShutdown { - private publicKeyCache: MemoryKVCache; - private publicKeyByUserIdCache: MemoryKVCache; + private publicKeyByUserIdCache: MemoryKVCache; + private logger: Logger; constructor( @Inject(DI.config) @@ -53,9 +56,17 @@ export class ApDbResolverService implements OnApplicationShutdown { private cacheService: CacheService, private apPersonService: ApPersonService, + private apLoggerService: ApLoggerService, + private utilityService: UtilityService, ) { - this.publicKeyCache = new MemoryKVCache(Infinity); - this.publicKeyByUserIdCache = new MemoryKVCache(Infinity); + this.publicKeyByUserIdCache = new MemoryKVCache(Infinity); + this.logger = this.apLoggerService.logger.createSubLogger('db-resolver'); + } + + private punyHost(url: string): string { + const urlObj = new URL(url); + const host = `${this.utilityService.toPuny(urlObj.hostname)}${urlObj.port.length > 0 ? ':' + urlObj.port : ''}`; + return host; } @bindThis @@ -116,62 +127,141 @@ export class ApDbResolverService implements OnApplicationShutdown { } } - /** - * AP KeyId => Misskey User and Key - */ @bindThis - public async getAuthUserFromKeyId(keyId: string): Promise<{ - user: MiRemoteUser; - key: MiUserPublickey; - } | null> { - const key = await this.publicKeyCache.fetch(keyId, async () => { - const key = await this.userPublickeysRepository.findOneBy({ - keyId, - }); - - if (key == null) return null; - - return key; - }, key => key != null); - - if (key == null) return null; - - const user = await this.cacheService.findUserById(key.userId).catch(() => null) as MiRemoteUser | null; - if (user == null) return null; - if (user.isDeleted) return null; - - return { - user, - key, - }; + private async refreshAndFindKey(userId: MiUser['id'], keyId: string): Promise { + this.refreshCacheByUserId(userId); + const keys = await this.getPublicKeyByUserId(userId); + if (keys == null || !Array.isArray(keys) || keys.length === 0) { + this.logger.warn(`No key found (refreshAndFindKey) userId=${userId} keyId=${keyId} keys=${JSON.stringify(keys)}`); + return null; + } + const exactKey = keys.find(x => x.keyId === keyId); + if (exactKey) return exactKey; + this.logger.warn(`No exact key found (refreshAndFindKey) userId=${userId} keyId=${keyId} keys=${JSON.stringify(keys)}`); + return null; } /** * AP Actor id => Misskey User and Key + * @param uri AP Actor id + * @param keyId Key id to find. If not specified, main key will be selected. + * @returns + * 1. `null` if the user and key host do not match + * 2. `{ user: null, key: null }` if the user is not found + * 3. `{ user: MiRemoteUser, key: null }` if key is not found + * 4. `{ user: MiRemoteUser, key: MiUserPublickey }` if both are found */ @bindThis - public async getAuthUserFromApId(uri: string): Promise<{ + public async getAuthUserFromApId(uri: string, keyId?: string): Promise<{ user: MiRemoteUser; key: MiUserPublickey | null; - } | null> { - const user = await this.apPersonService.resolvePerson(uri) as MiRemoteUser; - if (user.isDeleted) return null; + } | { + user: null; + key: null; + } | + null> { + if (keyId) { + if (this.punyHost(uri) !== this.punyHost(keyId)) { + /** + * keyIdはURL形式かつkeyIdのホストはuriのホストと一致するはず + * (ApPersonService.validateActorに由来) + * + * ただ、Mastodonはリプライ関連で他人のトゥートをHTTP Signature署名して送ってくることがある + * そのような署名は有効性に疑問があるので無視することにする + * ここではuriとkeyIdのホストが一致しない場合は無視する + * ハッシュをなくしたkeyIdとuriの同一性を比べてみてもいいが、`uri#*-key`というkeyIdを設定するのが + * 決まりごとというわけでもないため幅を持たせることにする + * + * + * The keyId should be in URL format and its host should match the host of the uri + * (derived from ApPersonService.validateActor) + * + * However, Mastodon sometimes sends toots from other users with HTTP Signature signing for reply-related purposes + * Such signatures are of questionable validity, so we choose to ignore them + * Here, we ignore cases where the hosts of uri and keyId do not match + * We could also compare the equality of keyId without the hash and uri, but since setting a keyId like `uri#*-key` + * is not a strict rule, we decide to allow for some flexibility + */ + this.logger.warn(`actor uri and keyId are not matched uri=${uri} keyId=${keyId}`); + return null; + } + } - const key = await this.publicKeyByUserIdCache.fetch( - user.id, - () => this.userPublickeysRepository.findOneBy({ userId: user.id }), + const user = await this.apPersonService.resolvePerson(uri, undefined, true) as MiRemoteUser; + if (user.isDeleted) return { user: null, key: null }; + + const keys = await this.getPublicKeyByUserId(user.id); + + if (keys == null || !Array.isArray(keys) || keys.length === 0) { + this.logger.warn(`No key found uri=${uri} userId=${user.id} keys=${JSON.stringify(keys)}`); + return { user, key: null }; + } + + if (!keyId) { + // Choose the main-like + const mainKey = keys.find(x => { + try { + const url = new URL(x.keyId); + const path = url.pathname.split('/').pop()?.toLowerCase(); + if (url.hash) { + if (url.hash.toLowerCase().includes('main')) { + return true; + } + } else if (path?.includes('main') || path === 'publickey') { + return true; + } + } catch { /* noop */ } + + return false; + }); + return { user, key: mainKey ?? keys[0] }; + } + + const exactKey = keys.find(x => x.keyId === keyId); + if (exactKey) return { user, key: exactKey }; + + /** + * keyIdで見つからない場合、まずはキャッシュを更新して再取得 + * If not found with keyId, update cache and reacquire + */ + const cacheRaw = this.publicKeyByUserIdCache.cache.get(user.id); + if (cacheRaw && cacheRaw.date > Date.now() - 1000 * 60 * 12) { + const exactKey = await this.refreshAndFindKey(user.id, keyId); + if (exactKey) return { user, key: exactKey }; + } + + /** + * lastFetchedAtでの更新制限を弱めて再取得 + * Reacquisition with weakened update limit at lastFetchedAt + */ + if (user.lastFetchedAt == null || user.lastFetchedAt < new Date(Date.now() - 1000 * 60 * 12)) { + this.logger.info(`Fetching user to find public key uri=${uri} userId=${user.id} keyId=${keyId}`); + const renewed = await this.apPersonService.fetchPersonWithRenewal(uri, 0); + if (renewed == null || renewed.isDeleted) return null; + + return { user, key: await this.refreshAndFindKey(user.id, keyId) }; + } + + this.logger.warn(`No key found uri=${uri} userId=${user.id} keyId=${keyId}`); + return { user, key: null }; + } + + @bindThis + public async getPublicKeyByUserId(userId: MiUser['id']): Promise { + return await this.publicKeyByUserIdCache.fetch( + userId, + () => this.userPublickeysRepository.find({ where: { userId } }), v => v != null, ); + } - return { - user, - key, - }; + @bindThis + public refreshCacheByUserId(userId: MiUser['id']): void { + this.publicKeyByUserIdCache.delete(userId); } @bindThis public dispose(): void { - this.publicKeyCache.dispose(); this.publicKeyByUserIdCache.dispose(); } diff --git a/packages/backend/src/core/activitypub/ApDeliverManagerService.ts b/packages/backend/src/core/activitypub/ApDeliverManagerService.ts index 5d07cd8e8f..db3302e6ff 100644 --- a/packages/backend/src/core/activitypub/ApDeliverManagerService.ts +++ b/packages/backend/src/core/activitypub/ApDeliverManagerService.ts @@ -9,10 +9,14 @@ import { DI } from '@/di-symbols.js'; import type { FollowingsRepository } from '@/models/_.js'; import type { MiLocalUser, MiRemoteUser, MiUser } from '@/models/User.js'; import { QueueService } from '@/core/QueueService.js'; -import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { bindThis } from '@/decorators.js'; import type { IActivity } from '@/core/activitypub/type.js'; import { ThinUser } from '@/queue/types.js'; +import { AccountUpdateService } from '@/core/AccountUpdateService.js'; +import type Logger from '@/logger.js'; +import { UserKeypairService } from '../UserKeypairService.js'; +import { ApLoggerService } from './ApLoggerService.js'; +import type { PrivateKeyWithPem } from '@misskey-dev/node-http-message-signatures'; interface IRecipe { type: string; @@ -27,12 +31,19 @@ interface IDirectRecipe extends IRecipe { to: MiRemoteUser; } +interface IAllKnowingSharedInboxRecipe extends IRecipe { + type: 'AllKnowingSharedInbox'; +} + const isFollowers = (recipe: IRecipe): recipe is IFollowersRecipe => recipe.type === 'Followers'; const isDirect = (recipe: IRecipe): recipe is IDirectRecipe => recipe.type === 'Direct'; +const isAllKnowingSharedInbox = (recipe: IRecipe): recipe is IAllKnowingSharedInboxRecipe => + recipe.type === 'AllKnowingSharedInbox'; + class DeliverManager { private actor: ThinUser; private activity: IActivity | null; @@ -40,16 +51,18 @@ class DeliverManager { /** * Constructor - * @param userEntityService + * @param userKeypairService * @param followingsRepository * @param queueService * @param actor Actor * @param activity Activity to deliver */ constructor( - private userEntityService: UserEntityService, + private userKeypairService: UserKeypairService, private followingsRepository: FollowingsRepository, private queueService: QueueService, + private accountUpdateService: AccountUpdateService, + private logger: Logger, actor: { id: MiUser['id']; host: null; }, activity: IActivity | null, @@ -91,6 +104,18 @@ class DeliverManager { this.addRecipe(recipe); } + /** + * Add recipe for all-knowing shared inbox deliver + */ + @bindThis + public addAllKnowingSharedInboxRecipe(): void { + const deliver: IAllKnowingSharedInboxRecipe = { + type: 'AllKnowingSharedInbox', + }; + + this.addRecipe(deliver); + } + /** * Add recipe * @param recipe Recipe @@ -104,11 +129,44 @@ class DeliverManager { * Execute delivers */ @bindThis - public async execute(): Promise { + public async execute(opts?: { privateKey?: PrivateKeyWithPem }): Promise { + //#region MIGRATION + if (!opts?.privateKey) { + /** + * ed25519の署名がなければ追加する + */ + const created = await this.userKeypairService.refreshAndPrepareEd25519KeyPair(this.actor.id); + if (created) { + // createdが存在するということは新規作成されたということなので、フォロワーに配信する + this.logger.info(`ed25519 key pair created for user ${this.actor.id} and publishing to followers`); + // リモートに配信 + const keyPair = await this.userKeypairService.getLocalUserPrivateKeyPem(created, 'main'); + await this.accountUpdateService.publishToFollowers(this.actor.id, keyPair); + } + } + //#endregion + + //#region collect inboxes by recipes // The value flags whether it is shared or not. // key: inbox URL, value: whether it is sharedInbox const inboxes = new Map(); + if (this.recipes.some(r => isAllKnowingSharedInbox(r))) { + // all-knowing shared inbox + const followings = await this.followingsRepository.find({ + where: [ + { followerSharedInbox: Not(IsNull()) }, + { followeeSharedInbox: Not(IsNull()) }, + ], + select: ['followerSharedInbox', 'followeeSharedInbox'], + }); + + for (const following of followings) { + if (following.followeeSharedInbox) inboxes.set(following.followeeSharedInbox, true); + if (following.followerSharedInbox) inboxes.set(following.followerSharedInbox, true); + } + } + // build inbox list // Process follower recipes first to avoid duplication when processing direct recipes later. if (this.recipes.some(r => isFollowers(r))) { @@ -142,39 +200,49 @@ class DeliverManager { inboxes.set(recipe.to.inbox, false); } + //#endregion // deliver - await this.queueService.deliverMany(this.actor, this.activity, inboxes); + await this.queueService.deliverMany(this.actor, this.activity, inboxes, opts?.privateKey); + this.logger.info(`Deliver queues dispatched: inboxes=${inboxes.size} actorId=${this.actor.id} activityId=${this.activity?.id}`); } } @Injectable() export class ApDeliverManagerService { + private logger: Logger; + constructor( @Inject(DI.followingsRepository) private followingsRepository: FollowingsRepository, - private userEntityService: UserEntityService, + private userKeypairService: UserKeypairService, private queueService: QueueService, + private accountUpdateService: AccountUpdateService, + private apLoggerService: ApLoggerService, ) { + this.logger = this.apLoggerService.logger.createSubLogger('deliver-manager'); } /** * Deliver activity to followers * @param actor * @param activity Activity + * @param forceMainKey Force to use main (rsa) key */ @bindThis - public async deliverToFollowers(actor: { id: MiLocalUser['id']; host: null; }, activity: IActivity): Promise { + public async deliverToFollowers(actor: { id: MiLocalUser['id']; host: null; }, activity: IActivity, privateKey?: PrivateKeyWithPem): Promise { const manager = new DeliverManager( - this.userEntityService, + this.userKeypairService, this.followingsRepository, this.queueService, + this.accountUpdateService, + this.logger, actor, activity, ); manager.addFollowersRecipe(); - await manager.execute(); + await manager.execute({ privateKey }); } /** @@ -186,9 +254,11 @@ export class ApDeliverManagerService { @bindThis public async deliverToUser(actor: { id: MiLocalUser['id']; host: null; }, activity: IActivity, to: MiRemoteUser): Promise { const manager = new DeliverManager( - this.userEntityService, + this.userKeypairService, this.followingsRepository, this.queueService, + this.accountUpdateService, + this.logger, actor, activity, ); @@ -199,10 +269,11 @@ export class ApDeliverManagerService { @bindThis public createDeliverManager(actor: { id: MiUser['id']; host: null; }, activity: IActivity | null): DeliverManager { return new DeliverManager( - this.userEntityService, + this.userKeypairService, this.followingsRepository, this.queueService, - + this.accountUpdateService, + this.logger, actor, activity, ); diff --git a/packages/backend/src/core/activitypub/ApInboxService.ts b/packages/backend/src/core/activitypub/ApInboxService.ts index d0d206760c..1bef9fe071 100644 --- a/packages/backend/src/core/activitypub/ApInboxService.ts +++ b/packages/backend/src/core/activitypub/ApInboxService.ts @@ -27,8 +27,8 @@ import { QueueService } from '@/core/QueueService.js'; import type { UsersRepository, NotesRepository, FollowingsRepository, AbuseUserReportsRepository, FollowRequestsRepository } from '@/models/_.js'; import { bindThis } from '@/decorators.js'; import type { MiRemoteUser } from '@/models/User.js'; -import { isNotNull } from '@/misc/is-not-null.js'; import { GlobalEventService } from '@/core/GlobalEventService.js'; +import { AbuseReportService } from '@/core/AbuseReportService.js'; import { getApHrefNullable, getApId, getApIds, getApType, isAccept, isActor, isAdd, isAnnounce, isBlock, isCollection, isCollectionOrOrderedCollection, isCreate, isDelete, isFlag, isFollow, isLike, isMove, isPost, isReject, isRemove, isTombstone, isUndo, isUpdate, validActor, validPost } from './type.js'; import { ApNoteService } from './models/ApNoteService.js'; import { ApLoggerService } from './ApLoggerService.js'; @@ -57,9 +57,6 @@ export class ApInboxService { @Inject(DI.followingsRepository) private followingsRepository: FollowingsRepository, - @Inject(DI.abuseUserReportsRepository) - private abuseUserReportsRepository: AbuseUserReportsRepository, - @Inject(DI.followRequestsRepository) private followRequestsRepository: FollowRequestsRepository, @@ -68,6 +65,7 @@ export class ApInboxService { private utilityService: UtilityService, private idService: IdService, private metaService: MetaService, + private abuseReportService: AbuseReportService, private userFollowingService: UserFollowingService, private apAudienceService: ApAudienceService, private reactionService: ReactionService, @@ -116,15 +114,8 @@ export class ApInboxService { result = await this.performOneActivity(actor, activity); } - // ついでにリモートユーザーの情報が古かったら更新しておく - if (actor.uri) { - if (actor.lastFetchedAt == null || Date.now() - actor.lastFetchedAt.getTime() > 1000 * 60 * 60 * 24) { - setImmediate(() => { - this.apPersonService.updatePerson(actor.uri); - }); - } - } - return result; + // ついでにリモートユーザーの情報が古かったら更新しておく? + // → No, この関数が呼び出される前に署名検証で更新されているはず } @bindThis @@ -539,20 +530,19 @@ export class ApInboxService { const userIds = uris .filter(uri => uri.startsWith(this.config.url + '/users/')) .map(uri => uri.split('/').at(-1)) - .filter(isNotNull); + .filter(x => x != null); const users = await this.usersRepository.findBy({ id: In(userIds), }); if (users.length < 1) return 'skip'; - await this.abuseUserReportsRepository.insert({ - id: this.idService.gen(), + await this.abuseReportService.report([{ targetUserId: users[0].id, targetUserHost: users[0].host, reporterId: actor.id, reporterHost: actor.host, comment: `${activity.content}\n${JSON.stringify(uris, null, 2)}`, - }); + }]); return 'ok'; } diff --git a/packages/backend/src/core/activitypub/ApMfmService.ts b/packages/backend/src/core/activitypub/ApMfmService.ts index ab75b9abbd..4036d2794a 100644 --- a/packages/backend/src/core/activitypub/ApMfmService.ts +++ b/packages/backend/src/core/activitypub/ApMfmService.ts @@ -25,7 +25,7 @@ export class ApMfmService { } @bindThis - public getNoteHtml(note: MiNote, apAppend?: string) { + public getNoteHtml(note: Pick, apAppend?: string) { let noMisskeyContent = false; const srcMfm = (note.text ?? '') + (apAppend ?? ''); diff --git a/packages/backend/src/core/activitypub/ApRendererService.ts b/packages/backend/src/core/activitypub/ApRendererService.ts index 4fc724b548..5d7419f934 100644 --- a/packages/backend/src/core/activitypub/ApRendererService.ts +++ b/packages/backend/src/core/activitypub/ApRendererService.ts @@ -22,16 +22,15 @@ import { UserKeypairService } from '@/core/UserKeypairService.js'; import { MfmService } from '@/core/MfmService.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { DriveFileEntityService } from '@/core/entities/DriveFileEntityService.js'; -import type { MiUserKeypair } from '@/models/UserKeypair.js'; import type { UsersRepository, UserProfilesRepository, NotesRepository, DriveFilesRepository, PollsRepository } from '@/models/_.js'; import { bindThis } from '@/decorators.js'; import { CustomEmojiService } from '@/core/CustomEmojiService.js'; -import { isNotNull } from '@/misc/is-not-null.js'; import { IdService } from '@/core/IdService.js'; import { JsonLdService } from './JsonLdService.js'; import { ApMfmService } from './ApMfmService.js'; import { CONTEXT } from './misc/contexts.js'; import type { IAccept, IActivity, IAdd, IAnnounce, IApDocument, IApEmoji, IApHashtag, IApImage, IApMention, IBlock, ICreate, IDelete, IFlag, IFollow, IKey, ILike, IMove, IObject, IPost, IQuestion, IReject, IRemove, ITombstone, IUndo, IUpdate } from './type.js'; +import type { PrivateKeyWithPem } from '@misskey-dev/node-http-message-signatures'; @Injectable() export class ApRendererService { @@ -252,15 +251,15 @@ export class ApRendererService { } @bindThis - public renderKey(user: MiLocalUser, key: MiUserKeypair, postfix?: string): IKey { + public renderKey(user: MiLocalUser, publicKey: string, postfix?: string): IKey { return { - id: `${this.config.url}/users/${user.id}${postfix ?? '/publickey'}`, + id: `${this.userEntityService.genLocalUserUri(user.id)}${postfix ?? '/publickey'}`, type: 'Key', owner: this.userEntityService.genLocalUserUri(user.id), - publicKeyPem: createPublicKey(key.publicKey).export({ + publicKeyPem: createPublicKey(publicKey).export({ type: 'spki', format: 'pem', - }), + }) as string, }; } @@ -317,7 +316,7 @@ export class ApRendererService { const getPromisedFiles = async (ids: string[]): Promise => { if (ids.length === 0) return []; const items = await this.driveFilesRepository.findBy({ id: In(ids) }); - return ids.map(id => items.find(item => item.id === id)).filter(isNotNull); + return ids.map(id => items.find(item => item.id === id)).filter(x => x != null); }; let inReplyTo; @@ -500,7 +499,10 @@ export class ApRendererService { tag, manuallyApprovesFollowers: user.isLocked, discoverable: user.isExplorable, - publicKey: this.renderKey(user, keypair, '#main-key'), + publicKey: this.renderKey(user, keypair.publicKey, '#main-key'), + additionalPublicKeys: [ + ...(keypair.ed25519PublicKey ? [this.renderKey(user, keypair.ed25519PublicKey, '#ed25519-key')] : []), + ], isCat: user.isCat, attachment: attachment.length ? attachment : undefined, }; @@ -623,12 +625,10 @@ export class ApRendererService { } @bindThis - public async attachLdSignature(activity: any, user: { id: MiUser['id']; host: null; }): Promise { - const keypair = await this.userKeypairService.getUserKeypair(user.id); - + public async attachLdSignature(activity: any, key: PrivateKeyWithPem): Promise { const jsonLd = this.jsonLdService.use(); jsonLd.debug = false; - activity = await jsonLd.signRsaSignature2017(activity, keypair.privateKey, `${this.config.url}/users/${user.id}#main-key`); + activity = await jsonLd.signRsaSignature2017(activity, key.privateKeyPem, key.keyId); return activity; } @@ -686,7 +686,7 @@ export class ApRendererService { if (names.length === 0) return []; const allEmojis = await this.customEmojiService.localEmojisCache.fetch(); - const emojis = names.map(name => allEmojis.get(name)).filter(isNotNull); + const emojis = names.map(name => allEmojis.get(name)).filter(x => x != null); return emojis; } diff --git a/packages/backend/src/core/activitypub/ApRequestService.ts b/packages/backend/src/core/activitypub/ApRequestService.ts index 93ac8ce9a7..0cae91316b 100644 --- a/packages/backend/src/core/activitypub/ApRequestService.ts +++ b/packages/backend/src/core/activitypub/ApRequestService.ts @@ -3,9 +3,9 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import * as crypto from 'node:crypto'; import { URL } from 'node:url'; import { Inject, Injectable } from '@nestjs/common'; +import { genRFC3230DigestHeader, signAsDraftToRequest } from '@misskey-dev/node-http-message-signatures'; import { DI } from '@/di-symbols.js'; import type { Config } from '@/config.js'; import type { MiUser } from '@/models/User.js'; @@ -15,122 +15,61 @@ import { LoggerService } from '@/core/LoggerService.js'; import { bindThis } from '@/decorators.js'; import type Logger from '@/logger.js'; import { validateContentTypeSetAsActivityPub } from '@/core/activitypub/misc/validator.js'; +import type { PrivateKeyWithPem, PrivateKey } from '@misskey-dev/node-http-message-signatures'; -type Request = { - url: string; - method: string; - headers: Record; -}; +export async function createSignedPost(args: { level: string; key: PrivateKey; url: string; body: string; digest?: string, additionalHeaders: Record }) { + const u = new URL(args.url); + const request = { + url: u.href, + method: 'POST', + headers: { + 'Date': new Date().toUTCString(), + 'Host': u.host, + 'Content-Type': 'application/activity+json', + ...args.additionalHeaders, + } as Record, + }; -type Signed = { - request: Request; - signingString: string; - signature: string; - signatureHeader: string; -}; + // TODO: httpMessageSignaturesImplementationLevelによって新規格で通信をするようにする + const digestHeader = args.digest ?? await genRFC3230DigestHeader(args.body, 'SHA-256'); + request.headers['Digest'] = digestHeader; -type PrivateKey = { - privateKeyPem: string; - keyId: string; -}; + const result = await signAsDraftToRequest( + request, + args.key, + ['(request-target)', 'date', 'host', 'digest'], + ); -export class ApRequestCreator { - static createSignedPost(args: { key: PrivateKey, url: string, body: string, digest?: string, additionalHeaders: Record }): Signed { - const u = new URL(args.url); - const digestHeader = args.digest ?? this.createDigest(args.body); + return { + request, + ...result, + }; +} - const request: Request = { - url: u.href, - method: 'POST', - headers: this.#objectAssignWithLcKey({ - 'Date': new Date().toUTCString(), - 'Host': u.host, - 'Content-Type': 'application/activity+json', - 'Digest': digestHeader, - }, args.additionalHeaders), - }; +export async function createSignedGet(args: { level: string; key: PrivateKey; url: string; additionalHeaders: Record }) { + const u = new URL(args.url); + const request = { + url: u.href, + method: 'GET', + headers: { + 'Accept': 'application/activity+json, application/ld+json; profile="https://www.w3.org/ns/activitystreams"', + 'Date': new Date().toUTCString(), + 'Host': new URL(args.url).host, + ...args.additionalHeaders, + } as Record, + }; - const result = this.#signToRequest(request, args.key, ['(request-target)', 'date', 'host', 'digest']); + // TODO: httpMessageSignaturesImplementationLevelによって新規格で通信をするようにする + const result = await signAsDraftToRequest( + request, + args.key, + ['(request-target)', 'date', 'host', 'accept'], + ); - return { - request, - signingString: result.signingString, - signature: result.signature, - signatureHeader: result.signatureHeader, - }; - } - - static createDigest(body: string) { - return `SHA-256=${crypto.createHash('sha256').update(body).digest('base64')}`; - } - - static createSignedGet(args: { key: PrivateKey, url: string, additionalHeaders: Record }): Signed { - const u = new URL(args.url); - - const request: Request = { - url: u.href, - method: 'GET', - headers: this.#objectAssignWithLcKey({ - 'Accept': 'application/activity+json, application/ld+json; profile="https://www.w3.org/ns/activitystreams"', - 'Date': new Date().toUTCString(), - 'Host': new URL(args.url).host, - }, args.additionalHeaders), - }; - - const result = this.#signToRequest(request, args.key, ['(request-target)', 'date', 'host', 'accept']); - - return { - request, - signingString: result.signingString, - signature: result.signature, - signatureHeader: result.signatureHeader, - }; - } - - static #signToRequest(request: Request, key: PrivateKey, includeHeaders: string[]): Signed { - const signingString = this.#genSigningString(request, includeHeaders); - const signature = crypto.sign('sha256', Buffer.from(signingString), key.privateKeyPem).toString('base64'); - const signatureHeader = `keyId="${key.keyId}",algorithm="rsa-sha256",headers="${includeHeaders.join(' ')}",signature="${signature}"`; - - request.headers = this.#objectAssignWithLcKey(request.headers, { - Signature: signatureHeader, - }); - // node-fetch will generate this for us. if we keep 'Host', it won't change with redirects! - delete request.headers['host']; - - return { - request, - signingString, - signature, - signatureHeader, - }; - } - - static #genSigningString(request: Request, includeHeaders: string[]): string { - request.headers = this.#lcObjectKey(request.headers); - - const results: string[] = []; - - for (const key of includeHeaders.map(x => x.toLowerCase())) { - if (key === '(request-target)') { - results.push(`(request-target): ${request.method.toLowerCase()} ${new URL(request.url).pathname}`); - } else { - results.push(`${key}: ${request.headers[key]}`); - } - } - - return results.join('\n'); - } - - static #lcObjectKey(src: Record): Record { - const dst: Record = {}; - for (const key of Object.keys(src).filter(x => x !== '__proto__' && typeof src[x] === 'string')) dst[key.toLowerCase()] = src[key]; - return dst; - } - - static #objectAssignWithLcKey(a: Record, b: Record): Record { - return Object.assign(this.#lcObjectKey(a), this.#lcObjectKey(b)); - } + return { + request, + ...result, + }; } @Injectable() @@ -150,21 +89,28 @@ export class ApRequestService { } @bindThis - public async signedPost(user: { id: MiUser['id'] }, url: string, object: unknown, digest?: string): Promise { + public async signedPost(user: { id: MiUser['id'] }, url: string, object: unknown, level: string, digest?: string, key?: PrivateKeyWithPem): Promise { const body = typeof object === 'string' ? object : JSON.stringify(object); - - const keypair = await this.userKeypairService.getUserKeypair(user.id); - - const req = ApRequestCreator.createSignedPost({ - key: { - privateKeyPem: keypair.privateKey, - keyId: `${this.config.url}/users/${user.id}#main-key`, - }, + const keyFetched = await this.userKeypairService.getLocalUserPrivateKey(key ?? user.id, level); + const req = await createSignedPost({ + level, + key: keyFetched, url, body, - digest, additionalHeaders: { + 'User-Agent': this.config.userAgent, }, + digest, + }); + + // node-fetch will generate this for us. if we keep 'Host', it won't change with redirects! + delete req.request.headers['Host']; + + this.logger.debug('create signed post', { + version: 'draft', + level, + url, + keyId: keyFetched.keyId, }); await this.httpRequestService.send(url, { @@ -180,19 +126,27 @@ export class ApRequestService { * @param url URL to fetch */ @bindThis - public async signedGet(url: string, user: { id: MiUser['id'] }): Promise { - const keypair = await this.userKeypairService.getUserKeypair(user.id); - - const req = ApRequestCreator.createSignedGet({ - key: { - privateKeyPem: keypair.privateKey, - keyId: `${this.config.url}/users/${user.id}#main-key`, - }, + public async signedGet(url: string, user: { id: MiUser['id'] }, level: string): Promise { + const key = await this.userKeypairService.getLocalUserPrivateKey(user.id, level); + const req = await createSignedGet({ + level, + key, url, additionalHeaders: { + 'User-Agent': this.config.userAgent, }, }); + // node-fetch will generate this for us. if we keep 'Host', it won't change with redirects! + delete req.request.headers['Host']; + + this.logger.debug('create signed get', { + version: 'draft', + level, + url, + keyId: key.keyId, + }); + const res = await this.httpRequestService.send(url, { method: req.request.method, headers: req.request.headers, diff --git a/packages/backend/src/core/activitypub/ApResolverService.ts b/packages/backend/src/core/activitypub/ApResolverService.ts index bb3c40f093..727ff6f956 100644 --- a/packages/backend/src/core/activitypub/ApResolverService.ts +++ b/packages/backend/src/core/activitypub/ApResolverService.ts @@ -16,6 +16,7 @@ import { UtilityService } from '@/core/UtilityService.js'; import { bindThis } from '@/decorators.js'; import { LoggerService } from '@/core/LoggerService.js'; import type Logger from '@/logger.js'; +import { FederatedInstanceService } from '@/core/FederatedInstanceService.js'; import { isCollectionOrOrderedCollection } from './type.js'; import { ApDbResolverService } from './ApDbResolverService.js'; import { ApRendererService } from './ApRendererService.js'; @@ -41,6 +42,7 @@ export class Resolver { private httpRequestService: HttpRequestService, private apRendererService: ApRendererService, private apDbResolverService: ApDbResolverService, + private federatedInstanceService: FederatedInstanceService, private loggerService: LoggerService, private recursionLimit = 100, ) { @@ -103,8 +105,10 @@ export class Resolver { this.user = await this.instanceActorService.getInstanceActor(); } + const server = await this.federatedInstanceService.fetch(host); + const object = (this.user - ? await this.apRequestService.signedGet(value, this.user) as IObject + ? await this.apRequestService.signedGet(value, this.user, server.httpMessageSignaturesImplementationLevel) as IObject : await this.httpRequestService.getActivityJson(value)) as IObject; if ( @@ -200,6 +204,7 @@ export class ApResolverService { private httpRequestService: HttpRequestService, private apRendererService: ApRendererService, private apDbResolverService: ApDbResolverService, + private federatedInstanceService: FederatedInstanceService, private loggerService: LoggerService, ) { } @@ -220,6 +225,7 @@ export class ApResolverService { this.httpRequestService, this.apRendererService, this.apDbResolverService, + this.federatedInstanceService, this.loggerService, ); } diff --git a/packages/backend/src/core/activitypub/misc/contexts.ts b/packages/backend/src/core/activitypub/misc/contexts.ts index feb8c42c56..fc4e3e3bef 100644 --- a/packages/backend/src/core/activitypub/misc/contexts.ts +++ b/packages/backend/src/core/activitypub/misc/contexts.ts @@ -134,6 +134,7 @@ const security_v1 = { 'privateKey': { '@id': 'sec:privateKey', '@type': '@id' }, 'privateKeyPem': 'sec:privateKeyPem', 'publicKey': { '@id': 'sec:publicKey', '@type': '@id' }, + 'additionalPublicKeys': { '@id': 'sec:publicKey', '@type': '@id' }, 'publicKeyBase58': 'sec:publicKeyBase58', 'publicKeyPem': 'sec:publicKeyPem', 'publicKeyWif': 'sec:publicKeyWif', diff --git a/packages/backend/src/core/activitypub/models/ApMentionService.ts b/packages/backend/src/core/activitypub/models/ApMentionService.ts index 0ced7e88af..2cd151fa04 100644 --- a/packages/backend/src/core/activitypub/models/ApMentionService.ts +++ b/packages/backend/src/core/activitypub/models/ApMentionService.ts @@ -8,7 +8,6 @@ import promiseLimit from 'promise-limit'; import type { MiUser } from '@/models/_.js'; import { toArray, unique } from '@/misc/prelude/array.js'; import { bindThis } from '@/decorators.js'; -import { isNotNull } from '@/misc/is-not-null.js'; import { isMention } from '../type.js'; import { Resolver } from '../ApResolverService.js'; import { ApPersonService } from './ApPersonService.js'; @@ -28,7 +27,7 @@ export class ApMentionService { const limit = promiseLimit(2); const mentionedUsers = (await Promise.all( hrefs.map(x => limit(() => this.apPersonService.resolvePerson(x, resolver).catch(() => null))), - )).filter(isNotNull); + )).filter(x => x != null); return mentionedUsers; } diff --git a/packages/backend/src/core/activitypub/models/ApNoteService.ts b/packages/backend/src/core/activitypub/models/ApNoteService.ts index c6e6b3a1e8..fc7aa1e0b9 100644 --- a/packages/backend/src/core/activitypub/models/ApNoteService.ts +++ b/packages/backend/src/core/activitypub/models/ApNoteService.ts @@ -24,7 +24,6 @@ import { UtilityService } from '@/core/UtilityService.js'; import { bindThis } from '@/decorators.js'; import { checkHttps } from '@/misc/check-https.js'; import { IdentifiableError } from '@/misc/identifiable-error.js'; -import { isNotNull } from '@/misc/is-not-null.js'; import { getOneApId, getApId, getOneApHrefNullable, validPost, isEmoji, getApType } from '../type.js'; import { ApLoggerService } from '../ApLoggerService.js'; import { ApMfmService } from '../ApMfmService.js'; @@ -253,7 +252,7 @@ export class ApNoteService { } }; - const uris = unique([note._misskey_quote, note.quoteUrl].filter(isNotNull)); + const uris = unique([note._misskey_quote, note.quoteUrl].filter(x => x != null)); const results = await Promise.all(uris.map(tryResolveNote)); quote = results.filter((x): x is { status: 'ok', res: MiNote } => x.status === 'ok').map(x => x.res).at(0); diff --git a/packages/backend/src/core/activitypub/models/ApPersonService.ts b/packages/backend/src/core/activitypub/models/ApPersonService.ts index 744b1ea683..c41fc713d5 100644 --- a/packages/backend/src/core/activitypub/models/ApPersonService.ts +++ b/packages/backend/src/core/activitypub/models/ApPersonService.ts @@ -3,9 +3,10 @@ * SPDX-License-Identifier: AGPL-3.0-only */ +import { verify } from 'crypto'; import { Inject, Injectable } from '@nestjs/common'; import promiseLimit from 'promise-limit'; -import { DataSource } from 'typeorm'; +import { DataSource, In, Not } from 'typeorm'; import { ModuleRef } from '@nestjs/core'; import { DI } from '@/di-symbols.js'; import type { FollowingsRepository, InstancesRepository, UserProfilesRepository, UserPublickeysRepository, UsersRepository } from '@/models/_.js'; @@ -34,11 +35,12 @@ import { StatusError } from '@/misc/status-error.js'; import type { UtilityService } from '@/core/UtilityService.js'; import type { UserEntityService } from '@/core/entities/UserEntityService.js'; import { bindThis } from '@/decorators.js'; +import { RoleService } from '@/core/RoleService.js'; import { MetaService } from '@/core/MetaService.js'; import { DriveFileEntityService } from '@/core/entities/DriveFileEntityService.js'; import type { AccountMoveService } from '@/core/AccountMoveService.js'; import { checkHttps } from '@/misc/check-https.js'; -import { isNotNull } from '@/misc/is-not-null.js'; +import { REMOTE_USER_CACHE_TTL, REMOTE_USER_MOVE_COOLDOWN } from '@/const.js'; import { getApId, getApType, getOneApHrefNullable, isActor, isCollection, isCollectionOrOrderedCollection, isPropertyValue } from '../type.js'; import { extractApHashtags } from './tag.js'; import type { OnModuleInit } from '@nestjs/common'; @@ -48,7 +50,7 @@ import type { ApResolverService, Resolver } from '../ApResolverService.js'; import type { ApLoggerService } from '../ApLoggerService.js'; // eslint-disable-next-line @typescript-eslint/consistent-type-imports import type { ApImageService } from './ApImageService.js'; -import type { IActor, IObject } from '../type.js'; +import type { IActor, IKey, IObject } from '../type.js'; const nameLength = 128; const summaryLength = 2048; @@ -101,6 +103,8 @@ export class ApPersonService implements OnModuleInit { @Inject(DI.followingsRepository) private followingsRepository: FollowingsRepository, + + private roleService: RoleService, ) { } @@ -183,13 +187,38 @@ export class ApPersonService implements OnModuleInit { } if (x.publicKey) { - if (typeof x.publicKey.id !== 'string') { - throw new Error('invalid Actor: publicKey.id is not a string'); + const publicKeys = Array.isArray(x.publicKey) ? x.publicKey : [x.publicKey]; + + for (const publicKey of publicKeys) { + if (typeof publicKey.id !== 'string') { + throw new Error('invalid Actor: publicKey.id is not a string'); + } + + const publicKeyIdHost = this.punyHost(publicKey.id); + if (publicKeyIdHost !== expectHost) { + throw new Error('invalid Actor: publicKey.id has different host'); + } + } + } + + if (x.additionalPublicKeys) { + if (!x.publicKey) { + throw new Error('invalid Actor: additionalPublicKeys is set but publicKey is not'); } - const publicKeyIdHost = this.punyHost(x.publicKey.id); - if (publicKeyIdHost !== expectHost) { - throw new Error('invalid Actor: publicKey.id has different host'); + if (!Array.isArray(x.additionalPublicKeys)) { + throw new Error('invalid Actor: additionalPublicKeys is not an array'); + } + + for (const key of x.additionalPublicKeys) { + if (typeof key.id !== 'string') { + throw new Error('invalid Actor: additionalPublicKeys.id is not a string'); + } + + const keyIdHost = this.punyHost(key.id); + if (keyIdHost !== expectHost) { + throw new Error('invalid Actor: additionalPublicKeys.id has different host'); + } } } @@ -226,6 +255,33 @@ export class ApPersonService implements OnModuleInit { return null; } + /** + * uriからUser(Person)をフェッチします。 + * + * Misskeyに対象のPersonが登録されていればそれを返し、登録がなければnullを返します。 + * また、TTLが0でない場合、TTLを過ぎていた場合はupdatePersonを実行します。 + */ + @bindThis + async fetchPersonWithRenewal(uri: string, TTL = REMOTE_USER_CACHE_TTL): Promise { + const exist = await this.fetchPerson(uri); + if (exist == null) return null; + + if (this.userEntityService.isRemoteUser(exist)) { + if (TTL === 0 || exist.lastFetchedAt == null || Date.now() - exist.lastFetchedAt.getTime() > TTL) { + this.logger.debug('fetchPersonWithRenewal: renew', { uri, TTL, lastFetchedAt: exist.lastFetchedAt }); + try { + await this.updatePerson(exist.uri); + return await this.fetchPerson(uri); + } catch (err) { + this.logger.error('error occurred while renewing user', { err }); + } + } + this.logger.debug('fetchPersonWithRenewal: use cache', { uri, TTL, lastFetchedAt: exist.lastFetchedAt }); + } + + return exist; + } + private async resolveAvatarAndBanner(user: MiRemoteUser, icon: any, image: any): Promise>> { if (user == null) throw new Error('failed to create user: user is null'); @@ -239,6 +295,11 @@ export class ApPersonService implements OnModuleInit { return this.apImageService.resolveImage(user, img).catch(() => null); })); + if (((avatar != null && avatar.id != null) || (banner != null && banner.id != null)) + && !(await this.roleService.getUserPolicies(user.id)).canUpdateBioMedia) { + return {}; + } + /* we don't want to return nulls on errors! if the database fields are already null, nothing changes; if the database has old @@ -356,11 +417,15 @@ export class ApPersonService implements OnModuleInit { })); if (person.publicKey) { - await transactionalEntityManager.save(new MiUserPublickey({ - userId: user.id, - keyId: person.publicKey.id, - keyPem: person.publicKey.publicKeyPem, - })); + const publicKeys = new Map(); + (person.additionalPublicKeys ?? []).forEach(key => publicKeys.set(key.id, key)); + (Array.isArray(person.publicKey) ? person.publicKey : [person.publicKey]).forEach(key => publicKeys.set(key.id, key)); + + await transactionalEntityManager.save(Array.from(publicKeys.values(), key => new MiUserPublickey({ + keyId: key.id, + userId: user!.id, + keyPem: key.publicKeyPem, + }))); } }); } catch (e) { @@ -506,11 +571,29 @@ export class ApPersonService implements OnModuleInit { // Update user await this.usersRepository.update(exist.id, updates); - if (person.publicKey) { - await this.userPublickeysRepository.update({ userId: exist.id }, { - keyId: person.publicKey.id, - keyPem: person.publicKey.publicKeyPem, + try { + // Deleteアクティビティ受信時にもここが走ってsaveがuserforeign key制約エラーを吐くことがある + // とりあえずtry-catchで囲っておく + const publicKeys = new Map(); + if (person.publicKey) { + (person.additionalPublicKeys ?? []).forEach(key => publicKeys.set(key.id, key)); + (Array.isArray(person.publicKey) ? person.publicKey : [person.publicKey]).forEach(key => publicKeys.set(key.id, key)); + + await this.userPublickeysRepository.save(Array.from(publicKeys.values(), key => ({ + keyId: key.id, + userId: exist.id, + keyPem: key.publicKeyPem, + }))); + } + + this.userPublickeysRepository.delete({ + keyId: Not(In(Array.from(publicKeys.keys()))), + userId: exist.id, + }).catch(err => { + this.logger.error('something happened while deleting remote user public keys:', { userId: exist.id, err }); }); + } catch (err) { + this.logger.error('something happened while updating remote user public keys:', { userId: exist.id, err }); } let _description: string | null = null; @@ -552,7 +635,7 @@ export class ApPersonService implements OnModuleInit { exist.movedAt == null || // 以前のmovingから14日以上経過した場合のみ移行処理を許可 // (Mastodonのクールダウン期間は30日だが若干緩めに設定しておく) - exist.movedAt.getTime() + 1000 * 60 * 60 * 24 * 14 < updated.movedAt.getTime() + exist.movedAt.getTime() + REMOTE_USER_MOVE_COOLDOWN < updated.movedAt.getTime() )) { this.logger.info(`Start to process Move of @${updated.username}@${updated.host} (${uri})`); return this.processRemoteMove(updated, movePreventUris) @@ -575,9 +658,9 @@ export class ApPersonService implements OnModuleInit { * リモートサーバーからフェッチしてMisskeyに登録しそれを返します。 */ @bindThis - public async resolvePerson(uri: string, resolver?: Resolver): Promise { + public async resolvePerson(uri: string, resolver?: Resolver, withRenewal = false): Promise { //#region このサーバーに既に登録されていたらそれを返す - const exist = await this.fetchPerson(uri); + const exist = withRenewal ? await this.fetchPersonWithRenewal(uri) : await this.fetchPerson(uri); if (exist) return exist; //#endregion @@ -637,7 +720,7 @@ export class ApPersonService implements OnModuleInit { // とりあえずidを別の時間で生成して順番を維持 let td = 0; - for (const note of featuredNotes.filter(isNotNull)) { + for (const note of featuredNotes.filter(x => x != null)) { td -= 1000; transactionalEntityManager.insert(MiUserNotePining, { id: this.idService.gen(Date.now() + td), diff --git a/packages/backend/src/core/activitypub/models/ApQuestionService.ts b/packages/backend/src/core/activitypub/models/ApQuestionService.ts index d1936cfe1d..73004d10b0 100644 --- a/packages/backend/src/core/activitypub/models/ApQuestionService.ts +++ b/packages/backend/src/core/activitypub/models/ApQuestionService.ts @@ -10,7 +10,6 @@ import type { Config } from '@/config.js'; import type { IPoll } from '@/models/Poll.js'; import type Logger from '@/logger.js'; import { bindThis } from '@/decorators.js'; -import { isNotNull } from '@/misc/is-not-null.js'; import { isQuestion } from '../type.js'; import { ApLoggerService } from '../ApLoggerService.js'; import { ApResolverService } from '../ApResolverService.js'; @@ -52,7 +51,7 @@ export class ApQuestionService { const choices = question[multiple ? 'anyOf' : 'oneOf'] ?.map((x) => x.name) - .filter(isNotNull) + .filter(x => x != null) ?? []; const votes = question[multiple ? 'anyOf' : 'oneOf']?.map((x) => x.replies?.totalItems ?? x._misskey_votes ?? 0); @@ -75,10 +74,10 @@ export class ApQuestionService { //#region このサーバーに既に登録されているか const note = await this.notesRepository.findOneBy({ uri }); - if (note == null) throw new Error('Question is not registed'); + if (note == null) throw new Error('Question is not registered'); const poll = await this.pollsRepository.findOneBy({ noteId: note.id }); - if (poll == null) throw new Error('Question is not registed'); + if (poll == null) throw new Error('Question is not registered'); //#endregion // resolve new Question object diff --git a/packages/backend/src/core/activitypub/models/tag.ts b/packages/backend/src/core/activitypub/models/tag.ts index e7ceec3262..f75cc45f7e 100644 --- a/packages/backend/src/core/activitypub/models/tag.ts +++ b/packages/backend/src/core/activitypub/models/tag.ts @@ -4,7 +4,6 @@ */ import { toArray } from '@/misc/prelude/array.js'; -import { isNotNull } from '@/misc/is-not-null.js'; import { isHashtag } from '../type.js'; import type { IObject, IApHashtag } from '../type.js'; @@ -16,7 +15,7 @@ export function extractApHashtags(tags: IObject | IObject[] | null | undefined): return hashtags.map(tag => { const m = tag.name.match(/^#(.+)/); return m ? m[1] : null; - }).filter(isNotNull); + }).filter(x => x != null); } export function extractApHashtagObjects(tags: IObject | IObject[] | null | undefined): IApHashtag[] { diff --git a/packages/backend/src/core/activitypub/type.ts b/packages/backend/src/core/activitypub/type.ts index 5b6c6c8ca6..1d55971660 100644 --- a/packages/backend/src/core/activitypub/type.ts +++ b/packages/backend/src/core/activitypub/type.ts @@ -55,7 +55,7 @@ export function getOneApId(value: ApObject): string { export function getApId(value: string | IObject): string { if (typeof value === 'string') return value; if (typeof value.id === 'string') return value.id; - throw new Error('cannot detemine id'); + throw new Error('cannot determine id'); } /** @@ -169,10 +169,8 @@ export interface IActor extends IObject { discoverable?: boolean; inbox: string; sharedInbox?: string; // 後方互換性のため - publicKey?: { - id: string; - publicKeyPem: string; - }; + publicKey?: IKey | IKey[]; + additionalPublicKeys?: IKey[]; followers?: string | ICollection | IOrderedCollection; following?: string | ICollection | IOrderedCollection; featured?: string | IOrderedCollection; @@ -236,8 +234,9 @@ export const isEmoji = (object: IObject): object is IApEmoji => export interface IKey extends IObject { type: 'Key'; + id: string; owner: string; - publicKeyPem: string | Buffer; + publicKeyPem: string; } export interface IApDocument extends IObject { diff --git a/packages/backend/src/core/chart/ChartLoggerService.ts b/packages/backend/src/core/chart/ChartLoggerService.ts index afc728d564..20815ea968 100644 --- a/packages/backend/src/core/chart/ChartLoggerService.ts +++ b/packages/backend/src/core/chart/ChartLoggerService.ts @@ -14,6 +14,6 @@ export class ChartLoggerService { constructor( private loggerService: LoggerService, ) { - this.logger = this.loggerService.getLogger('chart', 'white', process.env.NODE_ENV !== 'test'); + this.logger = this.loggerService.getLogger('chart', 'white'); } } diff --git a/packages/backend/src/core/chart/charts/federation.ts b/packages/backend/src/core/chart/charts/federation.ts index 5e4555ee96..c2329a2f73 100644 --- a/packages/backend/src/core/chart/charts/federation.ts +++ b/packages/backend/src/core/chart/charts/federation.ts @@ -47,7 +47,7 @@ export default class FederationChart extends Chart { // eslint-di const suspendedInstancesQuery = this.instancesRepository.createQueryBuilder('instance') .select('instance.host') - .where('instance.isSuspended = true'); + .where('instance.suspensionState != \'none\''); const pubsubSubQuery = this.followingsRepository.createQueryBuilder('f') .select('f.followerHost') @@ -89,7 +89,7 @@ export default class FederationChart extends Chart { // eslint-di .select('COUNT(instance.id)') .where(`instance.host IN (${ subInstancesQuery.getQuery() })`) .andWhere(meta.blockedHosts.length === 0 ? '1=1' : 'instance.host NOT ILIKE ANY(ARRAY[:...blocked])', { blocked: meta.blockedHosts.flatMap(x => [x, `%.${x}`]) }) - .andWhere('instance.isSuspended = false') + .andWhere('instance.suspensionState = \'none\'') .andWhere('instance.isNotResponding = false') .getRawOne() .then(x => parseInt(x.count, 10)), @@ -97,7 +97,7 @@ export default class FederationChart extends Chart { // eslint-di .select('COUNT(instance.id)') .where(`instance.host IN (${ pubInstancesQuery.getQuery() })`) .andWhere(meta.blockedHosts.length === 0 ? '1=1' : 'instance.host NOT ILIKE ANY(ARRAY[:...blocked])', { blocked: meta.blockedHosts.flatMap(x => [x, `%.${x}`]) }) - .andWhere('instance.isSuspended = false') + .andWhere('instance.suspensionState = \'none\'') .andWhere('instance.isNotResponding = false') .getRawOne() .then(x => parseInt(x.count, 10)), diff --git a/packages/backend/src/core/entities/AbuseReportNotificationRecipientEntityService.ts b/packages/backend/src/core/entities/AbuseReportNotificationRecipientEntityService.ts new file mode 100644 index 0000000000..1e23c194c5 --- /dev/null +++ b/packages/backend/src/core/entities/AbuseReportNotificationRecipientEntityService.ts @@ -0,0 +1,87 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { Inject, Injectable } from '@nestjs/common'; +import { In } from 'typeorm'; +import { DI } from '@/di-symbols.js'; +import type { AbuseReportNotificationRecipientRepository, MiAbuseReportNotificationRecipient } from '@/models/_.js'; +import { bindThis } from '@/decorators.js'; +import { UserEntityService } from '@/core/entities/UserEntityService.js'; +import { Packed } from '@/misc/json-schema.js'; +import { SystemWebhookEntityService } from '@/core/entities/SystemWebhookEntityService.js'; + +@Injectable() +export class AbuseReportNotificationRecipientEntityService { + constructor( + @Inject(DI.abuseReportNotificationRecipientRepository) + private abuseReportNotificationRecipientRepository: AbuseReportNotificationRecipientRepository, + private userEntityService: UserEntityService, + private systemWebhookEntityService: SystemWebhookEntityService, + ) { + } + + @bindThis + public async pack( + src: MiAbuseReportNotificationRecipient['id'] | MiAbuseReportNotificationRecipient, + opts?: { + users: Map>, + webhooks: Map>, + }, + ): Promise> { + const recipient = typeof src === 'object' + ? src + : await this.abuseReportNotificationRecipientRepository.findOneByOrFail({ id: src }); + const user = recipient.userId + ? (opts?.users.get(recipient.userId) ?? await this.userEntityService.pack<'UserLite'>(recipient.userId)) + : undefined; + const webhook = recipient.systemWebhookId + ? (opts?.webhooks.get(recipient.systemWebhookId) ?? await this.systemWebhookEntityService.pack(recipient.systemWebhookId)) + : undefined; + + return { + id: recipient.id, + isActive: recipient.isActive, + updatedAt: recipient.updatedAt.toISOString(), + name: recipient.name, + method: recipient.method, + userId: recipient.userId ?? undefined, + user: user, + systemWebhookId: recipient.systemWebhookId ?? undefined, + systemWebhook: webhook, + }; + } + + @bindThis + public async packMany( + src: MiAbuseReportNotificationRecipient['id'][] | MiAbuseReportNotificationRecipient[], + ): Promise[]> { + const objs = src.filter((it): it is MiAbuseReportNotificationRecipient => typeof it === 'object'); + const ids = src.filter((it): it is MiAbuseReportNotificationRecipient['id'] => typeof it === 'string'); + if (ids.length > 0) { + objs.push( + ...await this.abuseReportNotificationRecipientRepository.findBy({ id: In(ids) }), + ); + } + + const userIds = objs.map(it => it.userId).filter(x => x != null); + const users: Map> = (userIds.length > 0) + ? await this.userEntityService.packMany(userIds) + .then(it => new Map(it.map(it => [it.id, it]))) + : new Map(); + + const systemWebhookIds = objs.map(it => it.systemWebhookId).filter(x => x != null); + const systemWebhooks: Map> = (systemWebhookIds.length > 0) + ? await this.systemWebhookEntityService.packMany(systemWebhookIds) + .then(it => new Map(it.map(it => [it.id, it]))) + : new Map(); + + return Promise + .all( + objs.map(it => this.pack(it, { users: users, webhooks: systemWebhooks })), + ) + .then(it => it.sort((a, b) => a.id.localeCompare(b.id))); + } +} + diff --git a/packages/backend/src/core/entities/AbuseUserReportEntityService.ts b/packages/backend/src/core/entities/AbuseUserReportEntityService.ts index b0e1d1ab36..a13c244c19 100644 --- a/packages/backend/src/core/entities/AbuseUserReportEntityService.ts +++ b/packages/backend/src/core/entities/AbuseUserReportEntityService.ts @@ -10,7 +10,6 @@ import { awaitAll } from '@/misc/prelude/await-all.js'; import type { MiAbuseUserReport } from '@/models/AbuseUserReport.js'; import { bindThis } from '@/decorators.js'; import { IdService } from '@/core/IdService.js'; -import { isNotNull } from '@/misc/is-not-null.js'; import type { Packed } from '@/misc/json-schema.js'; import { UserEntityService } from './UserEntityService.js'; @@ -63,7 +62,7 @@ export class AbuseUserReportEntityService { ) { const _reporters = reports.map(({ reporter, reporterId }) => reporter ?? reporterId); const _targetUsers = reports.map(({ targetUser, targetUserId }) => targetUser ?? targetUserId); - const _assignees = reports.map(({ assignee, assigneeId }) => assignee ?? assigneeId).filter(isNotNull); + const _assignees = reports.map(({ assignee, assigneeId }) => assignee ?? assigneeId).filter(x => x != null); const _userMap = await this.userEntityService.packMany( [..._reporters, ..._targetUsers, ..._assignees], null, diff --git a/packages/backend/src/core/entities/ClipEntityService.ts b/packages/backend/src/core/entities/ClipEntityService.ts index 3855a28436..d915645906 100644 --- a/packages/backend/src/core/entities/ClipEntityService.ts +++ b/packages/backend/src/core/entities/ClipEntityService.ts @@ -53,7 +53,7 @@ export class ClipEntityService { isPublic: clip.isPublic, favoritedCount: await this.clipFavoritesRepository.countBy({ clipId: clip.id }), isFavorited: meId ? await this.clipFavoritesRepository.exists({ where: { clipId: clip.id, userId: meId } }) : undefined, - notesCount: meId ? await this.clipNotesRepository.countBy({ clipId: clip.id }) : undefined, + notesCount: (meId === clip.userId) ? await this.clipNotesRepository.countBy({ clipId: clip.id }) : undefined, }); } diff --git a/packages/backend/src/core/entities/DriveFileEntityService.ts b/packages/backend/src/core/entities/DriveFileEntityService.ts index 02ff2e7754..c485555f90 100644 --- a/packages/backend/src/core/entities/DriveFileEntityService.ts +++ b/packages/backend/src/core/entities/DriveFileEntityService.ts @@ -16,7 +16,6 @@ import { appendQuery, query } from '@/misc/prelude/url.js'; import { deepClone } from '@/misc/clone.js'; import { bindThis } from '@/decorators.js'; import { isMimeImage } from '@/misc/is-mime-image.js'; -import { isNotNull } from '@/misc/is-not-null.js'; import { IdService } from '@/core/IdService.js'; import { UtilityService } from '../UtilityService.js'; import { VideoProcessingService } from '../VideoProcessingService.js'; @@ -261,11 +260,11 @@ export class DriveFileEntityService { files: MiDriveFile[], options?: PackOptions, ): Promise[]> { - const _user = files.map(({ user, userId }) => user ?? userId).filter(isNotNull); + const _user = files.map(({ user, userId }) => user ?? userId).filter(x => x != null); const _userMap = await this.userEntityService.packMany(_user) .then(users => new Map(users.map(user => [user.id, user]))); const items = await Promise.all(files.map(f => this.packNullable(f, options, f.userId ? { packedUser: _userMap.get(f.userId) } : {}))); - return items.filter(isNotNull); + return items.filter(x => x != null); } @bindThis @@ -290,6 +289,6 @@ export class DriveFileEntityService { ): Promise[]> { if (fileIds.length === 0) return []; const filesMap = await this.packManyByIdsMap(fileIds, options); - return fileIds.map(id => filesMap.get(id)).filter(isNotNull); + return fileIds.map(id => filesMap.get(id)).filter(x => x != null); } } diff --git a/packages/backend/src/core/entities/InstanceEntityService.ts b/packages/backend/src/core/entities/InstanceEntityService.ts index 9117b13914..fd0f55c6ab 100644 --- a/packages/backend/src/core/entities/InstanceEntityService.ts +++ b/packages/backend/src/core/entities/InstanceEntityService.ts @@ -56,6 +56,7 @@ export class InstanceEntityService { infoUpdatedAt: instance.infoUpdatedAt ? instance.infoUpdatedAt.toISOString() : null, latestRequestReceivedAt: instance.latestRequestReceivedAt ? instance.latestRequestReceivedAt.toISOString() : null, moderationNote: iAmModerator ? instance.moderationNote : null, + httpMessageSignaturesImplementationLevel: instance.httpMessageSignaturesImplementationLevel, }; } diff --git a/packages/backend/src/core/entities/InviteCodeEntityService.ts b/packages/backend/src/core/entities/InviteCodeEntityService.ts index 26f57e1299..5d3e823a2a 100644 --- a/packages/backend/src/core/entities/InviteCodeEntityService.ts +++ b/packages/backend/src/core/entities/InviteCodeEntityService.ts @@ -12,7 +12,6 @@ import type { MiUser } from '@/models/User.js'; import type { MiRegistrationTicket } from '@/models/RegistrationTicket.js'; import { bindThis } from '@/decorators.js'; import { IdService } from '@/core/IdService.js'; -import { isNotNull } from '@/misc/is-not-null.js'; import { UserEntityService } from './UserEntityService.js'; @Injectable() @@ -59,8 +58,8 @@ export class InviteCodeEntityService { tickets: MiRegistrationTicket[], me: { id: MiUser['id'] }, ) { - const _createdBys = tickets.map(({ createdBy, createdById }) => createdBy ?? createdById).filter(isNotNull); - const _usedBys = tickets.map(({ usedBy, usedById }) => usedBy ?? usedById).filter(isNotNull); + const _createdBys = tickets.map(({ createdBy, createdById }) => createdBy ?? createdById).filter(x => x != null); + const _usedBys = tickets.map(({ usedBy, usedById }) => usedBy ?? usedById).filter(x => x != null); const _userMap = await this.userEntityService.packMany([..._createdBys, ..._usedBys], me) .then(users => new Map(users.map(u => [u.id, u]))); return Promise.all( diff --git a/packages/backend/src/core/entities/MetaEntityService.ts b/packages/backend/src/core/entities/MetaEntityService.ts index 5dfec589e1..09641ce485 100644 --- a/packages/backend/src/core/entities/MetaEntityService.ts +++ b/packages/backend/src/core/entities/MetaEntityService.ts @@ -50,6 +50,22 @@ export class MetaEntityService { })) .getMany(); + // クライアントの手間を減らすためあらかじめJSONに変換しておく + let defaultLightTheme = null; + let defaultDarkTheme = null; + if (instance.defaultLightTheme) { + try { + defaultLightTheme = JSON.stringify(JSON5.parse(instance.defaultLightTheme)); + } catch (e) { + } + } + if (instance.defaultDarkTheme) { + try { + defaultDarkTheme = JSON.stringify(JSON5.parse(instance.defaultDarkTheme)); + } catch (e) { + } + } + const packed: Packed<'MetaLite'> = { maintainerName: instance.maintainerName, maintainerEmail: instance.maintainerEmail, @@ -90,9 +106,8 @@ export class MetaEntityService { backgroundImageUrl: instance.backgroundImageUrl, logoImageUrl: instance.logoImageUrl, maxNoteTextLength: MAX_NOTE_TEXT_LENGTH, - // クライアントの手間を減らすためあらかじめJSONに変換しておく - defaultLightTheme: instance.defaultLightTheme ? JSON.stringify(JSON5.parse(instance.defaultLightTheme)) : null, - defaultDarkTheme: instance.defaultDarkTheme ? JSON.stringify(JSON5.parse(instance.defaultDarkTheme)) : null, + defaultLightTheme, + defaultDarkTheme, ads: ads.map(ad => ({ id: ad.id, url: ad.url, diff --git a/packages/backend/src/core/entities/NoteEntityService.ts b/packages/backend/src/core/entities/NoteEntityService.ts index 2ce72c50b8..2cd092231c 100644 --- a/packages/backend/src/core/entities/NoteEntityService.ts +++ b/packages/backend/src/core/entities/NoteEntityService.ts @@ -14,7 +14,6 @@ import type { MiNote } from '@/models/Note.js'; import type { MiNoteReaction } from '@/models/NoteReaction.js'; import type { UsersRepository, NotesRepository, FollowingsRepository, PollsRepository, PollVotesRepository, NoteReactionsRepository, ChannelsRepository } from '@/models/_.js'; import { bindThis } from '@/decorators.js'; -import { isNotNull } from '@/misc/is-not-null.js'; import { DebounceLoader } from '@/misc/loader.js'; import { IdService } from '@/core/IdService.js'; import type { OnModuleInit } from '@nestjs/common'; @@ -276,7 +275,7 @@ export class NoteEntityService implements OnModuleInit { packedFiles.set(k, v); } } - return fileIds.map(id => packedFiles.get(id)).filter(isNotNull); + return fileIds.map(id => packedFiles.get(id)).filter(x => x != null); } @bindThis @@ -449,12 +448,12 @@ export class NoteEntityService implements OnModuleInit { await this.customEmojiService.prefetchEmojis(this.aggregateNoteEmojis(notes)); // TODO: 本当は renote とか reply がないのに renoteId とか replyId があったらここで解決しておく - const fileIds = notes.map(n => [n.fileIds, n.renote?.fileIds, n.reply?.fileIds]).flat(2).filter(isNotNull); + const fileIds = notes.map(n => [n.fileIds, n.renote?.fileIds, n.reply?.fileIds]).flat(2).filter(x => x != null); const packedFiles = fileIds.length > 0 ? await this.driveFileEntityService.packManyByIdsMap(fileIds) : new Map(); const users = [ ...notes.map(({ user, userId }) => user ?? userId), - ...notes.map(({ replyUserId }) => replyUserId).filter(isNotNull), - ...notes.map(({ renoteUserId }) => renoteUserId).filter(isNotNull), + ...notes.map(({ replyUserId }) => replyUserId).filter(x => x != null), + ...notes.map(({ renoteUserId }) => renoteUserId).filter(x => x != null), ]; const packedUsers = await this.userEntityService.packMany(users, me) .then(users => new Map(users.map(u => [u.id, u]))); diff --git a/packages/backend/src/core/entities/NotificationEntityService.ts b/packages/backend/src/core/entities/NotificationEntityService.ts index 94d56c883b..f393513510 100644 --- a/packages/backend/src/core/entities/NotificationEntityService.ts +++ b/packages/backend/src/core/entities/NotificationEntityService.ts @@ -13,7 +13,6 @@ import type { MiGroupedNotification, MiNotification } from '@/models/Notificatio import type { MiNote } from '@/models/Note.js'; import type { Packed } from '@/misc/json-schema.js'; import { bindThis } from '@/decorators.js'; -import { isNotNull } from '@/misc/is-not-null.js'; import { FilterUnionByProperty, groupedNotificationTypes } from '@/types.js'; import { CacheService } from '@/core/CacheService.js'; import { RoleEntityService } from './RoleEntityService.js'; @@ -103,7 +102,7 @@ export class NotificationEntityService implements OnModuleInit { user, reaction: reaction.reaction, }; - }))).filter(r => isNotNull(r.user)); + }))).filter(r => r.user != null); // if all users have been deleted, don't show this notification if (reactions.length === 0) { return null; @@ -124,7 +123,7 @@ export class NotificationEntityService implements OnModuleInit { } return this.userEntityService.pack(userId, { id: meId }); - }))).filter(isNotNull); + }))).filter(x => x != null); // if all users have been deleted, don't show this notification if (users.length === 0) { return null; @@ -181,7 +180,7 @@ export class NotificationEntityService implements OnModuleInit { validNotifications = await this.#filterValidNotifier(validNotifications, meId); - const noteIds = validNotifications.map(x => 'noteId' in x ? x.noteId : null).filter(isNotNull); + const noteIds = validNotifications.map(x => 'noteId' in x ? x.noteId : null).filter(x => x != null); const notes = noteIds.length > 0 ? await this.notesRepository.find({ where: { id: In(noteIds) }, relations: ['user', 'reply', 'reply.user', 'renote', 'renote.user'], @@ -223,7 +222,7 @@ export class NotificationEntityService implements OnModuleInit { ); }); - return (await Promise.all(packPromises)).filter(isNotNull); + return (await Promise.all(packPromises)).filter(x => x != null); } @bindThis @@ -305,7 +304,7 @@ export class NotificationEntityService implements OnModuleInit { this.cacheService.userProfileCache.fetch(meId).then(p => new Set(p.mutedInstances)), ]); - const notifierIds = notifications.map(notification => 'notifierId' in notification ? notification.notifierId : null).filter(isNotNull); + const notifierIds = notifications.map(notification => 'notifierId' in notification ? notification.notifierId : null).filter(x => x != null); const notifiers = notifierIds.length > 0 ? await this.usersRepository.find({ where: { id: In(notifierIds) }, }) : []; @@ -313,7 +312,7 @@ export class NotificationEntityService implements OnModuleInit { const filteredNotifications = ((await Promise.all(notifications.map(async (notification) => { const isValid = this.#validateNotifier(notification, userIdsWhoMeMuting, userMutedInstances, notifiers); return isValid ? notification : null; - }))) as [T | null] ).filter(isNotNull); + }))) as [T | null] ).filter(x => x != null); return filteredNotifications; } diff --git a/packages/backend/src/core/entities/PageEntityService.ts b/packages/backend/src/core/entities/PageEntityService.ts index 142d9e81db..46bf51bb6d 100644 --- a/packages/backend/src/core/entities/PageEntityService.ts +++ b/packages/backend/src/core/entities/PageEntityService.ts @@ -14,7 +14,6 @@ import type { MiPage } from '@/models/Page.js'; import type { MiDriveFile } from '@/models/DriveFile.js'; import { bindThis } from '@/decorators.js'; import { IdService } from '@/core/IdService.js'; -import { isNotNull } from '@/misc/is-not-null.js'; import { UserEntityService } from './UserEntityService.js'; import { DriveFileEntityService } from './DriveFileEntityService.js'; @@ -106,7 +105,7 @@ export class PageEntityService { script: page.script, eyeCatchingImageId: page.eyeCatchingImageId, eyeCatchingImage: page.eyeCatchingImageId ? await this.driveFileEntityService.pack(page.eyeCatchingImageId) : null, - attachedFiles: this.driveFileEntityService.packMany((await Promise.all(attachedFiles)).filter(isNotNull)), + attachedFiles: this.driveFileEntityService.packMany((await Promise.all(attachedFiles)).filter(x => x != null)), likedCount: page.likedCount, isLiked: meId ? await this.pageLikesRepository.exists({ where: { pageId: page.id, userId: meId } }) : undefined, }); diff --git a/packages/backend/src/core/entities/SystemWebhookEntityService.ts b/packages/backend/src/core/entities/SystemWebhookEntityService.ts new file mode 100644 index 0000000000..e18734091c --- /dev/null +++ b/packages/backend/src/core/entities/SystemWebhookEntityService.ts @@ -0,0 +1,74 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { Inject, Injectable } from '@nestjs/common'; +import { In } from 'typeorm'; +import { DI } from '@/di-symbols.js'; +import type { MiSystemWebhook, SystemWebhooksRepository } from '@/models/_.js'; +import { bindThis } from '@/decorators.js'; +import { Packed } from '@/misc/json-schema.js'; + +@Injectable() +export class SystemWebhookEntityService { + constructor( + @Inject(DI.systemWebhooksRepository) + private systemWebhooksRepository: SystemWebhooksRepository, + ) { + } + + @bindThis + public async pack( + src: MiSystemWebhook['id'] | MiSystemWebhook, + opts?: { + webhooks: Map + }, + ): Promise> { + const webhook = typeof src === 'object' + ? src + : opts?.webhooks.get(src) ?? await this.systemWebhooksRepository.findOneByOrFail({ id: src }); + + return { + id: webhook.id, + isActive: webhook.isActive, + updatedAt: webhook.updatedAt.toISOString(), + latestSentAt: webhook.latestSentAt?.toISOString() ?? null, + latestStatus: webhook.latestStatus, + name: webhook.name, + on: webhook.on, + url: webhook.url, + secret: webhook.secret, + }; + } + + @bindThis + public async packMany(src: MiSystemWebhook['id'][] | MiSystemWebhook[]): Promise[]> { + if (src.length === 0) { + return []; + } + + const webhooks = Array.of(); + webhooks.push( + ...src.filter((it): it is MiSystemWebhook => typeof it === 'object'), + ); + + const ids = src.filter((it): it is MiSystemWebhook['id'] => typeof it === 'string'); + if (ids.length > 0) { + webhooks.push( + ...await this.systemWebhooksRepository.findBy({ id: In(ids) }), + ); + } + + return Promise + .all( + webhooks.map(x => + this.pack(x, { + webhooks: new Map(webhooks.map(x => [x.id, x])), + }), + ), + ) + .then(it => it.sort((a, b) => a.id.localeCompare(b.id))); + } +} + diff --git a/packages/backend/src/core/entities/UserEntityService.ts b/packages/backend/src/core/entities/UserEntityService.ts index b80a1ec206..7fd093c191 100644 --- a/packages/backend/src/core/entities/UserEntityService.ts +++ b/packages/backend/src/core/entities/UserEntityService.ts @@ -47,7 +47,6 @@ import { IdService } from '@/core/IdService.js'; import type { AnnouncementService } from '@/core/AnnouncementService.js'; import type { CustomEmojiService } from '@/core/CustomEmojiService.js'; import { AvatarDecorationService } from '@/core/AvatarDecorationService.js'; -import { isNotNull } from '@/misc/is-not-null.js'; import type { OnModuleInit } from '@nestjs/common'; import type { NoteEntityService } from './NoteEntityService.js'; import type { DriveFileEntityService } from './DriveFileEntityService.js'; @@ -502,11 +501,15 @@ export class UserEntityService implements OnModuleInit { emojis: this.customEmojiService.populateEmojis(user.emojis, user.host), onlineStatus: this.getOnlineStatus(user), // パフォーマンス上の理由でローカルユーザーのみ - badgeRoles: user.host == null ? this.roleService.getUserBadgeRoles(user.id).then(rs => rs.sort((a, b) => b.displayOrder - a.displayOrder).map(r => ({ - name: r.name, - iconUrl: r.iconUrl, - displayOrder: r.displayOrder, - }))) : undefined, + badgeRoles: user.host == null ? this.roleService.getUserBadgeRoles(user.id).then((rs) => rs + .filter((r) => r.isPublic || iAmModerator) + .sort((a, b) => b.displayOrder - a.displayOrder) + .map((r) => ({ + name: r.name, + iconUrl: r.iconUrl, + displayOrder: r.displayOrder, + })) + ) : undefined, ...(isDetailed ? { url: profile!.url, @@ -514,7 +517,7 @@ export class UserEntityService implements OnModuleInit { movedTo: user.movedToUri ? this.apPersonService.resolvePerson(user.movedToUri).then(user => user.id).catch(() => null) : null, alsoKnownAs: user.alsoKnownAs ? Promise.all(user.alsoKnownAs.map(uri => this.apPersonService.fetchPerson(uri).then(user => user?.id).catch(() => null))) - .then(xs => xs.length === 0 ? null : xs.filter(isNotNull)) + .then(xs => xs.length === 0 ? null : xs.filter(x => x != null)) : null, createdAt: this.idService.parse(user.id).date.toISOString(), updatedAt: user.updatedAt ? user.updatedAt.toISOString() : null, diff --git a/packages/backend/src/di-symbols.ts b/packages/backend/src/di-symbols.ts index 919f4794a3..271082b4ff 100644 --- a/packages/backend/src/di-symbols.ts +++ b/packages/backend/src/di-symbols.ts @@ -49,6 +49,7 @@ export const DI = { swSubscriptionsRepository: Symbol('swSubscriptionsRepository'), hashtagsRepository: Symbol('hashtagsRepository'), abuseUserReportsRepository: Symbol('abuseUserReportsRepository'), + abuseReportNotificationRecipientRepository: Symbol('abuseReportNotificationRecipientRepository'), registrationTicketsRepository: Symbol('registrationTicketsRepository'), authSessionsRepository: Symbol('authSessionsRepository'), accessTokensRepository: Symbol('accessTokensRepository'), @@ -70,6 +71,7 @@ export const DI = { channelFavoritesRepository: Symbol('channelFavoritesRepository'), registryItemsRepository: Symbol('registryItemsRepository'), webhooksRepository: Symbol('webhooksRepository'), + systemWebhooksRepository: Symbol('systemWebhooksRepository'), adsRepository: Symbol('adsRepository'), passwordResetRequestsRepository: Symbol('passwordResetRequestsRepository'), retentionAggregationsRepository: Symbol('retentionAggregationsRepository'), diff --git a/packages/backend/src/logger.ts b/packages/backend/src/logger.ts index d4705af601..ff5363a425 100644 --- a/packages/backend/src/logger.ts +++ b/packages/backend/src/logger.ts @@ -22,31 +22,27 @@ type Level = 'error' | 'success' | 'warning' | 'debug' | 'info'; export default class Logger { private context: Context; private parentLogger: Logger | null = null; - private store: boolean; - constructor(context: string, color?: KEYWORD, store = true) { + constructor(context: string, color?: KEYWORD) { this.context = { name: context, color: color, }; - this.store = store; } @bindThis - public createSubLogger(context: string, color?: KEYWORD, store = true): Logger { - const logger = new Logger(context, color, store); + public createSubLogger(context: string, color?: KEYWORD): Logger { + const logger = new Logger(context, color); logger.parentLogger = this; return logger; } @bindThis - private log(level: Level, message: string, data?: Record | null, important = false, subContexts: Context[] = [], store = true): void { + private log(level: Level, message: string, data?: Record | null, important = false, subContexts: Context[] = []): void { if (envOption.quiet) return; - if (!this.store) store = false; - if (level === 'debug') store = false; if (this.parentLogger) { - this.parentLogger.log(level, message, data, important, [this.context].concat(subContexts), store); + this.parentLogger.log(level, message, data, important, [this.context].concat(subContexts)); return; } diff --git a/packages/backend/src/misc/cache.ts b/packages/backend/src/misc/cache.ts index bba64a06ef..f498c110bf 100644 --- a/packages/backend/src/misc/cache.ts +++ b/packages/backend/src/misc/cache.ts @@ -195,6 +195,9 @@ export class MemoryKVCache { private lifetime: number; private gcIntervalHandle: NodeJS.Timeout; + /** + * @param lifetime キャッシュの生存期間 (ms) + */ constructor(lifetime: MemoryKVCache['lifetime']) { this.cache = new Map(); this.lifetime = lifetime; diff --git a/packages/backend/src/misc/gen-key-pair.ts b/packages/backend/src/misc/gen-key-pair.ts index 02a303dc0a..0b033ec33e 100644 --- a/packages/backend/src/misc/gen-key-pair.ts +++ b/packages/backend/src/misc/gen-key-pair.ts @@ -3,39 +3,14 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import * as crypto from 'node:crypto'; -import * as util from 'node:util'; +import { genEd25519KeyPair, genRsaKeyPair } from '@misskey-dev/node-http-message-signatures'; -const generateKeyPair = util.promisify(crypto.generateKeyPair); - -export async function genRsaKeyPair(modulusLength = 2048) { - return await generateKeyPair('rsa', { - modulusLength, - publicKeyEncoding: { - type: 'spki', - format: 'pem', - }, - privateKeyEncoding: { - type: 'pkcs8', - format: 'pem', - cipher: undefined, - passphrase: undefined, - }, - }); -} - -export async function genEcKeyPair(namedCurve: 'prime256v1' | 'secp384r1' | 'secp521r1' | 'curve25519' = 'prime256v1') { - return await generateKeyPair('ec', { - namedCurve, - publicKeyEncoding: { - type: 'spki', - format: 'pem', - }, - privateKeyEncoding: { - type: 'pkcs8', - format: 'pem', - cipher: undefined, - passphrase: undefined, - }, - }); +export async function genRSAAndEd25519KeyPair(rsaModulusLength = 4096) { + const [rsa, ed25519] = await Promise.all([genRsaKeyPair(rsaModulusLength), genEd25519KeyPair()]); + return { + publicKey: rsa.publicKey, + privateKey: rsa.privateKey, + ed25519PublicKey: ed25519.publicKey, + ed25519PrivateKey: ed25519.privateKey, + }; } diff --git a/packages/backend/src/misc/is-not-null.ts b/packages/backend/src/misc/is-not-null.ts deleted file mode 100644 index 8d9dc8bb39..0000000000 --- a/packages/backend/src/misc/is-not-null.ts +++ /dev/null @@ -1,8 +0,0 @@ -/* - * SPDX-FileCopyrightText: syuilo and misskey-project - * SPDX-License-Identifier: AGPL-3.0-only - */ - -export function isNotNull>(input: T | undefined | null): input is T { - return input != null; -} diff --git a/packages/backend/src/misc/is-user-related.ts b/packages/backend/src/misc/is-user-related.ts index 93c9b2b814..862d6e6a38 100644 --- a/packages/backend/src/misc/is-user-related.ts +++ b/packages/backend/src/misc/is-user-related.ts @@ -4,6 +4,10 @@ */ export function isUserRelated(note: any, userIds: Set, ignoreAuthor = false): boolean { + if (!note) { + return false; + } + if (userIds.has(note.userId) && !ignoreAuthor) { return true; } diff --git a/packages/backend/src/misc/json-schema.ts b/packages/backend/src/misc/json-schema.ts index 41e5bfe9e4..a721b8663c 100644 --- a/packages/backend/src/misc/json-schema.ts +++ b/packages/backend/src/misc/json-schema.ts @@ -4,12 +4,12 @@ */ import { - packedUserLiteSchema, - packedUserDetailedNotMeOnlySchema, packedMeDetailedOnlySchema, - packedUserDetailedNotMeSchema, packedMeDetailedSchema, + packedUserDetailedNotMeOnlySchema, + packedUserDetailedNotMeSchema, packedUserDetailedSchema, + packedUserLiteSchema, packedUserSchema, } from '@/models/json-schema/user.js'; import { packedNoteSchema } from '@/models/json-schema/note.js'; @@ -25,7 +25,7 @@ import { packedBlockingSchema } from '@/models/json-schema/blocking.js'; import { packedNoteReactionSchema } from '@/models/json-schema/note-reaction.js'; import { packedHashtagSchema } from '@/models/json-schema/hashtag.js'; import { packedInviteCodeSchema } from '@/models/json-schema/invite-code.js'; -import { packedPageSchema, packedPageBlockSchema } from '@/models/json-schema/page.js'; +import { packedPageBlockSchema, packedPageSchema } from '@/models/json-schema/page.js'; import { packedNoteFavoriteSchema } from '@/models/json-schema/note-favorite.js'; import { packedChannelSchema } from '@/models/json-schema/channel.js'; import { packedAntennaSchema } from '@/models/json-schema/antenna.js'; @@ -38,25 +38,27 @@ import { packedFlashSchema } from '@/models/json-schema/flash.js'; import { packedAnnouncementSchema } from '@/models/json-schema/announcement.js'; import { packedSigninSchema } from '@/models/json-schema/signin.js'; import { - packedRoleLiteSchema, - packedRoleSchema, - packedRolePoliciesSchema, + packedRoleCondFormulaFollowersOrFollowingOrNotesSchema, packedRoleCondFormulaLogicsSchema, - packedRoleCondFormulaValueNot, - packedRoleCondFormulaValueIsLocalOrRemoteSchema, packedRoleCondFormulaValueAssignedRoleSchema, packedRoleCondFormulaValueCreatedSchema, - packedRoleCondFormulaFollowersOrFollowingOrNotesSchema, + packedRoleCondFormulaValueIsLocalOrRemoteSchema, + packedRoleCondFormulaValueNot, packedRoleCondFormulaValueSchema, packedRoleCondFormulaValueUserSettingBooleanSchema, + packedRoleLiteSchema, + packedRolePoliciesSchema, + packedRoleSchema, } from '@/models/json-schema/role.js'; import { packedAdSchema } from '@/models/json-schema/ad.js'; -import { packedReversiGameLiteSchema, packedReversiGameDetailedSchema } from '@/models/json-schema/reversi-game.js'; +import { packedReversiGameDetailedSchema, packedReversiGameLiteSchema } from '@/models/json-schema/reversi-game.js'; import { - packedMetaLiteSchema, packedMetaDetailedOnlySchema, packedMetaDetailedSchema, + packedMetaLiteSchema, } from '@/models/json-schema/meta.js'; +import { packedSystemWebhookSchema } from '@/models/json-schema/system-webhook.js'; +import { packedAbuseReportNotificationRecipientSchema } from '@/models/json-schema/abuse-report-notification-recipient.js'; export const refs = { UserLite: packedUserLiteSchema, @@ -111,6 +113,8 @@ export const refs = { MetaLite: packedMetaLiteSchema, MetaDetailedOnly: packedMetaDetailedOnlySchema, MetaDetailed: packedMetaDetailedSchema, + SystemWebhook: packedSystemWebhookSchema, + AbuseReportNotificationRecipient: packedAbuseReportNotificationRecipientSchema, }; export type Packed = SchemaType; diff --git a/packages/backend/src/misc/json-value.ts b/packages/backend/src/misc/json-value.ts new file mode 100644 index 0000000000..7994441791 --- /dev/null +++ b/packages/backend/src/misc/json-value.ts @@ -0,0 +1,8 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +export type JsonValue = JsonArray | JsonObject | string | number | boolean | null; +export type JsonObject = {[K in string]?: JsonValue}; +export type JsonArray = JsonValue[]; diff --git a/packages/backend/src/misc/prelude/array.ts b/packages/backend/src/misc/prelude/array.ts index dbfe1fff18..f741a0c913 100644 --- a/packages/backend/src/misc/prelude/array.ts +++ b/packages/backend/src/misc/prelude/array.ts @@ -65,44 +65,6 @@ export function maximum(xs: number[]): number { return Math.max(...xs); } -/** - * Splits an array based on the equivalence relation. - * The concatenation of the result is equal to the argument. - */ -export function groupBy(f: EndoRelation, xs: T[]): T[][] { - const groups = [] as T[][]; - for (const x of xs) { - const lastGroup = groups.at(-1); - if (lastGroup !== undefined && f(lastGroup[0], x)) { - lastGroup.push(x); - } else { - groups.push([x]); - } - } - return groups; -} - -/** - * Splits an array based on the equivalence relation induced by the function. - * The concatenation of the result is equal to the argument. - */ -export function groupOn(f: (x: T) => S, xs: T[]): T[][] { - return groupBy((a, b) => f(a) === f(b), xs); -} - -export function groupByX(collections: T[], keySelector: (x: T) => string) { - return collections.reduce((obj: Record, item: T) => { - const key = keySelector(item); - if (!Object.prototype.hasOwnProperty.call(obj, key)) { - obj[key] = []; - } - - obj[key].push(item); - - return obj; - }, {}); -} - /** * Compare two arrays by lexicographical order */ diff --git a/packages/backend/src/misc/prelude/maybe.ts b/packages/backend/src/misc/prelude/maybe.ts deleted file mode 100644 index 1c58ccb9c7..0000000000 --- a/packages/backend/src/misc/prelude/maybe.ts +++ /dev/null @@ -1,25 +0,0 @@ -/* - * SPDX-FileCopyrightText: syuilo and misskey-project - * SPDX-License-Identifier: AGPL-3.0-only - */ - -export interface IMaybe { - isJust(): this is IJust; -} - -export interface IJust extends IMaybe { - get(): T; -} - -export function just(value: T): IJust { - return { - isJust: () => true, - get: () => value, - }; -} - -export function nothing(): IMaybe { - return { - isJust: () => false, - }; -} diff --git a/packages/backend/src/misc/prelude/string.ts b/packages/backend/src/misc/prelude/string.ts deleted file mode 100644 index 67ea529961..0000000000 --- a/packages/backend/src/misc/prelude/string.ts +++ /dev/null @@ -1,20 +0,0 @@ -/* - * SPDX-FileCopyrightText: syuilo and misskey-project - * SPDX-License-Identifier: AGPL-3.0-only - */ - -export function concat(xs: string[]): string { - return xs.join(''); -} - -export function capitalize(s: string): string { - return toUpperCase(s.charAt(0)) + toLowerCase(s.slice(1)); -} - -export function toUpperCase(s: string): string { - return s.toUpperCase(); -} - -export function toLowerCase(s: string): string { - return s.toLowerCase(); -} diff --git a/packages/backend/src/models/AbuseReportNotificationRecipient.ts b/packages/backend/src/models/AbuseReportNotificationRecipient.ts new file mode 100644 index 0000000000..fbff880afc --- /dev/null +++ b/packages/backend/src/models/AbuseReportNotificationRecipient.ts @@ -0,0 +1,100 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { Column, Entity, Index, JoinColumn, ManyToOne, PrimaryColumn } from 'typeorm'; +import { MiSystemWebhook } from '@/models/SystemWebhook.js'; +import { MiUserProfile } from '@/models/UserProfile.js'; +import { id } from './util/id.js'; +import { MiUser } from './User.js'; + +/** + * 通報受信時に通知を送信する方法. + */ +export type RecipientMethod = 'email' | 'webhook'; + +@Entity('abuse_report_notification_recipient') +export class MiAbuseReportNotificationRecipient { + @PrimaryColumn(id()) + public id: string; + + /** + * 有効かどうか. + */ + @Index() + @Column('boolean', { + default: true, + }) + public isActive: boolean; + + /** + * 更新日時. + */ + @Column('timestamp with time zone', { + default: () => 'CURRENT_TIMESTAMP', + }) + public updatedAt: Date; + + /** + * 通知設定名. + */ + @Column('varchar', { + length: 255, + }) + public name: string; + + /** + * 通知方法. + */ + @Index() + @Column('varchar', { + length: 64, + }) + public method: RecipientMethod; + + /** + * 通知先のユーザID. + */ + @Index() + @Column({ + ...id(), + nullable: true, + }) + public userId: MiUser['id'] | null; + + /** + * 通知先のユーザ. + */ + @ManyToOne(type => MiUser, { + onDelete: 'CASCADE', + }) + @JoinColumn({ name: 'userId', referencedColumnName: 'id', foreignKeyConstraintName: 'FK_abuse_report_notification_recipient_userId1' }) + public user: MiUser | null; + + /** + * 通知先のユーザプロフィール. + */ + @ManyToOne(type => MiUserProfile, {}) + @JoinColumn({ name: 'userId', referencedColumnName: 'userId', foreignKeyConstraintName: 'FK_abuse_report_notification_recipient_userId2' }) + public userProfile: MiUserProfile | null; + + /** + * 通知先のシステムWebhookId. + */ + @Index() + @Column({ + ...id(), + nullable: true, + }) + public systemWebhookId: string | null; + + /** + * 通知先のシステムWebhook. + */ + @ManyToOne(type => MiSystemWebhook, { + onDelete: 'CASCADE', + }) + @JoinColumn() + public systemWebhook: MiSystemWebhook | null; +} diff --git a/packages/backend/src/models/Instance.ts b/packages/backend/src/models/Instance.ts index 17cd5c6665..f2f2831cf1 100644 --- a/packages/backend/src/models/Instance.ts +++ b/packages/backend/src/models/Instance.ts @@ -158,4 +158,9 @@ export class MiInstance { length: 16384, default: '', }) public moderationNote: string; + + @Column('varchar', { + length: 16, default: '00', nullable: false, + }) + public httpMessageSignaturesImplementationLevel: string; } diff --git a/packages/backend/src/models/RepositoryModule.ts b/packages/backend/src/models/RepositoryModule.ts index d3062d6b36..ea0f88baba 100644 --- a/packages/backend/src/models/RepositoryModule.ts +++ b/packages/backend/src/models/RepositoryModule.ts @@ -3,11 +3,83 @@ * SPDX-License-Identifier: AGPL-3.0-only */ +import type { Provider } from '@nestjs/common'; import { Module } from '@nestjs/common'; import { DI } from '@/di-symbols.js'; -import { MiRepository, MiAbuseUserReport, MiAccessToken, MiAd, MiAnnouncement, MiAnnouncementRead, MiAntenna, MiApp, MiAuthSession, MiAvatarDecoration, MiBlocking, MiChannel, MiChannelFavorite, MiChannelFollowing, MiClip, MiClipFavorite, MiClipNote, MiDriveFile, MiDriveFolder, MiEmoji, MiFlash, MiFlashLike, MiFollowRequest, MiFollowing, MiGalleryLike, MiGalleryPost, MiHashtag, MiInstance, MiMeta, MiModerationLog, MiMuting, MiNote, MiNoteFavorite, MiNoteReaction, MiNoteThreadMuting, MiNoteUnread, MiPage, MiPageLike, MiPasswordResetRequest, MiPoll, MiPollVote, MiPromoNote, MiPromoRead, MiRegistrationTicket, MiRegistryItem, MiRelay, MiRenoteMuting, MiRetentionAggregation, MiRole, MiRoleAssignment, MiSignin, MiSwSubscription, MiUsedUsername, MiUser, MiUserIp, MiUserKeypair, MiUserList, MiUserListFavorite, MiUserListMembership, MiUserMemo, MiUserNotePining, MiUserPending, MiUserProfile, MiUserPublickey, MiUserSecurityKey, MiWebhook, MiBubbleGameRecord, MiReversiGame, miRepository } from './_.js'; +import { + MiAbuseReportNotificationRecipient, + MiAbuseUserReport, + MiAccessToken, + MiAd, + MiAnnouncement, + MiAnnouncementRead, + MiAntenna, + MiApp, + MiAuthSession, + MiAvatarDecoration, + MiBlocking, + MiBubbleGameRecord, + MiChannel, + MiChannelFavorite, + MiChannelFollowing, + MiClip, + MiClipFavorite, + MiClipNote, + MiDriveFile, + MiDriveFolder, + MiEmoji, + MiFlash, + MiFlashLike, + MiFollowing, + MiFollowRequest, + MiGalleryLike, + MiGalleryPost, + MiHashtag, + MiInstance, + MiMeta, + MiModerationLog, + MiMuting, + MiNote, + MiNoteFavorite, + MiNoteReaction, + MiNoteThreadMuting, + MiNoteUnread, + MiPage, + MiPageLike, + MiPasswordResetRequest, + MiPoll, + MiPollVote, + MiPromoNote, + MiPromoRead, + MiRegistrationTicket, + MiRegistryItem, + MiRelay, + MiRenoteMuting, + MiRepository, + miRepository, + MiRetentionAggregation, + MiReversiGame, + MiRole, + MiRoleAssignment, + MiSignin, + MiSwSubscription, + MiSystemWebhook, + MiUsedUsername, + MiUser, + MiUserIp, + MiUserKeypair, + MiUserList, + MiUserListFavorite, + MiUserListMembership, + MiUserMemo, + MiUserNotePining, + MiUserPending, + MiUserProfile, + MiUserPublickey, + MiUserSecurityKey, + MiWebhook +} from './_.js'; import type { DataSource } from 'typeorm'; -import type { Provider } from '@nestjs/common'; const $usersRepository: Provider = { provide: DI.usersRepository, @@ -225,6 +297,12 @@ const $abuseUserReportsRepository: Provider = { inject: [DI.db], }; +const $abuseReportNotificationRecipientRepository: Provider = { + provide: DI.abuseReportNotificationRecipientRepository, + useFactory: (db: DataSource) => db.getRepository(MiAbuseReportNotificationRecipient), + inject: [DI.db], +}; + const $registrationTicketsRepository: Provider = { provide: DI.registrationTicketsRepository, useFactory: (db: DataSource) => db.getRepository(MiRegistrationTicket).extend(miRepository as MiRepository), @@ -351,6 +429,12 @@ const $webhooksRepository: Provider = { inject: [DI.db], }; +const $systemWebhooksRepository: Provider = { + provide: DI.systemWebhooksRepository, + useFactory: (db: DataSource) => db.getRepository(MiSystemWebhook), + inject: [DI.db], +}; + const $adsRepository: Provider = { provide: DI.adsRepository, useFactory: (db: DataSource) => db.getRepository(MiAd).extend(miRepository as MiRepository), @@ -412,8 +496,7 @@ const $reversiGamesRepository: Provider = { }; @Module({ - imports: [ - ], + imports: [], providers: [ $usersRepository, $notesRepository, @@ -451,6 +534,7 @@ const $reversiGamesRepository: Provider = { $swSubscriptionsRepository, $hashtagsRepository, $abuseUserReportsRepository, + $abuseReportNotificationRecipientRepository, $registrationTicketsRepository, $authSessionsRepository, $accessTokensRepository, @@ -472,6 +556,7 @@ const $reversiGamesRepository: Provider = { $channelFavoritesRepository, $registryItemsRepository, $webhooksRepository, + $systemWebhooksRepository, $adsRepository, $passwordResetRequestsRepository, $retentionAggregationsRepository, @@ -520,6 +605,7 @@ const $reversiGamesRepository: Provider = { $swSubscriptionsRepository, $hashtagsRepository, $abuseUserReportsRepository, + $abuseReportNotificationRecipientRepository, $registrationTicketsRepository, $authSessionsRepository, $accessTokensRepository, @@ -541,6 +627,7 @@ const $reversiGamesRepository: Provider = { $channelFavoritesRepository, $registryItemsRepository, $webhooksRepository, + $systemWebhooksRepository, $adsRepository, $passwordResetRequestsRepository, $retentionAggregationsRepository, @@ -553,4 +640,5 @@ const $reversiGamesRepository: Provider = { $reversiGamesRepository, ], }) -export class RepositoryModule {} +export class RepositoryModule { +} diff --git a/packages/backend/src/models/SystemWebhook.ts b/packages/backend/src/models/SystemWebhook.ts new file mode 100644 index 0000000000..86fb323d1d --- /dev/null +++ b/packages/backend/src/models/SystemWebhook.ts @@ -0,0 +1,98 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { Column, Entity, Index, PrimaryColumn } from 'typeorm'; +import { Serialized } from '@/types.js'; +import { id } from './util/id.js'; + +export const systemWebhookEventTypes = [ + // ユーザからの通報を受けたとき + 'abuseReport', + // 通報を処理したとき + 'abuseReportResolved', +] as const; +export type SystemWebhookEventType = typeof systemWebhookEventTypes[number]; + +@Entity('system_webhook') +export class MiSystemWebhook { + @PrimaryColumn(id()) + public id: string; + + /** + * 有効かどうか. + */ + @Index('IDX_system_webhook_isActive', { synchronize: false }) + @Column('boolean', { + default: true, + }) + public isActive: boolean; + + /** + * 更新日時. + */ + @Column('timestamp with time zone', { + default: () => 'CURRENT_TIMESTAMP', + }) + public updatedAt: Date; + + /** + * 最後に送信された日時. + */ + @Column('timestamp with time zone', { + nullable: true, + }) + public latestSentAt: Date | null; + + /** + * 最後に送信されたステータスコード + */ + @Column('integer', { + nullable: true, + }) + public latestStatus: number | null; + + /** + * 通知設定名. + */ + @Column('varchar', { + length: 255, + }) + public name: string; + + /** + * イベント種別. + */ + @Index('IDX_system_webhook_on', { synchronize: false }) + @Column('varchar', { + length: 128, + array: true, + default: '{}', + }) + public on: SystemWebhookEventType[]; + + /** + * Webhook送信先のURL. + */ + @Column('varchar', { + length: 1024, + }) + public url: string; + + /** + * Webhook検証用の値. + */ + @Column('varchar', { + length: 1024, + }) + public secret: string; + + static deserialize(obj: Serialized): MiSystemWebhook { + return { + ...obj, + updatedAt: new Date(obj.updatedAt), + latestSentAt: obj.latestSentAt ? new Date(obj.latestSentAt) : null, + }; + } +} diff --git a/packages/backend/src/models/UserKeypair.ts b/packages/backend/src/models/UserKeypair.ts index f5252d126c..afa74ef11a 100644 --- a/packages/backend/src/models/UserKeypair.ts +++ b/packages/backend/src/models/UserKeypair.ts @@ -3,7 +3,7 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import { PrimaryColumn, Entity, JoinColumn, Column, OneToOne } from 'typeorm'; +import { PrimaryColumn, Entity, JoinColumn, Column, ManyToOne } from 'typeorm'; import { id } from './util/id.js'; import { MiUser } from './User.js'; @@ -12,22 +12,42 @@ export class MiUserKeypair { @PrimaryColumn(id()) public userId: MiUser['id']; - @OneToOne(type => MiUser, { + @ManyToOne(type => MiUser, { onDelete: 'CASCADE', }) @JoinColumn() public user: MiUser | null; + /** + * RSA public key + */ @Column('varchar', { length: 4096, }) public publicKey: string; + /** + * RSA private key + */ @Column('varchar', { length: 4096, }) public privateKey: string; + @Column('varchar', { + length: 128, + nullable: true, + default: null, + }) + public ed25519PublicKey: string | null; + + @Column('varchar', { + length: 128, + nullable: true, + default: null, + }) + public ed25519PrivateKey: string | null; + constructor(data: Partial) { if (data == null) return; diff --git a/packages/backend/src/models/UserPublickey.ts b/packages/backend/src/models/UserPublickey.ts index 6bcd785304..0ecff2bcbe 100644 --- a/packages/backend/src/models/UserPublickey.ts +++ b/packages/backend/src/models/UserPublickey.ts @@ -9,7 +9,13 @@ import { MiUser } from './User.js'; @Entity('user_publickey') export class MiUserPublickey { - @PrimaryColumn(id()) + @PrimaryColumn('varchar', { + length: 256, + }) + public keyId: string; + + @Index() + @Column(id()) public userId: MiUser['id']; @OneToOne(type => MiUser, { @@ -18,12 +24,6 @@ export class MiUserPublickey { @JoinColumn() public user: MiUser | null; - @Index({ unique: true }) - @Column('varchar', { - length: 256, - }) - public keyId: string; - @Column('varchar', { length: 4096, }) diff --git a/packages/backend/src/models/_.ts b/packages/backend/src/models/_.ts index 2e6a41586e..c72bdaa727 100644 --- a/packages/backend/src/models/_.ts +++ b/packages/backend/src/models/_.ts @@ -11,6 +11,7 @@ import { RawSqlResultsToEntityTransformer } from 'typeorm/query-builder/transfor import { ObjectUtils } from 'typeorm/util/ObjectUtils.js'; import { OrmUtils } from 'typeorm/util/OrmUtils.js'; import { MiAbuseUserReport } from '@/models/AbuseUserReport.js'; +import { MiAbuseReportNotificationRecipient } from '@/models/AbuseReportNotificationRecipient.js'; import { MiAccessToken } from '@/models/AccessToken.js'; import { MiAd } from '@/models/Ad.js'; import { MiAnnouncement } from '@/models/Announcement.js'; @@ -68,6 +69,7 @@ import { MiUserPublickey } from '@/models/UserPublickey.js'; import { MiUserSecurityKey } from '@/models/UserSecurityKey.js'; import { MiUserMemo } from '@/models/UserMemo.js'; import { MiWebhook } from '@/models/Webhook.js'; +import { MiSystemWebhook } from '@/models/SystemWebhook.js'; import { MiChannel } from '@/models/Channel.js'; import { MiRetentionAggregation } from '@/models/RetentionAggregation.js'; import { MiRole } from '@/models/Role.js'; @@ -80,34 +82,14 @@ import { MiReversiGame } from '@/models/ReversiGame.js'; import type { QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity.js'; export interface MiRepository { - createTableColumnNames(this: Repository & MiRepository, queryBuilder: InsertQueryBuilder): string[]; - createTableColumnNamesWithPrimaryKey(this: Repository & MiRepository, queryBuilder: InsertQueryBuilder): string[]; + createTableColumnNames(this: Repository & MiRepository): string[]; insertOne(this: Repository & MiRepository, entity: QueryDeepPartialEntity, findOptions?: Pick, 'relations'>): Promise; selectAliasColumnNames(this: Repository & MiRepository, queryBuilder: InsertQueryBuilder, builder: SelectQueryBuilder): void; } export const miRepository = { - createTableColumnNames(queryBuilder) { - // @ts-expect-error -- protected - const insertedColumns = queryBuilder.getInsertedColumns(); - if (insertedColumns.length) { - return insertedColumns.map(column => column.databaseName); - } - if (!queryBuilder.expressionMap.mainAlias?.hasMetadata && !queryBuilder.expressionMap.insertColumns.length) { - // @ts-expect-error -- protected - const valueSets = queryBuilder.getValueSets(); - if (valueSets.length === 1) { - return Object.keys(valueSets[0]); - } - } - return queryBuilder.expressionMap.insertColumns; - }, - createTableColumnNamesWithPrimaryKey(queryBuilder) { - const columnNames = this.createTableColumnNames(queryBuilder); - if (!columnNames.includes('id')) { - columnNames.unshift('id'); - } - return columnNames; + createTableColumnNames() { + return this.metadata.columns.filter(column => column.isSelect && !column.isVirtual).map(column => column.databaseName); }, async insertOne(entity, findOptions?) { const queryBuilder = this.createQueryBuilder().insert().values(entity); @@ -115,7 +97,7 @@ export const miRepository = { const mainAlias = queryBuilder.expressionMap.mainAlias!; const name = mainAlias.name; mainAlias.name = 't'; - const columnNames = this.createTableColumnNamesWithPrimaryKey(queryBuilder); + const columnNames = this.createTableColumnNames(); queryBuilder.returning(columnNames.reduce((a, c) => `${a}, ${queryBuilder.escape(c)}`, '').slice(2)); const builder = this.createQueryBuilder().addCommonTableExpression(queryBuilder, 'cte', { columnNames }); // eslint-disable-next-line @typescript-eslint/no-non-null-assertion @@ -136,7 +118,7 @@ export const miRepository = { selectOrAddSelect = (selection, selectionAliasName) => builder.addSelect(selection, selectionAliasName); return builder.select(selection, selectionAliasName); }; - for (const columnName of this.createTableColumnNamesWithPrimaryKey(queryBuilder)) { + for (const columnName of this.createTableColumnNames()) { selectOrAddSelect(`${builder.alias}.${columnName}`, `${builder.alias}_${columnName}`); } }, @@ -144,6 +126,7 @@ export const miRepository = { export { MiAbuseUserReport, + MiAbuseReportNotificationRecipient, MiAccessToken, MiAd, MiAnnouncement, @@ -201,6 +184,7 @@ export { MiUserPublickey, MiUserSecurityKey, MiWebhook, + MiSystemWebhook, MiChannel, MiRetentionAggregation, MiRole, @@ -213,6 +197,7 @@ export { }; export type AbuseUserReportsRepository = Repository & MiRepository; +export type AbuseReportNotificationRecipientRepository = Repository & MiRepository; export type AccessTokensRepository = Repository & MiRepository; export type AdsRepository = Repository & MiRepository; export type AnnouncementsRepository = Repository & MiRepository; @@ -270,6 +255,7 @@ export type UserProfilesRepository = Repository & MiRepository & MiRepository; export type UserSecurityKeysRepository = Repository & MiRepository; export type WebhooksRepository = Repository & MiRepository; +export type SystemWebhooksRepository = Repository & MiRepository; export type ChannelsRepository = Repository & MiRepository; export type RetentionAggregationsRepository = Repository & MiRepository; export type RolesRepository = Repository & MiRepository; diff --git a/packages/backend/src/models/json-schema/abuse-report-notification-recipient.ts b/packages/backend/src/models/json-schema/abuse-report-notification-recipient.ts new file mode 100644 index 0000000000..6215f0f5a2 --- /dev/null +++ b/packages/backend/src/models/json-schema/abuse-report-notification-recipient.ts @@ -0,0 +1,50 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +export const packedAbuseReportNotificationRecipientSchema = { + type: 'object', + properties: { + id: { + type: 'string', + optional: false, nullable: false, + }, + isActive: { + type: 'boolean', + optional: false, nullable: false, + }, + updatedAt: { + type: 'string', + format: 'date-time', + optional: false, nullable: false, + }, + name: { + type: 'string', + optional: false, nullable: false, + }, + method: { + type: 'string', + optional: false, nullable: false, + enum: ['email', 'webhook'], + }, + userId: { + type: 'string', + optional: true, nullable: false, + }, + user: { + type: 'object', + optional: true, nullable: false, + ref: 'UserLite', + }, + systemWebhookId: { + type: 'string', + optional: true, nullable: false, + }, + systemWebhook: { + type: 'object', + optional: true, nullable: false, + ref: 'SystemWebhook', + }, + }, +} as const; diff --git a/packages/backend/src/models/json-schema/drive-file.ts b/packages/backend/src/models/json-schema/drive-file.ts index ca88cc0e39..5ee1561c50 100644 --- a/packages/backend/src/models/json-schema/drive-file.ts +++ b/packages/backend/src/models/json-schema/drive-file.ts @@ -20,7 +20,7 @@ export const packedDriveFileSchema = { name: { type: 'string', optional: false, nullable: false, - example: 'lenna.jpg', + example: '192.jpg', }, type: { type: 'string', diff --git a/packages/backend/src/models/json-schema/federation-instance.ts b/packages/backend/src/models/json-schema/federation-instance.ts index ed40d405c6..c02e7f557a 100644 --- a/packages/backend/src/models/json-schema/federation-instance.ts +++ b/packages/backend/src/models/json-schema/federation-instance.ts @@ -116,5 +116,9 @@ export const packedFederationInstanceSchema = { type: 'string', optional: true, nullable: true, }, + httpMessageSignaturesImplementationLevel: { + type: 'string', + optional: false, nullable: false, + }, }, } as const; diff --git a/packages/backend/src/models/json-schema/role.ts b/packages/backend/src/models/json-schema/role.ts index d9987a70c3..7366f05356 100644 --- a/packages/backend/src/models/json-schema/role.ts +++ b/packages/backend/src/models/json-schema/role.ts @@ -228,6 +228,10 @@ export const packedRolePoliciesSchema = { type: 'boolean', optional: false, nullable: false, }, + canUpdateBioMedia: { + type: 'boolean', + optional: false, nullable: false, + }, pinLimit: { type: 'integer', optional: false, nullable: false, diff --git a/packages/backend/src/models/json-schema/system-webhook.ts b/packages/backend/src/models/json-schema/system-webhook.ts new file mode 100644 index 0000000000..d83065a743 --- /dev/null +++ b/packages/backend/src/models/json-schema/system-webhook.ts @@ -0,0 +1,54 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { systemWebhookEventTypes } from '@/models/SystemWebhook.js'; + +export const packedSystemWebhookSchema = { + type: 'object', + properties: { + id: { + type: 'string', + optional: false, nullable: false, + }, + isActive: { + type: 'boolean', + optional: false, nullable: false, + }, + updatedAt: { + type: 'string', + format: 'date-time', + optional: false, nullable: false, + }, + latestSentAt: { + type: 'string', + format: 'date-time', + optional: false, nullable: true, + }, + latestStatus: { + type: 'number', + optional: false, nullable: true, + }, + name: { + type: 'string', + optional: false, nullable: false, + }, + on: { + type: 'array', + items: { + type: 'string', + optional: false, nullable: false, + enum: systemWebhookEventTypes, + }, + }, + url: { + type: 'string', + optional: false, nullable: false, + }, + secret: { + type: 'string', + optional: false, nullable: false, + }, + }, +} as const; diff --git a/packages/backend/src/postgres.ts b/packages/backend/src/postgres.ts index 2d14537bbb..251a03c303 100644 --- a/packages/backend/src/postgres.ts +++ b/packages/backend/src/postgres.ts @@ -5,13 +5,12 @@ // https://github.com/typeorm/typeorm/issues/2400 import pg from 'pg'; -pg.types.setTypeParser(20, Number); - import { DataSource, Logger } from 'typeorm'; import * as highlight from 'cli-highlight'; import { entities as charts } from '@/core/chart/entities.js'; import { MiAbuseUserReport } from '@/models/AbuseUserReport.js'; +import { MiAbuseReportNotificationRecipient } from '@/models/AbuseReportNotificationRecipient.js'; import { MiAccessToken } from '@/models/AccessToken.js'; import { MiAd } from '@/models/Ad.js'; import { MiAnnouncement } from '@/models/Announcement.js'; @@ -69,6 +68,7 @@ import { MiUserProfile } from '@/models/UserProfile.js'; import { MiUserPublickey } from '@/models/UserPublickey.js'; import { MiUserSecurityKey } from '@/models/UserSecurityKey.js'; import { MiWebhook } from '@/models/Webhook.js'; +import { MiSystemWebhook } from '@/models/SystemWebhook.js'; import { MiChannel } from '@/models/Channel.js'; import { MiRetentionAggregation } from '@/models/RetentionAggregation.js'; import { MiRole } from '@/models/Role.js'; @@ -83,9 +83,11 @@ import { Config } from '@/config.js'; import MisskeyLogger from '@/logger.js'; import { bindThis } from '@/decorators.js'; +pg.types.setTypeParser(20, Number); + export const dbLogger = new MisskeyLogger('db'); -const sqlLogger = dbLogger.createSubLogger('sql', 'gray', false); +const sqlLogger = dbLogger.createSubLogger('sql', 'gray'); class MyCustomLogger implements Logger { @bindThis @@ -167,6 +169,7 @@ export const entities = [ MiHashtag, MiSwSubscription, MiAbuseUserReport, + MiAbuseReportNotificationRecipient, MiRegistrationTicket, MiSignin, MiModerationLog, @@ -185,6 +188,7 @@ export const entities = [ MiPasswordResetRequest, MiUserPending, MiWebhook, + MiSystemWebhook, MiUserIp, MiRetentionAggregation, MiRole, diff --git a/packages/backend/src/queue/QueueProcessorModule.ts b/packages/backend/src/queue/QueueProcessorModule.ts index 8086158997..a1fd38fcc5 100644 --- a/packages/backend/src/queue/QueueProcessorModule.ts +++ b/packages/backend/src/queue/QueueProcessorModule.ts @@ -11,7 +11,8 @@ import { QueueProcessorService } from './QueueProcessorService.js'; import { DeliverProcessorService } from './processors/DeliverProcessorService.js'; import { EndedPollNotificationProcessorService } from './processors/EndedPollNotificationProcessorService.js'; import { InboxProcessorService } from './processors/InboxProcessorService.js'; -import { WebhookDeliverProcessorService } from './processors/WebhookDeliverProcessorService.js'; +import { UserWebhookDeliverProcessorService } from './processors/UserWebhookDeliverProcessorService.js'; +import { SystemWebhookDeliverProcessorService } from './processors/SystemWebhookDeliverProcessorService.js'; import { CheckExpiredMutingsProcessorService } from './processors/CheckExpiredMutingsProcessorService.js'; import { CleanChartsProcessorService } from './processors/CleanChartsProcessorService.js'; import { CleanProcessorService } from './processors/CleanProcessorService.js'; @@ -71,7 +72,8 @@ import { RelationshipProcessorService } from './processors/RelationshipProcessor DeleteFileProcessorService, CleanRemoteFilesProcessorService, RelationshipProcessorService, - WebhookDeliverProcessorService, + UserWebhookDeliverProcessorService, + SystemWebhookDeliverProcessorService, EndedPollNotificationProcessorService, DeliverProcessorService, InboxProcessorService, diff --git a/packages/backend/src/queue/QueueProcessorService.ts b/packages/backend/src/queue/QueueProcessorService.ts index ce999d9cef..169b22c3f5 100644 --- a/packages/backend/src/queue/QueueProcessorService.ts +++ b/packages/backend/src/queue/QueueProcessorService.ts @@ -5,11 +5,13 @@ import { Inject, Injectable, OnApplicationShutdown } from '@nestjs/common'; import * as Bull from 'bullmq'; +import * as Sentry from '@sentry/node'; import type { Config } from '@/config.js'; import { DI } from '@/di-symbols.js'; import type Logger from '@/logger.js'; import { bindThis } from '@/decorators.js'; -import { WebhookDeliverProcessorService } from './processors/WebhookDeliverProcessorService.js'; +import { UserWebhookDeliverProcessorService } from './processors/UserWebhookDeliverProcessorService.js'; +import { SystemWebhookDeliverProcessorService } from './processors/SystemWebhookDeliverProcessorService.js'; import { EndedPollNotificationProcessorService } from './processors/EndedPollNotificationProcessorService.js'; import { DeliverProcessorService } from './processors/DeliverProcessorService.js'; import { InboxProcessorService } from './processors/InboxProcessorService.js'; @@ -75,7 +77,8 @@ export class QueueProcessorService implements OnApplicationShutdown { private dbQueueWorker: Bull.Worker; private deliverQueueWorker: Bull.Worker; private inboxQueueWorker: Bull.Worker; - private webhookDeliverQueueWorker: Bull.Worker; + private userWebhookDeliverQueueWorker: Bull.Worker; + private systemWebhookDeliverQueueWorker: Bull.Worker; private relationshipQueueWorker: Bull.Worker; private objectStorageQueueWorker: Bull.Worker; private endedPollNotificationQueueWorker: Bull.Worker; @@ -85,7 +88,8 @@ export class QueueProcessorService implements OnApplicationShutdown { private config: Config, private queueLoggerService: QueueLoggerService, - private webhookDeliverProcessorService: WebhookDeliverProcessorService, + private userWebhookDeliverProcessorService: UserWebhookDeliverProcessorService, + private systemWebhookDeliverProcessorService: SystemWebhookDeliverProcessorService, private endedPollNotificationProcessorService: EndedPollNotificationProcessorService, private deliverProcessorService: DeliverProcessorService, private inboxProcessorService: InboxProcessorService, @@ -135,199 +139,367 @@ export class QueueProcessorService implements OnApplicationShutdown { } //#region system - this.systemQueueWorker = new Bull.Worker(QUEUE.SYSTEM, (job) => { - switch (job.name) { - case 'tickCharts': return this.tickChartsProcessorService.process(); - case 'resyncCharts': return this.resyncChartsProcessorService.process(); - case 'cleanCharts': return this.cleanChartsProcessorService.process(); - case 'aggregateRetention': return this.aggregateRetentionProcessorService.process(); - case 'checkExpiredMutings': return this.checkExpiredMutingsProcessorService.process(); - case 'clean': return this.cleanProcessorService.process(); - default: throw new Error(`unrecognized job type ${job.name} for system`); - } - }, { - ...baseQueueOptions(this.config, QUEUE.SYSTEM), - autorun: false, - }); + { + const processer = (job: Bull.Job) => { + switch (job.name) { + case 'tickCharts': return this.tickChartsProcessorService.process(); + case 'resyncCharts': return this.resyncChartsProcessorService.process(); + case 'cleanCharts': return this.cleanChartsProcessorService.process(); + case 'aggregateRetention': return this.aggregateRetentionProcessorService.process(); + case 'checkExpiredMutings': return this.checkExpiredMutingsProcessorService.process(); + case 'clean': return this.cleanProcessorService.process(); + default: throw new Error(`unrecognized job type ${job.name} for system`); + } + }; - const systemLogger = this.logger.createSubLogger('system'); + this.systemQueueWorker = new Bull.Worker(QUEUE.SYSTEM, (job) => { + if (this.config.sentryForBackend) { + return Sentry.startSpan({ name: 'Queue: System: ' + job.name }, () => processer(job)); + } else { + return processer(job); + } + }, { + ...baseQueueOptions(this.config, QUEUE.SYSTEM), + autorun: false, + }); - this.systemQueueWorker - .on('active', (job) => systemLogger.debug(`active id=${job.id}`)) - .on('completed', (job, result) => systemLogger.debug(`completed(${result}) id=${job.id}`)) - .on('failed', (job, err) => systemLogger.warn(`failed(${err.stack}) id=${job ? job.id : '-'}`, { job, e: renderError(err) })) - .on('error', (err: Error) => systemLogger.error(`error ${err.stack}`, { e: renderError(err) })) - .on('stalled', (jobId) => systemLogger.warn(`stalled id=${jobId}`)); + const logger = this.logger.createSubLogger('system'); + + this.systemQueueWorker + .on('active', (job) => logger.debug(`active id=${job.id}`)) + .on('completed', (job, result) => logger.debug(`completed(${result}) id=${job.id}`)) + .on('failed', (job, err: Error) => { + logger.error(`failed(${err.stack}) id=${job ? job.id : '-'}`, { job, e: renderError(err) }); + if (config.sentryForBackend) { + Sentry.captureMessage(`Queue: System: ${job?.name ?? '?'}: ${err.message}`, { + level: 'error', + extra: { job, err }, + }); + } + }) + .on('error', (err: Error) => logger.error(`error ${err.stack}`, { e: renderError(err) })) + .on('stalled', (jobId) => logger.warn(`stalled id=${jobId}`)); + } //#endregion //#region db - this.dbQueueWorker = new Bull.Worker(QUEUE.DB, (job) => { - switch (job.name) { - case 'deleteDriveFiles': return this.deleteDriveFilesProcessorService.process(job); - case 'exportCustomEmojis': return this.exportCustomEmojisProcessorService.process(job); - case 'exportNotes': return this.exportNotesProcessorService.process(job); - case 'exportClips': return this.exportClipsProcessorService.process(job); - case 'exportFavorites': return this.exportFavoritesProcessorService.process(job); - case 'exportFollowing': return this.exportFollowingProcessorService.process(job); - case 'exportMuting': return this.exportMutingProcessorService.process(job); - case 'exportBlocking': return this.exportBlockingProcessorService.process(job); - case 'exportUserLists': return this.exportUserListsProcessorService.process(job); - case 'exportAntennas': return this.exportAntennasProcessorService.process(job); - case 'importFollowing': return this.importFollowingProcessorService.process(job); - case 'importFollowingToDb': return this.importFollowingProcessorService.processDb(job); - case 'importMuting': return this.importMutingProcessorService.process(job); - case 'importBlocking': return this.importBlockingProcessorService.process(job); - case 'importBlockingToDb': return this.importBlockingProcessorService.processDb(job); - case 'importUserLists': return this.importUserListsProcessorService.process(job); - case 'importCustomEmojis': return this.importCustomEmojisProcessorService.process(job); - case 'importAntennas': return this.importAntennasProcessorService.process(job); - case 'deleteAccount': return this.deleteAccountProcessorService.process(job); - default: throw new Error(`unrecognized job type ${job.name} for db`); - } - }, { - ...baseQueueOptions(this.config, QUEUE.DB), - autorun: false, - }); + { + const processer = (job: Bull.Job) => { + switch (job.name) { + case 'deleteDriveFiles': return this.deleteDriveFilesProcessorService.process(job); + case 'exportCustomEmojis': return this.exportCustomEmojisProcessorService.process(job); + case 'exportNotes': return this.exportNotesProcessorService.process(job); + case 'exportClips': return this.exportClipsProcessorService.process(job); + case 'exportFavorites': return this.exportFavoritesProcessorService.process(job); + case 'exportFollowing': return this.exportFollowingProcessorService.process(job); + case 'exportMuting': return this.exportMutingProcessorService.process(job); + case 'exportBlocking': return this.exportBlockingProcessorService.process(job); + case 'exportUserLists': return this.exportUserListsProcessorService.process(job); + case 'exportAntennas': return this.exportAntennasProcessorService.process(job); + case 'importFollowing': return this.importFollowingProcessorService.process(job); + case 'importFollowingToDb': return this.importFollowingProcessorService.processDb(job); + case 'importMuting': return this.importMutingProcessorService.process(job); + case 'importBlocking': return this.importBlockingProcessorService.process(job); + case 'importBlockingToDb': return this.importBlockingProcessorService.processDb(job); + case 'importUserLists': return this.importUserListsProcessorService.process(job); + case 'importCustomEmojis': return this.importCustomEmojisProcessorService.process(job); + case 'importAntennas': return this.importAntennasProcessorService.process(job); + case 'deleteAccount': return this.deleteAccountProcessorService.process(job); + default: throw new Error(`unrecognized job type ${job.name} for db`); + } + }; - const dbLogger = this.logger.createSubLogger('db'); + this.dbQueueWorker = new Bull.Worker(QUEUE.DB, (job) => { + if (this.config.sentryForBackend) { + return Sentry.startSpan({ name: 'Queue: DB: ' + job.name }, () => processer(job)); + } else { + return processer(job); + } + }, { + ...baseQueueOptions(this.config, QUEUE.DB), + autorun: false, + }); - this.dbQueueWorker - .on('active', (job) => dbLogger.debug(`active id=${job.id}`)) - .on('completed', (job, result) => dbLogger.debug(`completed(${result}) id=${job.id}`)) - .on('failed', (job, err) => dbLogger.warn(`failed(${err.stack}) id=${job ? job.id : '-'}`, { job, e: renderError(err) })) - .on('error', (err: Error) => dbLogger.error(`error ${err.stack}`, { e: renderError(err) })) - .on('stalled', (jobId) => dbLogger.warn(`stalled id=${jobId}`)); + const logger = this.logger.createSubLogger('db'); + + this.dbQueueWorker + .on('active', (job) => logger.debug(`active id=${job.id}`)) + .on('completed', (job, result) => logger.debug(`completed(${result}) id=${job.id}`)) + .on('failed', (job, err) => { + logger.error(`failed(${err.stack}) id=${job ? job.id : '-'}`, { job, e: renderError(err) }); + if (config.sentryForBackend) { + Sentry.captureMessage(`Queue: DB: ${job?.name ?? '?'}: ${err.message}`, { + level: 'error', + extra: { job, err }, + }); + } + }) + .on('error', (err: Error) => logger.error(`error ${err.stack}`, { e: renderError(err) })) + .on('stalled', (jobId) => logger.warn(`stalled id=${jobId}`)); + } //#endregion //#region deliver - this.deliverQueueWorker = new Bull.Worker(QUEUE.DELIVER, (job) => this.deliverProcessorService.process(job), { - ...baseQueueOptions(this.config, QUEUE.DELIVER), - autorun: false, - concurrency: this.config.deliverJobConcurrency ?? 128, - limiter: { - max: this.config.deliverJobPerSec ?? 128, - duration: 1000, - }, - settings: { - backoffStrategy: httpRelatedBackoff, - }, - }); + { + this.deliverQueueWorker = new Bull.Worker(QUEUE.DELIVER, (job) => { + if (this.config.sentryForBackend) { + return Sentry.startSpan({ name: 'Queue: Deliver' }, () => this.deliverProcessorService.process(job)); + } else { + return this.deliverProcessorService.process(job); + } + }, { + ...baseQueueOptions(this.config, QUEUE.DELIVER), + autorun: false, + concurrency: this.config.deliverJobConcurrency ?? 16, + limiter: { + max: this.config.deliverJobPerSec ?? 1024, + duration: 1000, + }, + settings: { + backoffStrategy: httpRelatedBackoff, + }, + }); - const deliverLogger = this.logger.createSubLogger('deliver'); + const logger = this.logger.createSubLogger('deliver'); - this.deliverQueueWorker - .on('active', (job) => deliverLogger.debug(`active ${getJobInfo(job, true)} to=${job.data.to}`)) - .on('completed', (job, result) => deliverLogger.debug(`completed(${result}) ${getJobInfo(job, true)} to=${job.data.to}`)) - .on('failed', (job, err) => deliverLogger.warn(`failed(${err.stack}) ${getJobInfo(job)} to=${job ? job.data.to : '-'}`)) - .on('error', (err: Error) => deliverLogger.error(`error ${err.stack}`, { e: renderError(err) })) - .on('stalled', (jobId) => deliverLogger.warn(`stalled id=${jobId}`)); + this.deliverQueueWorker + .on('active', (job) => logger.debug(`active ${getJobInfo(job, true)} to=${job.data.to}`)) + .on('completed', (job, result) => logger.debug(`completed(${result}) ${getJobInfo(job, true)} to=${job.data.to}`)) + .on('failed', (job, err) => { + logger.error(`failed(${err.stack}) ${getJobInfo(job)} to=${job ? job.data.to : '-'}`); + if (config.sentryForBackend) { + Sentry.captureMessage(`Queue: Deliver: ${err.message}`, { + level: 'error', + extra: { job, err }, + }); + } + }) + .on('error', (err: Error) => logger.error(`error ${err.stack}`, { e: renderError(err) })) + .on('stalled', (jobId) => logger.warn(`stalled id=${jobId}`)); + } //#endregion //#region inbox - this.inboxQueueWorker = new Bull.Worker(QUEUE.INBOX, (job) => this.inboxProcessorService.process(job), { - ...baseQueueOptions(this.config, QUEUE.INBOX), - autorun: false, - concurrency: this.config.inboxJobConcurrency ?? 16, - limiter: { - max: this.config.inboxJobPerSec ?? 32, - duration: 1000, - }, - settings: { - backoffStrategy: httpRelatedBackoff, - }, - }); + { + this.inboxQueueWorker = new Bull.Worker(QUEUE.INBOX, (job) => { + if (this.config.sentryForBackend) { + return Sentry.startSpan({ name: 'Queue: Inbox' }, () => this.inboxProcessorService.process(job)); + } else { + return this.inboxProcessorService.process(job); + } + }, { + ...baseQueueOptions(this.config, QUEUE.INBOX), + autorun: false, + concurrency: this.config.inboxJobConcurrency ?? 4, + limiter: { + max: this.config.inboxJobPerSec ?? 64, + duration: 1000, + }, + settings: { + backoffStrategy: httpRelatedBackoff, + }, + }); - const inboxLogger = this.logger.createSubLogger('inbox'); + const logger = this.logger.createSubLogger('inbox'); - this.inboxQueueWorker - .on('active', (job) => inboxLogger.debug(`active ${getJobInfo(job, true)}`)) - .on('completed', (job, result) => inboxLogger.debug(`completed(${result}) ${getJobInfo(job, true)}`)) - .on('failed', (job, err) => inboxLogger.warn(`failed(${err.stack}) ${getJobInfo(job)} activity=${job ? (job.data.activity ? job.data.activity.id : 'none') : '-'}`, { job, e: renderError(err) })) - .on('error', (err: Error) => inboxLogger.error(`error ${err.stack}`, { e: renderError(err) })) - .on('stalled', (jobId) => inboxLogger.warn(`stalled id=${jobId}`)); + this.inboxQueueWorker + .on('active', (job) => logger.debug(`active ${getJobInfo(job, true)}`)) + .on('completed', (job, result) => logger.debug(`completed(${result}) ${getJobInfo(job, true)}`)) + .on('failed', (job, err) => { + logger.error(`failed(${err.stack}) ${getJobInfo(job)} activity=${job ? (job.data.activity ? job.data.activity.id : 'none') : '-'}`, { job, e: renderError(err) }); + if (config.sentryForBackend) { + Sentry.captureMessage(`Queue: Inbox: ${err.message}`, { + level: 'error', + extra: { job, err }, + }); + } + }) + .on('error', (err: Error) => logger.error(`error ${err.stack}`, { e: renderError(err) })) + .on('stalled', (jobId) => logger.warn(`stalled id=${jobId}`)); + } //#endregion - //#region webhook deliver - this.webhookDeliverQueueWorker = new Bull.Worker(QUEUE.WEBHOOK_DELIVER, (job) => this.webhookDeliverProcessorService.process(job), { - ...baseQueueOptions(this.config, QUEUE.WEBHOOK_DELIVER), - autorun: false, - concurrency: 64, - limiter: { - max: 64, - duration: 1000, - }, - settings: { - backoffStrategy: httpRelatedBackoff, - }, - }); + //#region user-webhook deliver + { + this.userWebhookDeliverQueueWorker = new Bull.Worker(QUEUE.USER_WEBHOOK_DELIVER, (job) => { + if (this.config.sentryForBackend) { + return Sentry.startSpan({ name: 'Queue: UserWebhookDeliver' }, () => this.userWebhookDeliverProcessorService.process(job)); + } else { + return this.userWebhookDeliverProcessorService.process(job); + } + }, { + ...baseQueueOptions(this.config, QUEUE.USER_WEBHOOK_DELIVER), + autorun: false, + concurrency: 64, + limiter: { + max: 64, + duration: 1000, + }, + settings: { + backoffStrategy: httpRelatedBackoff, + }, + }); - const webhookLogger = this.logger.createSubLogger('webhook'); + const logger = this.logger.createSubLogger('user-webhook'); - this.webhookDeliverQueueWorker - .on('active', (job) => webhookLogger.debug(`active ${getJobInfo(job, true)} to=${job.data.to}`)) - .on('completed', (job, result) => webhookLogger.debug(`completed(${result}) ${getJobInfo(job, true)} to=${job.data.to}`)) - .on('failed', (job, err) => webhookLogger.warn(`failed(${err.stack}) ${getJobInfo(job)} to=${job ? job.data.to : '-'}`)) - .on('error', (err: Error) => webhookLogger.error(`error ${err.stack}`, { e: renderError(err) })) - .on('stalled', (jobId) => webhookLogger.warn(`stalled id=${jobId}`)); + this.userWebhookDeliverQueueWorker + .on('active', (job) => logger.debug(`active ${getJobInfo(job, true)} to=${job.data.to}`)) + .on('completed', (job, result) => logger.debug(`completed(${result}) ${getJobInfo(job, true)} to=${job.data.to}`)) + .on('failed', (job, err) => { + logger.error(`failed(${err.stack}) ${getJobInfo(job)} to=${job ? job.data.to : '-'}`); + if (config.sentryForBackend) { + Sentry.captureMessage(`Queue: UserWebhookDeliver: ${err.message}`, { + level: 'error', + extra: { job, err }, + }); + } + }) + .on('error', (err: Error) => logger.error(`error ${err.stack}`, { e: renderError(err) })) + .on('stalled', (jobId) => logger.warn(`stalled id=${jobId}`)); + } + //#endregion + + //#region system-webhook deliver + { + this.systemWebhookDeliverQueueWorker = new Bull.Worker(QUEUE.SYSTEM_WEBHOOK_DELIVER, (job) => { + if (this.config.sentryForBackend) { + return Sentry.startSpan({ name: 'Queue: SystemWebhookDeliver' }, () => this.systemWebhookDeliverProcessorService.process(job)); + } else { + return this.systemWebhookDeliverProcessorService.process(job); + } + }, { + ...baseQueueOptions(this.config, QUEUE.SYSTEM_WEBHOOK_DELIVER), + autorun: false, + concurrency: 16, + limiter: { + max: 16, + duration: 1000, + }, + settings: { + backoffStrategy: httpRelatedBackoff, + }, + }); + + const logger = this.logger.createSubLogger('system-webhook'); + + this.systemWebhookDeliverQueueWorker + .on('active', (job) => logger.debug(`active ${getJobInfo(job, true)} to=${job.data.to}`)) + .on('completed', (job, result) => logger.debug(`completed(${result}) ${getJobInfo(job, true)} to=${job.data.to}`)) + .on('failed', (job, err) => { + logger.error(`failed(${err.stack}) ${getJobInfo(job)} to=${job ? job.data.to : '-'}`); + if (config.sentryForBackend) { + Sentry.captureMessage(`Queue: SystemWebhookDeliver: ${err.message}`, { + level: 'error', + extra: { job, err }, + }); + } + }) + .on('error', (err: Error) => logger.error(`error ${err.stack}`, { e: renderError(err) })) + .on('stalled', (jobId) => logger.warn(`stalled id=${jobId}`)); + } //#endregion //#region relationship - this.relationshipQueueWorker = new Bull.Worker(QUEUE.RELATIONSHIP, (job) => { - switch (job.name) { - case 'follow': return this.relationshipProcessorService.processFollow(job); - case 'unfollow': return this.relationshipProcessorService.processUnfollow(job); - case 'block': return this.relationshipProcessorService.processBlock(job); - case 'unblock': return this.relationshipProcessorService.processUnblock(job); - default: throw new Error(`unrecognized job type ${job.name} for relationship`); - } - }, { - ...baseQueueOptions(this.config, QUEUE.RELATIONSHIP), - autorun: false, - concurrency: this.config.relationshipJobConcurrency ?? 16, - limiter: { - max: this.config.relationshipJobPerSec ?? 64, - duration: 1000, - }, - }); + { + const processer = (job: Bull.Job) => { + switch (job.name) { + case 'follow': return this.relationshipProcessorService.processFollow(job); + case 'unfollow': return this.relationshipProcessorService.processUnfollow(job); + case 'block': return this.relationshipProcessorService.processBlock(job); + case 'unblock': return this.relationshipProcessorService.processUnblock(job); + default: throw new Error(`unrecognized job type ${job.name} for relationship`); + } + }; - const relationshipLogger = this.logger.createSubLogger('relationship'); + this.relationshipQueueWorker = new Bull.Worker(QUEUE.RELATIONSHIP, (job) => { + if (this.config.sentryForBackend) { + return Sentry.startSpan({ name: 'Queue: Relationship: ' + job.name }, () => processer(job)); + } else { + return processer(job); + } + }, { + ...baseQueueOptions(this.config, QUEUE.RELATIONSHIP), + autorun: false, + concurrency: this.config.relationshipJobConcurrency ?? 16, + limiter: { + max: this.config.relationshipJobPerSec ?? 64, + duration: 1000, + }, + }); - this.relationshipQueueWorker - .on('active', (job) => relationshipLogger.debug(`active id=${job.id}`)) - .on('completed', (job, result) => relationshipLogger.debug(`completed(${result}) id=${job.id}`)) - .on('failed', (job, err) => relationshipLogger.warn(`failed(${err.stack}) id=${job ? job.id : '-'}`, { job, e: renderError(err) })) - .on('error', (err: Error) => relationshipLogger.error(`error ${err.stack}`, { e: renderError(err) })) - .on('stalled', (jobId) => relationshipLogger.warn(`stalled id=${jobId}`)); + const logger = this.logger.createSubLogger('relationship'); + + this.relationshipQueueWorker + .on('active', (job) => logger.debug(`active id=${job.id}`)) + .on('completed', (job, result) => logger.debug(`completed(${result}) id=${job.id}`)) + .on('failed', (job, err) => { + logger.error(`failed(${err.stack}) id=${job ? job.id : '-'}`, { job, e: renderError(err) }); + if (config.sentryForBackend) { + Sentry.captureMessage(`Queue: Relationship: ${job?.name ?? '?'}: ${err.message}`, { + level: 'error', + extra: { job, err }, + }); + } + }) + .on('error', (err: Error) => logger.error(`error ${err.stack}`, { e: renderError(err) })) + .on('stalled', (jobId) => logger.warn(`stalled id=${jobId}`)); + } //#endregion //#region object storage - this.objectStorageQueueWorker = new Bull.Worker(QUEUE.OBJECT_STORAGE, (job) => { - switch (job.name) { - case 'deleteFile': return this.deleteFileProcessorService.process(job); - case 'cleanRemoteFiles': return this.cleanRemoteFilesProcessorService.process(job); - default: throw new Error(`unrecognized job type ${job.name} for objectStorage`); - } - }, { - ...baseQueueOptions(this.config, QUEUE.OBJECT_STORAGE), - autorun: false, - concurrency: 16, - }); + { + const processer = (job: Bull.Job) => { + switch (job.name) { + case 'deleteFile': return this.deleteFileProcessorService.process(job); + case 'cleanRemoteFiles': return this.cleanRemoteFilesProcessorService.process(job); + default: throw new Error(`unrecognized job type ${job.name} for objectStorage`); + } + }; - const objectStorageLogger = this.logger.createSubLogger('objectStorage'); + this.objectStorageQueueWorker = new Bull.Worker(QUEUE.OBJECT_STORAGE, (job) => { + if (this.config.sentryForBackend) { + return Sentry.startSpan({ name: 'Queue: ObjectStorage: ' + job.name }, () => processer(job)); + } else { + return processer(job); + } + }, { + ...baseQueueOptions(this.config, QUEUE.OBJECT_STORAGE), + autorun: false, + concurrency: 16, + }); - this.objectStorageQueueWorker - .on('active', (job) => objectStorageLogger.debug(`active id=${job.id}`)) - .on('completed', (job, result) => objectStorageLogger.debug(`completed(${result}) id=${job.id}`)) - .on('failed', (job, err) => objectStorageLogger.warn(`failed(${err.stack}) id=${job ? job.id : '-'}`, { job, e: renderError(err) })) - .on('error', (err: Error) => objectStorageLogger.error(`error ${err.stack}`, { e: renderError(err) })) - .on('stalled', (jobId) => objectStorageLogger.warn(`stalled id=${jobId}`)); + const logger = this.logger.createSubLogger('objectStorage'); + + this.objectStorageQueueWorker + .on('active', (job) => logger.debug(`active id=${job.id}`)) + .on('completed', (job, result) => logger.debug(`completed(${result}) id=${job.id}`)) + .on('failed', (job, err) => { + logger.error(`failed(${err.stack}) id=${job ? job.id : '-'}`, { job, e: renderError(err) }); + if (config.sentryForBackend) { + Sentry.captureMessage(`Queue: ObjectStorage: ${job?.name ?? '?'}: ${err.message}`, { + level: 'error', + extra: { job, err }, + }); + } + }) + .on('error', (err: Error) => logger.error(`error ${err.stack}`, { e: renderError(err) })) + .on('stalled', (jobId) => logger.warn(`stalled id=${jobId}`)); + } //#endregion //#region ended poll notification - this.endedPollNotificationQueueWorker = new Bull.Worker(QUEUE.ENDED_POLL_NOTIFICATION, (job) => this.endedPollNotificationProcessorService.process(job), { - ...baseQueueOptions(this.config, QUEUE.ENDED_POLL_NOTIFICATION), - autorun: false, - }); + { + this.endedPollNotificationQueueWorker = new Bull.Worker(QUEUE.ENDED_POLL_NOTIFICATION, (job) => { + if (this.config.sentryForBackend) { + return Sentry.startSpan({ name: 'Queue: EndedPollNotification' }, () => this.endedPollNotificationProcessorService.process(job)); + } else { + return this.endedPollNotificationProcessorService.process(job); + } + }, { + ...baseQueueOptions(this.config, QUEUE.ENDED_POLL_NOTIFICATION), + autorun: false, + }); + } //#endregion } @@ -338,7 +510,8 @@ export class QueueProcessorService implements OnApplicationShutdown { this.dbQueueWorker.run(), this.deliverQueueWorker.run(), this.inboxQueueWorker.run(), - this.webhookDeliverQueueWorker.run(), + this.userWebhookDeliverQueueWorker.run(), + this.systemWebhookDeliverQueueWorker.run(), this.relationshipQueueWorker.run(), this.objectStorageQueueWorker.run(), this.endedPollNotificationQueueWorker.run(), @@ -352,7 +525,8 @@ export class QueueProcessorService implements OnApplicationShutdown { this.dbQueueWorker.close(), this.deliverQueueWorker.close(), this.inboxQueueWorker.close(), - this.webhookDeliverQueueWorker.close(), + this.userWebhookDeliverQueueWorker.close(), + this.systemWebhookDeliverQueueWorker.close(), this.relationshipQueueWorker.close(), this.objectStorageQueueWorker.close(), this.endedPollNotificationQueueWorker.close(), diff --git a/packages/backend/src/queue/const.ts b/packages/backend/src/queue/const.ts index 132e916612..67f689b618 100644 --- a/packages/backend/src/queue/const.ts +++ b/packages/backend/src/queue/const.ts @@ -14,7 +14,8 @@ export const QUEUE = { DB: 'db', RELATIONSHIP: 'relationship', OBJECT_STORAGE: 'objectStorage', - WEBHOOK_DELIVER: 'webhookDeliver', + USER_WEBHOOK_DELIVER: 'userWebhookDeliver', + SYSTEM_WEBHOOK_DELIVER: 'systemWebhookDeliver', }; export function baseQueueOptions(config: Config, queueName: typeof QUEUE[keyof typeof QUEUE]): Bull.QueueOptions { diff --git a/packages/backend/src/queue/processors/DeliverProcessorService.ts b/packages/backend/src/queue/processors/DeliverProcessorService.ts index b73195afc3..3bd9187e8b 100644 --- a/packages/backend/src/queue/processors/DeliverProcessorService.ts +++ b/packages/backend/src/queue/processors/DeliverProcessorService.ts @@ -73,25 +73,33 @@ export class DeliverProcessorService { } try { - await this.apRequestService.signedPost(job.data.user, job.data.to, job.data.content, job.data.digest); + const _server = await this.federatedInstanceService.fetch(host); + await this.fetchInstanceMetadataService.fetchInstanceMetadata(_server).then(() => {}); + const server = await this.federatedInstanceService.fetch(host); + + await this.apRequestService.signedPost( + job.data.user, + job.data.to, + job.data.content, + server.httpMessageSignaturesImplementationLevel, + job.data.digest, + job.data.privateKey, + ); // Update stats - this.federatedInstanceService.fetch(host).then(i => { - if (i.isNotResponding) { - this.federatedInstanceService.update(i.id, { - isNotResponding: false, - notRespondingSince: null, - }); - } + if (server.isNotResponding) { + this.federatedInstanceService.update(server.id, { + isNotResponding: false, + notRespondingSince: null, + }); + } - this.fetchInstanceMetadataService.fetchInstanceMetadata(i); - this.apRequestChart.deliverSucc(); - this.federationChart.deliverd(i.host, true); + this.apRequestChart.deliverSucc(); + this.federationChart.deliverd(server.host, true); - if (meta.enableChartsForFederatedInstances) { - this.instanceChart.requestSent(i.host, true); - } - }); + if (meta.enableChartsForFederatedInstances) { + this.instanceChart.requestSent(server.host, true); + } return 'Success'; } catch (res) { @@ -109,6 +117,12 @@ export class DeliverProcessorService { suspensionState: 'autoSuspendedForNotResponding', }); } + } else { + // isNotRespondingがtrueでnotRespondingSinceがnullの場合はnotRespondingSinceをセット + // notRespondingSinceは新たな機能なので、それ以前のデータにはnotRespondingSinceがない場合がある + this.federatedInstanceService.update(i.id, { + notRespondingSince: new Date(), + }); } this.apRequestChart.deliverFail(); diff --git a/packages/backend/src/queue/processors/InboxProcessorService.ts b/packages/backend/src/queue/processors/InboxProcessorService.ts index fa7009f8f5..935c623df1 100644 --- a/packages/backend/src/queue/processors/InboxProcessorService.ts +++ b/packages/backend/src/queue/processors/InboxProcessorService.ts @@ -5,8 +5,8 @@ import { URL } from 'node:url'; import { Injectable } from '@nestjs/common'; -import httpSignature from '@peertube/http-signature'; import * as Bull from 'bullmq'; +import { verifyDraftSignature } from '@misskey-dev/node-http-message-signatures'; import type Logger from '@/logger.js'; import { MetaService } from '@/core/MetaService.js'; import { FederatedInstanceService } from '@/core/FederatedInstanceService.js'; @@ -20,6 +20,7 @@ import type { MiRemoteUser } from '@/models/User.js'; import type { MiUserPublickey } from '@/models/UserPublickey.js'; import { ApDbResolverService } from '@/core/activitypub/ApDbResolverService.js'; import { StatusError } from '@/misc/status-error.js'; +import * as Acct from '@/misc/acct.js'; import { UtilityService } from '@/core/UtilityService.js'; import { ApPersonService } from '@/core/activitypub/models/ApPersonService.js'; import { JsonLdService } from '@/core/activitypub/JsonLdService.js'; @@ -52,8 +53,15 @@ export class InboxProcessorService { @bindThis public async process(job: Bull.Job): Promise { - const signature = job.data.signature; // HTTP-signature + const signature = job.data.signature ? + 'version' in job.data.signature ? job.data.signature.value : job.data.signature + : null; + if (Array.isArray(signature)) { + // RFC 9401はsignatureが配列になるが、とりあえずエラーにする + throw new Error('signature is array'); + } let activity = job.data.activity; + let actorUri = getApId(activity.actor); //#region Log const info = Object.assign({}, activity); @@ -61,7 +69,7 @@ export class InboxProcessorService { this.logger.debug(JSON.stringify(info, null, 2)); //#endregion - const host = this.utilityService.toPuny(new URL(signature.keyId).hostname); + const host = this.utilityService.toPuny(new URL(actorUri).hostname); // ブロックしてたら中断 const meta = await this.metaService.fetch(); @@ -69,69 +77,76 @@ export class InboxProcessorService { return `Blocked request: ${host}`; } - const keyIdLower = signature.keyId.toLowerCase(); - if (keyIdLower.startsWith('acct:')) { - return `Old keyId is no longer supported. ${keyIdLower}`; - } - // HTTP-Signature keyIdを元にDBから取得 - let authUser: { - user: MiRemoteUser; - key: MiUserPublickey | null; - } | null = await this.apDbResolverService.getAuthUserFromKeyId(signature.keyId); + let authUser: Awaited> = null; + let httpSignatureIsValid = null as boolean | null; - // keyIdでわからなければ、activity.actorを元にDBから取得 || activity.actorを元にリモートから取得 - if (authUser == null) { - try { - authUser = await this.apDbResolverService.getAuthUserFromApId(getApId(activity.actor)); - } catch (err) { - // 対象が4xxならスキップ - if (err instanceof StatusError) { - if (!err.isRetryable) { - throw new Bull.UnrecoverableError(`skip: Ignored deleted actors on both ends ${activity.actor} - ${err.statusCode}`); - } - throw new Error(`Error in actor ${activity.actor} - ${err.statusCode}`); + try { + authUser = await this.apDbResolverService.getAuthUserFromApId(actorUri, signature?.keyId); + } catch (err) { + // 対象が4xxならスキップ + if (err instanceof StatusError) { + if (!err.isRetryable) { + throw new Bull.UnrecoverableError(`skip: Ignored deleted actors on both ends ${activity.actor} - ${err.statusCode}`); } + throw new Error(`Error in actor ${activity.actor} - ${err.statusCode}`); } } - // それでもわからなければ終了 - if (authUser == null) { + // authUser.userがnullならスキップ + if (authUser != null && authUser.user == null) { throw new Bull.UnrecoverableError('skip: failed to resolve user'); } - // publicKey がなくても終了 - if (authUser.key == null) { - throw new Bull.UnrecoverableError('skip: failed to resolve user publicKey'); + if (signature != null && authUser != null) { + if (signature.keyId.toLowerCase().startsWith('acct:')) { + this.logger.warn(`Old keyId is no longer supported. lowerKeyId=${signature.keyId.toLowerCase()}`); + } else if (authUser.key != null) { + // keyがなかったらLD Signatureで検証するべき + // HTTP-Signatureの検証 + const errorLogger = (ms: any) => this.logger.error(ms); + httpSignatureIsValid = await verifyDraftSignature(signature, authUser.key.keyPem, errorLogger); + this.logger.debug('Inbox message validation: ', { + userId: authUser.user.id, + userAcct: Acct.toString(authUser.user), + parsedKeyId: signature.keyId, + foundKeyId: authUser.key.keyId, + httpSignatureValid: httpSignatureIsValid, + }); + } } - // HTTP-Signatureの検証 - const httpSignatureValidated = httpSignature.verifySignature(signature, authUser.key.keyPem); - - // また、signatureのsignerは、activity.actorと一致する必要がある - if (!httpSignatureValidated || authUser.user.uri !== activity.actor) { + if ( + authUser == null || + httpSignatureIsValid !== true || + authUser.user.uri !== actorUri // 一応チェック + ) { // 一致しなくても、でもLD-Signatureがありそうならそっちも見る const ldSignature = activity.signature; - if (ldSignature) { + + if (ldSignature && ldSignature.creator) { if (ldSignature.type !== 'RsaSignature2017') { throw new Bull.UnrecoverableError(`skip: unsupported LD-signature type ${ldSignature.type}`); } - // ldSignature.creator: https://example.oom/users/user#main-key - // みたいになっててUserを引っ張れば公開キーも入ることを期待する - if (ldSignature.creator) { - const candicate = ldSignature.creator.replace(/#.*/, ''); - await this.apPersonService.resolvePerson(candicate).catch(() => null); + if (ldSignature.creator.toLowerCase().startsWith('acct:')) { + throw new Bull.UnrecoverableError(`old key not supported ${ldSignature.creator}`); } - // keyIdからLD-Signatureのユーザーを取得 - authUser = await this.apDbResolverService.getAuthUserFromKeyId(ldSignature.creator); + authUser = await this.apDbResolverService.getAuthUserFromApId(actorUri, ldSignature.creator); + if (authUser == null) { - throw new Bull.UnrecoverableError('skip: LD-Signatureのユーザーが取得できませんでした'); + throw new Bull.UnrecoverableError(`skip: LD-Signatureのactorとcreatorが一致しませんでした uri=${actorUri} creator=${ldSignature.creator}`); + } + if (authUser.user == null) { + throw new Bull.UnrecoverableError(`skip: LD-Signatureのユーザーが取得できませんでした uri=${actorUri} creator=${ldSignature.creator}`); + } + // 一応actorチェック + if (authUser.user.uri !== actorUri) { + throw new Bull.UnrecoverableError(`skip: LD-Signature user(${authUser.user.uri}) !== activity.actor(${actorUri})`); } - if (authUser.key == null) { - throw new Bull.UnrecoverableError('skip: LD-SignatureのユーザーはpublicKeyを持っていませんでした'); + throw new Bull.UnrecoverableError(`skip: LD-SignatureのユーザーはpublicKeyを持っていませんでした uri=${actorUri} creator=${ldSignature.creator}`); } const jsonLd = this.jsonLdService.use(); @@ -142,13 +157,27 @@ export class InboxProcessorService { throw new Bull.UnrecoverableError('skip: LD-Signatureの検証に失敗しました'); } + // ブロックしてたら中断 + const ldHost = this.utilityService.extractDbHost(authUser.user.uri); + if (this.utilityService.isBlockedHost(meta.blockedHosts, ldHost)) { + throw new Bull.UnrecoverableError(`Blocked request: ${ldHost}`); + } + // アクティビティを正規化 + // GHSA-2vxv-pv3m-3wvj delete activity.signature; try { activity = await jsonLd.compact(activity) as IActivity; } catch (e) { throw new Bull.UnrecoverableError(`skip: failed to compact activity: ${e}`); } + + // actorが正規化前後で一致しているか確認 + actorUri = getApId(activity.actor); + if (authUser.user.uri !== actorUri) { + throw new Bull.UnrecoverableError(`skip: LD-Signature user(${authUser.user.uri}) !== activity(after normalization).actor(${actorUri})`); + } + // TODO: 元のアクティビティと非互換な形に正規化される場合は転送をスキップする // https://github.com/mastodon/mastodon/blob/664b0ca/app/services/activitypub/process_collection_service.rb#L24-L29 activity.signature = ldSignature; @@ -158,19 +187,8 @@ export class InboxProcessorService { delete compactedInfo['@context']; this.logger.debug(`compacted: ${JSON.stringify(compactedInfo, null, 2)}`); //#endregion - - // もう一度actorチェック - if (authUser.user.uri !== activity.actor) { - throw new Bull.UnrecoverableError(`skip: LD-Signature user(${authUser.user.uri}) !== activity.actor(${activity.actor})`); - } - - // ブロックしてたら中断 - const ldHost = this.utilityService.extractDbHost(authUser.user.uri); - if (this.utilityService.isBlockedHost(meta.blockedHosts, ldHost)) { - throw new Bull.UnrecoverableError(`Blocked request: ${ldHost}`); - } } else { - throw new Bull.UnrecoverableError(`skip: http-signature verification failed and no LD-Signature. keyId=${signature.keyId}`); + throw new Bull.UnrecoverableError(`skip: http-signature verification failed and no LD-Signature. http_signature_keyId=${signature?.keyId}`); } } diff --git a/packages/backend/src/queue/processors/SystemWebhookDeliverProcessorService.ts b/packages/backend/src/queue/processors/SystemWebhookDeliverProcessorService.ts new file mode 100644 index 0000000000..f6bef52684 --- /dev/null +++ b/packages/backend/src/queue/processors/SystemWebhookDeliverProcessorService.ts @@ -0,0 +1,87 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { Inject, Injectable } from '@nestjs/common'; +import * as Bull from 'bullmq'; +import { DI } from '@/di-symbols.js'; +import type { SystemWebhooksRepository } from '@/models/_.js'; +import type { Config } from '@/config.js'; +import type Logger from '@/logger.js'; +import { HttpRequestService } from '@/core/HttpRequestService.js'; +import { StatusError } from '@/misc/status-error.js'; +import { bindThis } from '@/decorators.js'; +import { QueueLoggerService } from '../QueueLoggerService.js'; +import { SystemWebhookDeliverJobData } from '../types.js'; + +@Injectable() +export class SystemWebhookDeliverProcessorService { + private logger: Logger; + + constructor( + @Inject(DI.config) + private config: Config, + + @Inject(DI.systemWebhooksRepository) + private systemWebhooksRepository: SystemWebhooksRepository, + + private httpRequestService: HttpRequestService, + private queueLoggerService: QueueLoggerService, + ) { + this.logger = this.queueLoggerService.logger.createSubLogger('webhook'); + } + + @bindThis + public async process(job: Bull.Job): Promise { + try { + this.logger.debug(`delivering ${job.data.webhookId}`); + + const res = await this.httpRequestService.send(job.data.to, { + method: 'POST', + headers: { + 'User-Agent': 'Misskey-Hooks', + 'X-Misskey-Host': this.config.host, + 'X-Misskey-Hook-Id': job.data.webhookId, + 'X-Misskey-Hook-Secret': job.data.secret, + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + server: this.config.url, + hookId: job.data.webhookId, + eventId: job.data.eventId, + createdAt: job.data.createdAt, + type: job.data.type, + body: job.data.content, + }), + }); + + this.systemWebhooksRepository.update({ id: job.data.webhookId }, { + latestSentAt: new Date(), + latestStatus: res.status, + }); + + return 'Success'; + } catch (res) { + this.logger.error(res as Error); + + this.systemWebhooksRepository.update({ id: job.data.webhookId }, { + latestSentAt: new Date(), + latestStatus: res instanceof StatusError ? res.statusCode : 1, + }); + + if (res instanceof StatusError) { + // 4xx + if (!res.isRetryable) { + throw new Bull.UnrecoverableError(`${res.statusCode} ${res.statusMessage}`); + } + + // 5xx etc. + throw new Error(`${res.statusCode} ${res.statusMessage}`); + } else { + // DNS error, socket error, timeout ... + throw res; + } + } + } +} diff --git a/packages/backend/src/queue/processors/WebhookDeliverProcessorService.ts b/packages/backend/src/queue/processors/UserWebhookDeliverProcessorService.ts similarity index 92% rename from packages/backend/src/queue/processors/WebhookDeliverProcessorService.ts rename to packages/backend/src/queue/processors/UserWebhookDeliverProcessorService.ts index 8c260c0137..9ec630ef70 100644 --- a/packages/backend/src/queue/processors/WebhookDeliverProcessorService.ts +++ b/packages/backend/src/queue/processors/UserWebhookDeliverProcessorService.ts @@ -13,10 +13,10 @@ import { HttpRequestService } from '@/core/HttpRequestService.js'; import { StatusError } from '@/misc/status-error.js'; import { bindThis } from '@/decorators.js'; import { QueueLoggerService } from '../QueueLoggerService.js'; -import type { WebhookDeliverJobData } from '../types.js'; +import { UserWebhookDeliverJobData } from '../types.js'; @Injectable() -export class WebhookDeliverProcessorService { +export class UserWebhookDeliverProcessorService { private logger: Logger; constructor( @@ -33,7 +33,7 @@ export class WebhookDeliverProcessorService { } @bindThis - public async process(job: Bull.Job): Promise { + public async process(job: Bull.Job): Promise { try { this.logger.debug(`delivering ${job.data.webhookId}`); diff --git a/packages/backend/src/queue/types.ts b/packages/backend/src/queue/types.ts index ce57ba745e..f2466f2e3d 100644 --- a/packages/backend/src/queue/types.ts +++ b/packages/backend/src/queue/types.ts @@ -9,7 +9,24 @@ import type { MiNote } from '@/models/Note.js'; import type { MiUser } from '@/models/User.js'; import type { MiWebhook } from '@/models/Webhook.js'; import type { IActivity } from '@/core/activitypub/type.js'; -import type httpSignature from '@peertube/http-signature'; +import type { ParsedSignature, PrivateKeyWithPem } from '@misskey-dev/node-http-message-signatures'; + +/** + * @peertube/http-signature 時代の古いデータにも対応しておく + * TODO: 2026年ぐらいには消す + */ +export interface OldParsedSignature { + scheme: 'Signature'; + params: { + keyId: string; + algorithm: string; + headers: string[]; + signature: string; + }; + signingString: string; + algorithm: string; + keyId: string; +} export type DeliverJobData = { /** Actor */ @@ -22,11 +39,13 @@ export type DeliverJobData = { to: string; /** whether it is sharedInbox */ isSharedInbox: boolean; + /** force to use main (rsa) key */ + privateKey?: PrivateKeyWithPem; }; export type InboxJobData = { activity: IActivity; - signature: httpSignature.IParsedSignature; + signature: ParsedSignature | OldParsedSignature | null; }; export type RelationshipJobData = { @@ -106,7 +125,17 @@ export type EndedPollNotificationJobData = { noteId: MiNote['id']; }; -export type WebhookDeliverJobData = { +export type SystemWebhookDeliverJobData = { + type: string; + content: unknown; + webhookId: MiWebhook['id']; + to: string; + secret: string; + createdAt: number; + eventId: string; +}; + +export type UserWebhookDeliverJobData = { type: string; content: unknown; webhookId: MiWebhook['id']; diff --git a/packages/backend/src/server/ActivityPubServerService.ts b/packages/backend/src/server/ActivityPubServerService.ts index 3255d64621..753eaad047 100644 --- a/packages/backend/src/server/ActivityPubServerService.ts +++ b/packages/backend/src/server/ActivityPubServerService.ts @@ -3,11 +3,10 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import * as crypto from 'node:crypto'; import { IncomingMessage } from 'node:http'; import { Inject, Injectable } from '@nestjs/common'; import fastifyAccepts from '@fastify/accepts'; -import httpSignature from '@peertube/http-signature'; +import { verifyDigestHeader, parseRequestSignature } from '@misskey-dev/node-http-message-signatures'; import { Brackets, In, IsNull, LessThan, Not } from 'typeorm'; import accepts from 'accepts'; import vary from 'vary'; @@ -31,12 +30,17 @@ import { IActivity } from '@/core/activitypub/type.js'; import { isQuote, isRenote } from '@/misc/is-renote.js'; import type { FastifyInstance, FastifyRequest, FastifyReply, FastifyPluginOptions, FastifyBodyParser } from 'fastify'; import type { FindOptionsWhere } from 'typeorm'; +import { LoggerService } from '@/core/LoggerService.js'; +import Logger from '@/logger.js'; const ACTIVITY_JSON = 'application/activity+json; charset=utf-8'; const LD_JSON = 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"; charset=utf-8'; @Injectable() export class ActivityPubServerService { + private logger: Logger; + private inboxLogger: Logger; + constructor( @Inject(DI.config) private config: Config, @@ -71,8 +75,11 @@ export class ActivityPubServerService { private queueService: QueueService, private userKeypairService: UserKeypairService, private queryService: QueryService, + private loggerService: LoggerService, ) { //this.createServer = this.createServer.bind(this); + this.logger = this.loggerService.getLogger('server-ap', 'gray'); + this.inboxLogger = this.logger.createSubLogger('inbox', 'gray'); } @bindThis @@ -100,70 +107,44 @@ export class ActivityPubServerService { } @bindThis - private inbox(request: FastifyRequest, reply: FastifyReply) { - let signature; + private async inbox(request: FastifyRequest, reply: FastifyReply) { + if (request.body == null) { + this.inboxLogger.warn('request body is empty'); + reply.code(400); + return; + } + + let signature: ReturnType; + + const verifyDigest = await verifyDigestHeader(request.raw, request.rawBody || '', true); + if (verifyDigest !== true) { + this.inboxLogger.warn('digest verification failed'); + reply.code(401); + return; + } try { - signature = httpSignature.parseRequest(request.raw, { 'headers': [] }); - } catch (e) { + signature = parseRequestSignature(request.raw, { + requiredInputs: { + draft: ['(request-target)', 'digest', 'host', 'date'], + }, + }); + } catch (err) { + this.inboxLogger.warn('signature header parsing failed', { err }); + + if (typeof request.body === 'object' && 'signature' in request.body) { + // LD SignatureがあればOK + this.queueService.inbox(request.body as IActivity, null); + reply.code(202); + return; + } + + this.inboxLogger.warn('signature header parsing failed and LD signature not found'); reply.code(401); return; } - if (signature.params.headers.indexOf('host') === -1 - || request.headers.host !== this.config.host) { - // Host not specified or not match. - reply.code(401); - return; - } - - if (signature.params.headers.indexOf('digest') === -1) { - // Digest not found. - reply.code(401); - } else { - const digest = request.headers.digest; - - if (typeof digest !== 'string') { - // Huh? - reply.code(401); - return; - } - - const re = /^([a-zA-Z0-9\-]+)=(.+)$/; - const match = digest.match(re); - - if (match == null) { - // Invalid digest - reply.code(401); - return; - } - - const algo = match[1].toUpperCase(); - const digestValue = match[2]; - - if (algo !== 'SHA-256') { - // Unsupported digest algorithm - reply.code(401); - return; - } - - if (request.rawBody == null) { - // Bad request - reply.code(400); - return; - } - - const hash = crypto.createHash('sha256').update(request.rawBody).digest('base64'); - - if (hash !== digestValue) { - // Invalid digest - reply.code(401); - return; - } - } - this.queueService.inbox(request.body as IActivity, signature); - reply.code(202); } @@ -640,7 +621,7 @@ export class ActivityPubServerService { if (this.userEntityService.isLocalUser(user)) { reply.header('Cache-Control', 'public, max-age=180'); this.setResponseType(request, reply); - return (this.apRendererService.addContext(this.apRendererService.renderKey(user, keypair))); + return (this.apRendererService.addContext(this.apRendererService.renderKey(user, keypair.publicKey))); } else { reply.code(400); return; diff --git a/packages/backend/src/server/FileServerService.ts b/packages/backend/src/server/FileServerService.ts index 9db3aa1bfb..77a637d895 100644 --- a/packages/backend/src/server/FileServerService.ts +++ b/packages/backend/src/server/FileServerService.ts @@ -53,7 +53,7 @@ export class FileServerService { private internalStorageService: InternalStorageService, private loggerService: LoggerService, ) { - this.logger = this.loggerService.getLogger('server', 'gray', false); + this.logger = this.loggerService.getLogger('server', 'gray'); //this.createServer = this.createServer.bind(this); } diff --git a/packages/backend/src/server/NodeinfoServerService.ts b/packages/backend/src/server/NodeinfoServerService.ts index cc18997fdc..c0f8084768 100644 --- a/packages/backend/src/server/NodeinfoServerService.ts +++ b/packages/backend/src/server/NodeinfoServerService.ts @@ -94,6 +94,13 @@ export class NodeinfoServerService { localComments: 0, }, metadata: { + /** + * '00': Draft, RSA only + * '01': Draft, Ed25519 suported + * '11': RFC 9421, Ed25519 supported + */ + httpMessageSignaturesImplementationLevel: '01', + nodeName: meta.name, nodeDescription: meta.description, nodeAdmins: [{ diff --git a/packages/backend/src/server/ServerService.ts b/packages/backend/src/server/ServerService.ts index 3572f16627..9c849480f2 100644 --- a/packages/backend/src/server/ServerService.ts +++ b/packages/backend/src/server/ServerService.ts @@ -68,7 +68,7 @@ export class ServerService implements OnApplicationShutdown { private loggerService: LoggerService, private oauth2ProviderService: OAuth2ProviderService, ) { - this.logger = this.loggerService.getLogger('server', 'gray', false); + this.logger = this.loggerService.getLogger('server', 'gray'); } @bindThis diff --git a/packages/backend/src/server/api/ApiCallService.ts b/packages/backend/src/server/api/ApiCallService.ts index 271ef80554..47f64f6609 100644 --- a/packages/backend/src/server/api/ApiCallService.ts +++ b/packages/backend/src/server/api/ApiCallService.ts @@ -73,6 +73,16 @@ export class ApiCallService implements OnApplicationShutdown { reply.header('WWW-Authenticate', `Bearer realm="Misskey", error="insufficient_scope", error_description="${err.message}"`); } statusCode = statusCode ?? 403; + } else if (err.code === 'RATE_LIMIT_EXCEEDED') { + const info: unknown = err.info; + const unixEpochInSeconds = Date.now(); + if (typeof(info) === 'object' && info && 'resetMs' in info && typeof(info.resetMs) === 'number') { + const cooldownInSeconds = Math.ceil((info.resetMs - unixEpochInSeconds) / 1000); + // もしかするとマイナスになる可能性がなくはないのでマイナスだったら0にしておく + reply.header('Retry-After', Math.max(cooldownInSeconds, 0).toString(10)); + } else { + this.logger.warn(`rate limit information has unexpected type ${typeof(err.info?.reset)}`); + } } else if (!statusCode) { statusCode = 500; } @@ -93,7 +103,7 @@ export class ApiCallService implements OnApplicationShutdown { } } - #onExecError(ep: IEndpoint, data: any, err: Error): void { + #onExecError(ep: IEndpoint, data: any, err: Error, userId?: MiUser['id']): void { if (err instanceof ApiError || err instanceof AuthenticationError) { throw err; } else { @@ -108,10 +118,13 @@ export class ApiCallService implements OnApplicationShutdown { id: errId, }, }); - console.error(err, errId); if (this.config.sentryForBackend) { Sentry.captureMessage(`Internal error occurred in ${ep.name}: ${err.message}`, { + level: 'error', + user: { + id: userId, + }, extra: { ep: ep.name, ps: data, @@ -305,12 +318,17 @@ export class ApiCallService implements OnApplicationShutdown { if (factor > 0) { // Rate limit await this.rateLimiterService.limit(limit as IEndpointMeta['limit'] & { key: NonNullable }, limitActor, factor).catch(err => { - throw new ApiError({ - message: 'Rate limit exceeded. Please try again later.', - code: 'RATE_LIMIT_EXCEEDED', - id: 'd5826d14-3982-4d2e-8011-b9e9f02499ef', - httpStatusCode: 429, - }); + if ('info' in err) { + // errはLimiter.LimiterInfoであることが期待される + throw new ApiError({ + message: 'Rate limit exceeded. Please try again later.', + code: 'RATE_LIMIT_EXCEEDED', + id: 'd5826d14-3982-4d2e-8011-b9e9f02499ef', + httpStatusCode: 429, + }, err.info); + } else { + throw new TypeError('information must be a rate-limiter information.'); + } }); } } @@ -410,9 +428,13 @@ export class ApiCallService implements OnApplicationShutdown { // API invoking if (this.config.sentryForBackend) { - return await Sentry.startSpan({ name: 'API: ' + ep.name }, () => ep.exec(data, user, token, file, request.ip, request.headers).catch((err: Error) => this.#onExecError(ep, data, err))); + return await Sentry.startSpan({ + name: 'API: ' + ep.name, + }, () => ep.exec(data, user, token, file, request.ip, request.headers) + .catch((err: Error) => this.#onExecError(ep, data, err, user?.id))); } else { - return await ep.exec(data, user, token, file, request.ip, request.headers).catch((err: Error) => this.#onExecError(ep, data, err)); + return await ep.exec(data, user, token, file, request.ip, request.headers) + .catch((err: Error) => this.#onExecError(ep, data, err, user?.id)); } } diff --git a/packages/backend/src/server/api/EndpointsModule.ts b/packages/backend/src/server/api/EndpointsModule.ts index c645f4bcc6..41576bedaa 100644 --- a/packages/backend/src/server/api/EndpointsModule.ts +++ b/packages/backend/src/server/api/EndpointsModule.ts @@ -6,8 +6,13 @@ import { Module } from '@nestjs/common'; import { CoreModule } from '@/core/CoreModule.js'; -import * as ep___admin_meta from './endpoints/admin/meta.js'; +import * as ep___admin_abuseReport_notificationRecipient_list from '@/server/api/endpoints/admin/abuse-report/notification-recipient/list.js'; +import * as ep___admin_abuseReport_notificationRecipient_show from '@/server/api/endpoints/admin/abuse-report/notification-recipient/show.js'; +import * as ep___admin_abuseReport_notificationRecipient_create from '@/server/api/endpoints/admin/abuse-report/notification-recipient/create.js'; +import * as ep___admin_abuseReport_notificationRecipient_update from '@/server/api/endpoints/admin/abuse-report/notification-recipient/update.js'; +import * as ep___admin_abuseReport_notificationRecipient_delete from '@/server/api/endpoints/admin/abuse-report/notification-recipient/delete.js'; import * as ep___admin_abuseUserReports from './endpoints/admin/abuse-user-reports.js'; +import * as ep___admin_meta from './endpoints/admin/meta.js'; import * as ep___admin_accounts_create from './endpoints/admin/accounts/create.js'; import * as ep___admin_accounts_delete from './endpoints/admin/accounts/delete.js'; import * as ep___admin_accounts_findByEmail from './endpoints/admin/accounts/find-by-email.js'; @@ -82,6 +87,11 @@ import * as ep___admin_roles_assign from './endpoints/admin/roles/assign.js'; import * as ep___admin_roles_unassign from './endpoints/admin/roles/unassign.js'; import * as ep___admin_roles_updateDefaultPolicies from './endpoints/admin/roles/update-default-policies.js'; import * as ep___admin_roles_users from './endpoints/admin/roles/users.js'; +import * as ep___admin_systemWebhook_create from './endpoints/admin/system-webhook/create.js'; +import * as ep___admin_systemWebhook_delete from './endpoints/admin/system-webhook/delete.js'; +import * as ep___admin_systemWebhook_list from './endpoints/admin/system-webhook/list.js'; +import * as ep___admin_systemWebhook_show from './endpoints/admin/system-webhook/show.js'; +import * as ep___admin_systemWebhook_update from './endpoints/admin/system-webhook/update.js'; import * as ep___announcements from './endpoints/announcements.js'; import * as ep___announcements_show from './endpoints/announcements/show.js'; import * as ep___antennas_create from './endpoints/antennas/create.js'; @@ -381,6 +391,11 @@ import type { Provider } from '@nestjs/common'; const $admin_meta: Provider = { provide: 'ep:admin/meta', useClass: ep___admin_meta.default }; const $admin_abuseUserReports: Provider = { provide: 'ep:admin/abuse-user-reports', useClass: ep___admin_abuseUserReports.default }; +const $admin_abuseReport_notificationRecipient_list: Provider = { provide: 'ep:admin/abuse-report/notification-recipient/list', useClass: ep___admin_abuseReport_notificationRecipient_list.default }; +const $admin_abuseReport_notificationRecipient_show: Provider = { provide: 'ep:admin/abuse-report/notification-recipient/show', useClass: ep___admin_abuseReport_notificationRecipient_show.default }; +const $admin_abuseReport_notificationRecipient_create: Provider = { provide: 'ep:admin/abuse-report/notification-recipient/create', useClass: ep___admin_abuseReport_notificationRecipient_create.default }; +const $admin_abuseReport_notificationRecipient_update: Provider = { provide: 'ep:admin/abuse-report/notification-recipient/update', useClass: ep___admin_abuseReport_notificationRecipient_update.default }; +const $admin_abuseReport_notificationRecipient_delete: Provider = { provide: 'ep:admin/abuse-report/notification-recipient/delete', useClass: ep___admin_abuseReport_notificationRecipient_delete.default }; const $admin_accounts_create: Provider = { provide: 'ep:admin/accounts/create', useClass: ep___admin_accounts_create.default }; const $admin_accounts_delete: Provider = { provide: 'ep:admin/accounts/delete', useClass: ep___admin_accounts_delete.default }; const $admin_accounts_findByEmail: Provider = { provide: 'ep:admin/accounts/find-by-email', useClass: ep___admin_accounts_findByEmail.default }; @@ -455,6 +470,11 @@ const $admin_roles_assign: Provider = { provide: 'ep:admin/roles/assign', useCla const $admin_roles_unassign: Provider = { provide: 'ep:admin/roles/unassign', useClass: ep___admin_roles_unassign.default }; const $admin_roles_updateDefaultPolicies: Provider = { provide: 'ep:admin/roles/update-default-policies', useClass: ep___admin_roles_updateDefaultPolicies.default }; const $admin_roles_users: Provider = { provide: 'ep:admin/roles/users', useClass: ep___admin_roles_users.default }; +const $admin_systemWebhook_create: Provider = { provide: 'ep:admin/system-webhook/create', useClass: ep___admin_systemWebhook_create.default }; +const $admin_systemWebhook_delete: Provider = { provide: 'ep:admin/system-webhook/delete', useClass: ep___admin_systemWebhook_delete.default }; +const $admin_systemWebhook_list: Provider = { provide: 'ep:admin/system-webhook/list', useClass: ep___admin_systemWebhook_list.default }; +const $admin_systemWebhook_show: Provider = { provide: 'ep:admin/system-webhook/show', useClass: ep___admin_systemWebhook_show.default }; +const $admin_systemWebhook_update: Provider = { provide: 'ep:admin/system-webhook/update', useClass: ep___admin_systemWebhook_update.default }; const $announcements: Provider = { provide: 'ep:announcements', useClass: ep___announcements.default }; const $announcements_show: Provider = { provide: 'ep:announcements/show', useClass: ep___announcements_show.default }; const $antennas_create: Provider = { provide: 'ep:antennas/create', useClass: ep___antennas_create.default }; @@ -758,6 +778,11 @@ const $reversi_verify: Provider = { provide: 'ep:reversi/verify', useClass: ep__ ApiLoggerService, $admin_meta, $admin_abuseUserReports, + $admin_abuseReport_notificationRecipient_list, + $admin_abuseReport_notificationRecipient_show, + $admin_abuseReport_notificationRecipient_create, + $admin_abuseReport_notificationRecipient_update, + $admin_abuseReport_notificationRecipient_delete, $admin_accounts_create, $admin_accounts_delete, $admin_accounts_findByEmail, @@ -832,6 +857,11 @@ const $reversi_verify: Provider = { provide: 'ep:reversi/verify', useClass: ep__ $admin_roles_unassign, $admin_roles_updateDefaultPolicies, $admin_roles_users, + $admin_systemWebhook_create, + $admin_systemWebhook_delete, + $admin_systemWebhook_list, + $admin_systemWebhook_show, + $admin_systemWebhook_update, $announcements, $announcements_show, $antennas_create, @@ -1129,6 +1159,11 @@ const $reversi_verify: Provider = { provide: 'ep:reversi/verify', useClass: ep__ exports: [ $admin_meta, $admin_abuseUserReports, + $admin_abuseReport_notificationRecipient_list, + $admin_abuseReport_notificationRecipient_show, + $admin_abuseReport_notificationRecipient_create, + $admin_abuseReport_notificationRecipient_update, + $admin_abuseReport_notificationRecipient_delete, $admin_accounts_create, $admin_accounts_delete, $admin_accounts_findByEmail, @@ -1203,6 +1238,11 @@ const $reversi_verify: Provider = { provide: 'ep:reversi/verify', useClass: ep__ $admin_roles_unassign, $admin_roles_updateDefaultPolicies, $admin_roles_users, + $admin_systemWebhook_create, + $admin_systemWebhook_delete, + $admin_systemWebhook_list, + $admin_systemWebhook_show, + $admin_systemWebhook_update, $announcements, $announcements_show, $antennas_create, diff --git a/packages/backend/src/server/api/RateLimiterService.ts b/packages/backend/src/server/api/RateLimiterService.ts index 0439cdfe5e..52d73baa0a 100644 --- a/packages/backend/src/server/api/RateLimiterService.ts +++ b/packages/backend/src/server/api/RateLimiterService.ts @@ -32,11 +32,13 @@ export class RateLimiterService { @bindThis public limit(limitation: IEndpointMeta['limit'] & { key: NonNullable }, actor: string, factor = 1) { - return new Promise((ok, reject) => { - if (this.disabled) ok(); + { + if (this.disabled) { + return Promise.resolve(); + } // Short-term limit - const min = (): void => { + const min = new Promise((ok, reject) => { const minIntervalLimiter = new Limiter({ id: `${actor}:${limitation.key}:min`, duration: limitation.minInterval! * factor, @@ -46,25 +48,25 @@ export class RateLimiterService { minIntervalLimiter.get((err, info) => { if (err) { - return reject('ERR'); + return reject({ code: 'ERR', info }); } this.logger.debug(`${actor} ${limitation.key} min remaining: ${info.remaining}`); if (info.remaining === 0) { - reject('BRIEF_REQUEST_INTERVAL'); + return reject({ code: 'BRIEF_REQUEST_INTERVAL', info }); } else { if (hasLongTermLimit) { - max(); + return max.then(ok, reject); } else { - ok(); + return ok(); } } }); - }; + }); // Long term limit - const max = (): void => { + const max = new Promise((ok, reject) => { const limiter = new Limiter({ id: `${actor}:${limitation.key}`, duration: limitation.duration! * factor, @@ -74,18 +76,18 @@ export class RateLimiterService { limiter.get((err, info) => { if (err) { - return reject('ERR'); + return reject({ code: 'ERR', info }); } this.logger.debug(`${actor} ${limitation.key} max remaining: ${info.remaining}`); if (info.remaining === 0) { - reject('RATE_LIMIT_EXCEEDED'); + return reject({ code: 'RATE_LIMIT_EXCEEDED', info }); } else { - ok(); + return ok(); } }); - }; + }); const hasShortTermLimit = typeof limitation.minInterval === 'number'; @@ -94,12 +96,12 @@ export class RateLimiterService { typeof limitation.max === 'number'; if (hasShortTermLimit) { - min(); + return min; } else if (hasLongTermLimit) { - max(); + return max; } else { - ok(); + return Promise.resolve(); } - }); + } } } diff --git a/packages/backend/src/server/api/endpoints.ts b/packages/backend/src/server/api/endpoints.ts index a38c62f35a..3dfb7fdad4 100644 --- a/packages/backend/src/server/api/endpoints.ts +++ b/packages/backend/src/server/api/endpoints.ts @@ -6,8 +6,18 @@ import { permissions } from 'misskey-js'; import type { KeyOf, Schema } from '@/misc/json-schema.js'; -import * as ep___admin_meta from './endpoints/admin/meta.js'; +import * as ep___admin_abuseReport_notificationRecipient_list + from '@/server/api/endpoints/admin/abuse-report/notification-recipient/list.js'; +import * as ep___admin_abuseReport_notificationRecipient_show + from '@/server/api/endpoints/admin/abuse-report/notification-recipient/show.js'; +import * as ep___admin_abuseReport_notificationRecipient_create + from '@/server/api/endpoints/admin/abuse-report/notification-recipient/create.js'; +import * as ep___admin_abuseReport_notificationRecipient_update + from '@/server/api/endpoints/admin/abuse-report/notification-recipient/update.js'; +import * as ep___admin_abuseReport_notificationRecipient_delete + from '@/server/api/endpoints/admin/abuse-report/notification-recipient/delete.js'; import * as ep___admin_abuseUserReports from './endpoints/admin/abuse-user-reports.js'; +import * as ep___admin_meta from './endpoints/admin/meta.js'; import * as ep___admin_accounts_create from './endpoints/admin/accounts/create.js'; import * as ep___admin_accounts_delete from './endpoints/admin/accounts/delete.js'; import * as ep___admin_accounts_findByEmail from './endpoints/admin/accounts/find-by-email.js'; @@ -44,7 +54,8 @@ import * as ep___admin_emoji_setCategoryBulk from './endpoints/admin/emoji/set-c import * as ep___admin_emoji_setLicenseBulk from './endpoints/admin/emoji/set-license-bulk.js'; import * as ep___admin_emoji_update from './endpoints/admin/emoji/update.js'; import * as ep___admin_federation_deleteAllFiles from './endpoints/admin/federation/delete-all-files.js'; -import * as ep___admin_federation_refreshRemoteInstanceMetadata from './endpoints/admin/federation/refresh-remote-instance-metadata.js'; +import * as ep___admin_federation_refreshRemoteInstanceMetadata + from './endpoints/admin/federation/refresh-remote-instance-metadata.js'; import * as ep___admin_federation_removeAllFollowing from './endpoints/admin/federation/remove-all-following.js'; import * as ep___admin_federation_updateInstance from './endpoints/admin/federation/update-instance.js'; import * as ep___admin_getIndexStats from './endpoints/admin/get-index-stats.js'; @@ -82,6 +93,11 @@ import * as ep___admin_roles_assign from './endpoints/admin/roles/assign.js'; import * as ep___admin_roles_unassign from './endpoints/admin/roles/unassign.js'; import * as ep___admin_roles_updateDefaultPolicies from './endpoints/admin/roles/update-default-policies.js'; import * as ep___admin_roles_users from './endpoints/admin/roles/users.js'; +import * as ep___admin_systemWebhook_create from './endpoints/admin/system-webhook/create.js'; +import * as ep___admin_systemWebhook_delete from './endpoints/admin/system-webhook/delete.js'; +import * as ep___admin_systemWebhook_list from './endpoints/admin/system-webhook/list.js'; +import * as ep___admin_systemWebhook_show from './endpoints/admin/system-webhook/show.js'; +import * as ep___admin_systemWebhook_update from './endpoints/admin/system-webhook/update.js'; import * as ep___announcements from './endpoints/announcements.js'; import * as ep___announcements_show from './endpoints/announcements/show.js'; import * as ep___antennas_create from './endpoints/antennas/create.js'; @@ -379,6 +395,11 @@ import * as ep___reversi_verify from './endpoints/reversi/verify.js'; const eps = [ ['admin/meta', ep___admin_meta], ['admin/abuse-user-reports', ep___admin_abuseUserReports], + ['admin/abuse-report/notification-recipient/list', ep___admin_abuseReport_notificationRecipient_list], + ['admin/abuse-report/notification-recipient/show', ep___admin_abuseReport_notificationRecipient_show], + ['admin/abuse-report/notification-recipient/create', ep___admin_abuseReport_notificationRecipient_create], + ['admin/abuse-report/notification-recipient/update', ep___admin_abuseReport_notificationRecipient_update], + ['admin/abuse-report/notification-recipient/delete', ep___admin_abuseReport_notificationRecipient_delete], ['admin/accounts/create', ep___admin_accounts_create], ['admin/accounts/delete', ep___admin_accounts_delete], ['admin/accounts/find-by-email', ep___admin_accounts_findByEmail], @@ -453,6 +474,11 @@ const eps = [ ['admin/roles/unassign', ep___admin_roles_unassign], ['admin/roles/update-default-policies', ep___admin_roles_updateDefaultPolicies], ['admin/roles/users', ep___admin_roles_users], + ['admin/system-webhook/create', ep___admin_systemWebhook_create], + ['admin/system-webhook/delete', ep___admin_systemWebhook_delete], + ['admin/system-webhook/list', ep___admin_systemWebhook_list], + ['admin/system-webhook/show', ep___admin_systemWebhook_show], + ['admin/system-webhook/update', ep___admin_systemWebhook_update], ['announcements', ep___announcements], ['announcements/show', ep___announcements_show], ['antennas/create', ep___antennas_create], @@ -873,8 +899,12 @@ export interface IEndpoint { const endpoints: IEndpoint[] = (eps as [string, any]).map(([name, ep]) => { return { name: name, - get meta() { return ep.meta ?? {}; }, - get params() { return ep.paramDef; }, + get meta() { + return ep.meta ?? {}; + }, + get params() { + return ep.paramDef; + }, }; }); diff --git a/packages/backend/src/server/api/endpoints/admin/abuse-report/notification-recipient/create.ts b/packages/backend/src/server/api/endpoints/admin/abuse-report/notification-recipient/create.ts new file mode 100644 index 0000000000..bdfbcba518 --- /dev/null +++ b/packages/backend/src/server/api/endpoints/admin/abuse-report/notification-recipient/create.ts @@ -0,0 +1,122 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { Inject, Injectable } from '@nestjs/common'; +import { Endpoint } from '@/server/api/endpoint-base.js'; +import { ApiError } from '@/server/api/error.js'; +import { + AbuseReportNotificationRecipientEntityService, +} from '@/core/entities/AbuseReportNotificationRecipientEntityService.js'; +import { AbuseReportNotificationService } from '@/core/AbuseReportNotificationService.js'; +import { DI } from '@/di-symbols.js'; +import type { UserProfilesRepository } from '@/models/_.js'; + +export const meta = { + tags: ['admin', 'abuse-report', 'notification-recipient'], + + requireCredential: true, + requireModerator: true, + secure: true, + kind: 'write:admin:abuse-report:notification-recipient', + + res: { + type: 'object', + ref: 'AbuseReportNotificationRecipient', + }, + + errors: { + correlationCheckEmail: { + message: 'If "method" is email, "userId" must be set.', + code: 'CORRELATION_CHECK_EMAIL', + id: '348bb8ae-575a-6fe9-4327-5811999def8f', + httpStatusCode: 400, + }, + correlationCheckWebhook: { + message: 'If "method" is webhook, "systemWebhookId" must be set.', + code: 'CORRELATION_CHECK_WEBHOOK', + id: 'b0c15051-de2d-29ef-260c-9585cddd701a', + httpStatusCode: 400, + }, + emailAddressNotSet: { + message: 'Email address is not set.', + code: 'EMAIL_ADDRESS_NOT_SET', + id: '7cc1d85e-2f58-fc31-b644-3de8d0d3421f', + httpStatusCode: 400, + }, + }, +} as const; + +export const paramDef = { + type: 'object', + properties: { + isActive: { + type: 'boolean', + }, + name: { + type: 'string', + minLength: 1, + maxLength: 255, + }, + method: { + type: 'string', + enum: ['email', 'webhook'], + }, + userId: { + type: 'string', + format: 'misskey:id', + }, + systemWebhookId: { + type: 'string', + format: 'misskey:id', + }, + }, + required: [ + 'isActive', + 'name', + 'method', + ], +} as const; + +@Injectable() +export default class extends Endpoint { // eslint-disable-line import/no-default-export + constructor( + @Inject(DI.userProfilesRepository) + private userProfilesRepository: UserProfilesRepository, + private abuseReportNotificationService: AbuseReportNotificationService, + private abuseReportNotificationRecipientEntityService: AbuseReportNotificationRecipientEntityService, + ) { + super(meta, paramDef, async (ps, me) => { + if (ps.method === 'email') { + const userProfile = await this.userProfilesRepository.findOneBy({ userId: ps.userId }); + if (!ps.userId || !userProfile) { + throw new ApiError(meta.errors.correlationCheckEmail); + } + + if (!userProfile.email || !userProfile.emailVerified) { + throw new ApiError(meta.errors.emailAddressNotSet); + } + } + + if (ps.method === 'webhook' && !ps.systemWebhookId) { + throw new ApiError(meta.errors.correlationCheckWebhook); + } + + const userId = ps.method === 'email' ? ps.userId : null; + const systemWebhookId = ps.method === 'webhook' ? ps.systemWebhookId : null; + const result = await this.abuseReportNotificationService.createRecipient( + { + isActive: ps.isActive, + name: ps.name, + method: ps.method, + userId: userId ?? null, + systemWebhookId: systemWebhookId ?? null, + }, + me, + ); + + return this.abuseReportNotificationRecipientEntityService.pack(result); + }); + } +} diff --git a/packages/backend/src/server/api/endpoints/admin/abuse-report/notification-recipient/delete.ts b/packages/backend/src/server/api/endpoints/admin/abuse-report/notification-recipient/delete.ts new file mode 100644 index 0000000000..b6dc44e09c --- /dev/null +++ b/packages/backend/src/server/api/endpoints/admin/abuse-report/notification-recipient/delete.ts @@ -0,0 +1,44 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { Injectable } from '@nestjs/common'; +import { Endpoint } from '@/server/api/endpoint-base.js'; +import { AbuseReportNotificationService } from '@/core/AbuseReportNotificationService.js'; + +export const meta = { + tags: ['admin', 'abuse-report', 'notification-recipient'], + + requireCredential: true, + requireModerator: true, + secure: true, + kind: 'write:admin:abuse-report:notification-recipient', +} as const; + +export const paramDef = { + type: 'object', + properties: { + id: { + type: 'string', + format: 'misskey:id', + }, + }, + required: [ + 'id', + ], +} as const; + +@Injectable() +export default class extends Endpoint { // eslint-disable-line import/no-default-export + constructor( + private abuseReportNotificationService: AbuseReportNotificationService, + ) { + super(meta, paramDef, async (ps, me) => { + await this.abuseReportNotificationService.deleteRecipient( + ps.id, + me, + ); + }); + } +} diff --git a/packages/backend/src/server/api/endpoints/admin/abuse-report/notification-recipient/list.ts b/packages/backend/src/server/api/endpoints/admin/abuse-report/notification-recipient/list.ts new file mode 100644 index 0000000000..dad9161a8a --- /dev/null +++ b/packages/backend/src/server/api/endpoints/admin/abuse-report/notification-recipient/list.ts @@ -0,0 +1,55 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { Injectable } from '@nestjs/common'; +import { Endpoint } from '@/server/api/endpoint-base.js'; +import { + AbuseReportNotificationRecipientEntityService, +} from '@/core/entities/AbuseReportNotificationRecipientEntityService.js'; +import { AbuseReportNotificationService } from '@/core/AbuseReportNotificationService.js'; + +export const meta = { + tags: ['admin', 'abuse-report', 'notification-recipient'], + + requireCredential: true, + requireModerator: true, + secure: true, + kind: 'read:admin:abuse-report:notification-recipient', + + res: { + type: 'array', + items: { + type: 'object', + ref: 'AbuseReportNotificationRecipient', + }, + }, +} as const; + +export const paramDef = { + type: 'object', + properties: { + method: { + type: 'array', + items: { + type: 'string', + enum: ['email', 'webhook'], + }, + }, + }, + required: [], +} as const; + +@Injectable() +export default class extends Endpoint { // eslint-disable-line import/no-default-export + constructor( + private abuseReportNotificationService: AbuseReportNotificationService, + private abuseReportNotificationRecipientEntityService: AbuseReportNotificationRecipientEntityService, + ) { + super(meta, paramDef, async (ps) => { + const recipients = await this.abuseReportNotificationService.fetchRecipients({ method: ps.method }); + return this.abuseReportNotificationRecipientEntityService.packMany(recipients); + }); + } +} diff --git a/packages/backend/src/server/api/endpoints/admin/abuse-report/notification-recipient/show.ts b/packages/backend/src/server/api/endpoints/admin/abuse-report/notification-recipient/show.ts new file mode 100644 index 0000000000..557798f946 --- /dev/null +++ b/packages/backend/src/server/api/endpoints/admin/abuse-report/notification-recipient/show.ts @@ -0,0 +1,64 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { Injectable } from '@nestjs/common'; +import { Endpoint } from '@/server/api/endpoint-base.js'; +import { + AbuseReportNotificationRecipientEntityService, +} from '@/core/entities/AbuseReportNotificationRecipientEntityService.js'; +import { AbuseReportNotificationService } from '@/core/AbuseReportNotificationService.js'; +import { ApiError } from '@/server/api/error.js'; + +export const meta = { + tags: ['admin', 'abuse-report', 'notification-recipient'], + + requireCredential: true, + requireModerator: true, + secure: true, + kind: 'read:admin:abuse-report:notification-recipient', + + res: { + type: 'object', + ref: 'AbuseReportNotificationRecipient', + }, + + errors: { + noSuchRecipient: { + message: 'No such recipient.', + code: 'NO_SUCH_RECIPIENT', + id: '013de6a8-f757-04cb-4d73-cc2a7e3368e4', + kind: 'server', + httpStatusCode: 404, + }, + }, +} as const; + +export const paramDef = { + type: 'object', + properties: { + id: { + type: 'string', + format: 'misskey:id', + }, + }, + required: ['id'], +} as const; + +@Injectable() +export default class extends Endpoint { // eslint-disable-line import/no-default-export + constructor( + private abuseReportNotificationService: AbuseReportNotificationService, + private abuseReportNotificationRecipientEntityService: AbuseReportNotificationRecipientEntityService, + ) { + super(meta, paramDef, async (ps) => { + const recipients = await this.abuseReportNotificationService.fetchRecipients({ ids: [ps.id] }); + if (recipients.length === 0) { + throw new ApiError(meta.errors.noSuchRecipient); + } + + return this.abuseReportNotificationRecipientEntityService.pack(recipients[0]); + }); + } +} diff --git a/packages/backend/src/server/api/endpoints/admin/abuse-report/notification-recipient/update.ts b/packages/backend/src/server/api/endpoints/admin/abuse-report/notification-recipient/update.ts new file mode 100644 index 0000000000..bd4b485217 --- /dev/null +++ b/packages/backend/src/server/api/endpoints/admin/abuse-report/notification-recipient/update.ts @@ -0,0 +1,128 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { Inject, Injectable } from '@nestjs/common'; +import { Endpoint } from '@/server/api/endpoint-base.js'; +import { ApiError } from '@/server/api/error.js'; +import { + AbuseReportNotificationRecipientEntityService, +} from '@/core/entities/AbuseReportNotificationRecipientEntityService.js'; +import { AbuseReportNotificationService } from '@/core/AbuseReportNotificationService.js'; +import { DI } from '@/di-symbols.js'; +import type { UserProfilesRepository } from '@/models/_.js'; + +export const meta = { + tags: ['admin', 'abuse-report', 'notification-recipient'], + + requireCredential: true, + requireModerator: true, + secure: true, + kind: 'write:admin:abuse-report:notification-recipient', + + res: { + type: 'object', + ref: 'AbuseReportNotificationRecipient', + }, + + errors: { + correlationCheckEmail: { + message: 'If "method" is email, "userId" must be set.', + code: 'CORRELATION_CHECK_EMAIL', + id: '348bb8ae-575a-6fe9-4327-5811999def8f', + httpStatusCode: 400, + }, + correlationCheckWebhook: { + message: 'If "method" is webhook, "systemWebhookId" must be set.', + code: 'CORRELATION_CHECK_WEBHOOK', + id: 'b0c15051-de2d-29ef-260c-9585cddd701a', + httpStatusCode: 400, + }, + emailAddressNotSet: { + message: 'Email address is not set.', + code: 'EMAIL_ADDRESS_NOT_SET', + id: '7cc1d85e-2f58-fc31-b644-3de8d0d3421f', + httpStatusCode: 400, + }, + }, +} as const; + +export const paramDef = { + type: 'object', + properties: { + id: { + type: 'string', + format: 'misskey:id', + }, + isActive: { + type: 'boolean', + }, + name: { + type: 'string', + minLength: 1, + maxLength: 255, + }, + method: { + type: 'string', + enum: ['email', 'webhook'], + }, + userId: { + type: 'string', + format: 'misskey:id', + }, + systemWebhookId: { + type: 'string', + format: 'misskey:id', + }, + }, + required: [ + 'id', + 'isActive', + 'name', + 'method', + ], +} as const; + +@Injectable() +export default class extends Endpoint { // eslint-disable-line import/no-default-export + constructor( + @Inject(DI.userProfilesRepository) + private userProfilesRepository: UserProfilesRepository, + private abuseReportNotificationService: AbuseReportNotificationService, + private abuseReportNotificationRecipientEntityService: AbuseReportNotificationRecipientEntityService, + ) { + super(meta, paramDef, async (ps, me) => { + if (ps.method === 'email') { + const userProfile = await this.userProfilesRepository.findOneBy({ userId: ps.userId }); + if (!ps.userId || !userProfile) { + throw new ApiError(meta.errors.correlationCheckEmail); + } + + if (!userProfile.email || !userProfile.emailVerified) { + throw new ApiError(meta.errors.emailAddressNotSet); + } + } + + if (ps.method === 'webhook' && !ps.systemWebhookId) { + throw new ApiError(meta.errors.correlationCheckWebhook); + } + + const userId = ps.method === 'email' ? ps.userId : null; + const systemWebhookId = ps.method === 'webhook' ? ps.systemWebhookId : null; + const result = await this.abuseReportNotificationService.updateRecipient( + { + id: ps.id, + isActive: ps.isActive, + name: ps.name, + method: ps.method, + userId: userId ?? null, + systemWebhookId: systemWebhookId ?? null, + }, + me, + ); + + return this.abuseReportNotificationRecipientEntityService.pack(result); + }); + } +} diff --git a/packages/backend/src/server/api/endpoints/admin/ad/update.ts b/packages/backend/src/server/api/endpoints/admin/ad/update.ts index 62358457ff..4e3d731aca 100644 --- a/packages/backend/src/server/api/endpoints/admin/ad/update.ts +++ b/packages/backend/src/server/api/endpoints/admin/ad/update.ts @@ -40,7 +40,7 @@ export const paramDef = { startsAt: { type: 'integer' }, dayOfWeek: { type: 'integer' }, }, - required: ['id', 'memo', 'url', 'imageUrl', 'place', 'priority', 'ratio', 'expiresAt', 'startsAt', 'dayOfWeek'], + required: ['id'], } as const; @Injectable() @@ -63,8 +63,8 @@ export default class extends Endpoint { // eslint- ratio: ps.ratio, memo: ps.memo, imageUrl: ps.imageUrl, - expiresAt: new Date(ps.expiresAt), - startsAt: new Date(ps.startsAt), + expiresAt: ps.expiresAt ? new Date(ps.expiresAt) : undefined, + startsAt: ps.startsAt ? new Date(ps.startsAt) : undefined, dayOfWeek: ps.dayOfWeek, }); diff --git a/packages/backend/src/server/api/endpoints/admin/drive/show-file.ts b/packages/backend/src/server/api/endpoints/admin/drive/show-file.ts index 459d8880fa..a7136d8c8c 100644 --- a/packages/backend/src/server/api/endpoints/admin/drive/show-file.ts +++ b/packages/backend/src/server/api/endpoints/admin/drive/show-file.ts @@ -61,7 +61,7 @@ export const meta = { name: { type: 'string', optional: false, nullable: false, - example: 'lenna.jpg', + example: '192.jpg', }, type: { type: 'string', diff --git a/packages/backend/src/server/api/endpoints/admin/queue/inbox-delayed.ts b/packages/backend/src/server/api/endpoints/admin/queue/inbox-delayed.ts index 305ae1af1d..bfe230da8d 100644 --- a/packages/backend/src/server/api/endpoints/admin/queue/inbox-delayed.ts +++ b/packages/backend/src/server/api/endpoints/admin/queue/inbox-delayed.ts @@ -56,7 +56,8 @@ export default class extends Endpoint { // eslint- const res = [] as [string, number][]; for (const job of jobs) { - const host = new URL(job.data.signature.keyId).host; + const signature = job.data.signature ? 'version' in job.data.signature ? job.data.signature.value : job.data.signature : null; + const host = signature ? Array.isArray(signature) ? 'TODO' : new URL(signature.keyId).host : new URL(job.data.activity.actor).host; if (res.find(x => x[0] === host)) { res.find(x => x[0] === host)![1]++; } else { diff --git a/packages/backend/src/server/api/endpoints/admin/queue/stats.ts b/packages/backend/src/server/api/endpoints/admin/queue/stats.ts index 9694b3fa40..d7f9e4eaa3 100644 --- a/packages/backend/src/server/api/endpoints/admin/queue/stats.ts +++ b/packages/backend/src/server/api/endpoints/admin/queue/stats.ts @@ -5,7 +5,7 @@ import { Inject, Injectable } from '@nestjs/common'; import { Endpoint } from '@/server/api/endpoint-base.js'; -import type { DbQueue, DeliverQueue, EndedPollNotificationQueue, InboxQueue, ObjectStorageQueue, SystemQueue, WebhookDeliverQueue } from '@/core/QueueModule.js'; +import type { DbQueue, DeliverQueue, EndedPollNotificationQueue, InboxQueue, ObjectStorageQueue, SystemQueue, UserWebhookDeliverQueue, SystemWebhookDeliverQueue } from '@/core/QueueModule.js'; export const meta = { tags: ['admin'], @@ -53,7 +53,8 @@ export default class extends Endpoint { // eslint- @Inject('queue:inbox') public inboxQueue: InboxQueue, @Inject('queue:db') public dbQueue: DbQueue, @Inject('queue:objectStorage') public objectStorageQueue: ObjectStorageQueue, - @Inject('queue:webhookDeliver') public webhookDeliverQueue: WebhookDeliverQueue, + @Inject('queue:userWebhookDeliver') public userWebhookDeliverQueue: UserWebhookDeliverQueue, + @Inject('queue:systemWebhookDeliver') public systemWebhookDeliverQueue: SystemWebhookDeliverQueue, ) { super(meta, paramDef, async (ps, me) => { const deliverJobCounts = await this.deliverQueue.getJobCounts(); diff --git a/packages/backend/src/server/api/endpoints/admin/resolve-abuse-user-report.ts b/packages/backend/src/server/api/endpoints/admin/resolve-abuse-user-report.ts index 8b0456068b..9b79100fcf 100644 --- a/packages/backend/src/server/api/endpoints/admin/resolve-abuse-user-report.ts +++ b/packages/backend/src/server/api/endpoints/admin/resolve-abuse-user-report.ts @@ -5,12 +5,10 @@ import { Inject, Injectable } from '@nestjs/common'; import { Endpoint } from '@/server/api/endpoint-base.js'; -import type { UsersRepository, AbuseUserReportsRepository } from '@/models/_.js'; -import { InstanceActorService } from '@/core/InstanceActorService.js'; -import { QueueService } from '@/core/QueueService.js'; -import { ApRendererService } from '@/core/activitypub/ApRendererService.js'; +import type { AbuseUserReportsRepository } from '@/models/_.js'; import { DI } from '@/di-symbols.js'; -import { ModerationLogService } from '@/core/ModerationLogService.js'; +import { ApiError } from '@/server/api/error.js'; +import { AbuseReportService } from '@/core/AbuseReportService.js'; export const meta = { tags: ['admin'], @@ -18,6 +16,16 @@ export const meta = { requireCredential: true, requireModerator: true, kind: 'write:admin:resolve-abuse-user-report', + + errors: { + noSuchAbuseReport: { + message: 'No such abuse report.', + code: 'NO_SUCH_ABUSE_REPORT', + id: 'ac3794dd-2ce4-d878-e546-73c60c06b398', + kind: 'server', + httpStatusCode: 404, + }, + }, } as const; export const paramDef = { @@ -29,47 +37,20 @@ export const paramDef = { required: ['reportId'], } as const; -// TODO: ロジックをサービスに切り出す - @Injectable() export default class extends Endpoint { // eslint-disable-line import/no-default-export constructor( - @Inject(DI.usersRepository) - private usersRepository: UsersRepository, - @Inject(DI.abuseUserReportsRepository) private abuseUserReportsRepository: AbuseUserReportsRepository, - - private queueService: QueueService, - private instanceActorService: InstanceActorService, - private apRendererService: ApRendererService, - private moderationLogService: ModerationLogService, + private abuseReportService: AbuseReportService, ) { super(meta, paramDef, async (ps, me) => { const report = await this.abuseUserReportsRepository.findOneBy({ id: ps.reportId }); - - if (report == null) { - throw new Error('report not found'); + if (!report) { + throw new ApiError(meta.errors.noSuchAbuseReport); } - if (ps.forward && report.targetUserHost != null) { - const actor = await this.instanceActorService.getInstanceActor(); - const targetUser = await this.usersRepository.findOneByOrFail({ id: report.targetUserId }); - - this.queueService.deliver(actor, this.apRendererService.addContext(this.apRendererService.renderFlag(actor, targetUser.uri!, report.comment)), targetUser.inbox, false); - } - - await this.abuseUserReportsRepository.update(report.id, { - resolved: true, - assigneeId: me.id, - forwarded: ps.forward && report.targetUserHost != null, - }); - - this.moderationLogService.log(me, 'resolveAbuseReport', { - reportId: report.id, - report: report, - forwarded: ps.forward && report.targetUserHost != null, - }); + await this.abuseReportService.resolve([{ reportId: report.id, forward: ps.forward }], me); }); } } diff --git a/packages/backend/src/server/api/endpoints/admin/roles/update.ts b/packages/backend/src/server/api/endpoints/admin/roles/update.ts index 5242e0be2f..465ad7aaaf 100644 --- a/packages/backend/src/server/api/endpoints/admin/roles/update.ts +++ b/packages/backend/src/server/api/endpoints/admin/roles/update.ts @@ -6,7 +6,6 @@ import { Inject, Injectable } from '@nestjs/common'; import { Endpoint } from '@/server/api/endpoint-base.js'; import type { RolesRepository } from '@/models/_.js'; -import { GlobalEventService } from '@/core/GlobalEventService.js'; import { DI } from '@/di-symbols.js'; import { ApiError } from '@/server/api/error.js'; import { RoleService } from '@/core/RoleService.js'; @@ -50,19 +49,6 @@ export const paramDef = { }, required: [ 'roleId', - 'name', - 'description', - 'color', - 'iconUrl', - 'target', - 'condFormula', - 'isPublic', - 'isModerator', - 'isAdministrator', - 'asBadge', - 'canEditMembersByModerator', - 'displayOrder', - 'policies', ], } as const; diff --git a/packages/backend/src/server/api/endpoints/admin/system-webhook/create.ts b/packages/backend/src/server/api/endpoints/admin/system-webhook/create.ts new file mode 100644 index 0000000000..28071e7a33 --- /dev/null +++ b/packages/backend/src/server/api/endpoints/admin/system-webhook/create.ts @@ -0,0 +1,85 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { Injectable } from '@nestjs/common'; +import { Endpoint } from '@/server/api/endpoint-base.js'; +import { SystemWebhookEntityService } from '@/core/entities/SystemWebhookEntityService.js'; +import { systemWebhookEventTypes } from '@/models/SystemWebhook.js'; +import { SystemWebhookService } from '@/core/SystemWebhookService.js'; + +export const meta = { + tags: ['admin', 'system-webhook'], + + requireCredential: true, + requireModerator: true, + secure: true, + kind: 'write:admin:system-webhook', + + res: { + type: 'object', + ref: 'SystemWebhook', + }, +} as const; + +export const paramDef = { + type: 'object', + properties: { + isActive: { + type: 'boolean', + }, + name: { + type: 'string', + minLength: 1, + maxLength: 255, + }, + on: { + type: 'array', + items: { + type: 'string', + enum: systemWebhookEventTypes, + }, + }, + url: { + type: 'string', + minLength: 1, + maxLength: 1024, + }, + secret: { + type: 'string', + minLength: 1, + maxLength: 1024, + }, + }, + required: [ + 'isActive', + 'name', + 'on', + 'url', + 'secret', + ], +} as const; + +@Injectable() +export default class extends Endpoint { // eslint-disable-line import/no-default-export + constructor( + private systemWebhookService: SystemWebhookService, + private systemWebhookEntityService: SystemWebhookEntityService, + ) { + super(meta, paramDef, async (ps, me) => { + const result = await this.systemWebhookService.createSystemWebhook( + { + isActive: ps.isActive, + name: ps.name, + on: ps.on, + url: ps.url, + secret: ps.secret, + }, + me, + ); + + return this.systemWebhookEntityService.pack(result); + }); + } +} diff --git a/packages/backend/src/server/api/endpoints/admin/system-webhook/delete.ts b/packages/backend/src/server/api/endpoints/admin/system-webhook/delete.ts new file mode 100644 index 0000000000..9cdfc7e70f --- /dev/null +++ b/packages/backend/src/server/api/endpoints/admin/system-webhook/delete.ts @@ -0,0 +1,44 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { Injectable } from '@nestjs/common'; +import { Endpoint } from '@/server/api/endpoint-base.js'; +import { SystemWebhookService } from '@/core/SystemWebhookService.js'; + +export const meta = { + tags: ['admin', 'system-webhook'], + + requireCredential: true, + requireModerator: true, + secure: true, + kind: 'write:admin:system-webhook', +} as const; + +export const paramDef = { + type: 'object', + properties: { + id: { + type: 'string', + format: 'misskey:id', + }, + }, + required: [ + 'id', + ], +} as const; + +@Injectable() +export default class extends Endpoint { // eslint-disable-line import/no-default-export + constructor( + private systemWebhookService: SystemWebhookService, + ) { + super(meta, paramDef, async (ps, me) => { + await this.systemWebhookService.deleteSystemWebhook( + ps.id, + me, + ); + }); + } +} diff --git a/packages/backend/src/server/api/endpoints/admin/system-webhook/list.ts b/packages/backend/src/server/api/endpoints/admin/system-webhook/list.ts new file mode 100644 index 0000000000..7a440a774e --- /dev/null +++ b/packages/backend/src/server/api/endpoints/admin/system-webhook/list.ts @@ -0,0 +1,60 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { Injectable } from '@nestjs/common'; +import { Endpoint } from '@/server/api/endpoint-base.js'; +import { SystemWebhookEntityService } from '@/core/entities/SystemWebhookEntityService.js'; +import { systemWebhookEventTypes } from '@/models/SystemWebhook.js'; +import { SystemWebhookService } from '@/core/SystemWebhookService.js'; + +export const meta = { + tags: ['admin', 'system-webhook'], + + requireCredential: true, + requireModerator: true, + secure: true, + kind: 'write:admin:system-webhook', + + res: { + type: 'array', + items: { + type: 'object', + ref: 'SystemWebhook', + }, + }, +} as const; + +export const paramDef = { + type: 'object', + properties: { + isActive: { + type: 'boolean', + }, + on: { + type: 'array', + items: { + type: 'string', + enum: systemWebhookEventTypes, + }, + }, + }, + required: [], +} as const; + +@Injectable() +export default class extends Endpoint { // eslint-disable-line import/no-default-export + constructor( + private systemWebhookService: SystemWebhookService, + private systemWebhookEntityService: SystemWebhookEntityService, + ) { + super(meta, paramDef, async (ps) => { + const webhooks = await this.systemWebhookService.fetchSystemWebhooks({ + isActive: ps.isActive, + on: ps.on, + }); + return this.systemWebhookEntityService.packMany(webhooks); + }); + } +} diff --git a/packages/backend/src/server/api/endpoints/admin/system-webhook/show.ts b/packages/backend/src/server/api/endpoints/admin/system-webhook/show.ts new file mode 100644 index 0000000000..75862c96a7 --- /dev/null +++ b/packages/backend/src/server/api/endpoints/admin/system-webhook/show.ts @@ -0,0 +1,62 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { Injectable } from '@nestjs/common'; +import { Endpoint } from '@/server/api/endpoint-base.js'; +import { SystemWebhookEntityService } from '@/core/entities/SystemWebhookEntityService.js'; +import { ApiError } from '@/server/api/error.js'; +import { SystemWebhookService } from '@/core/SystemWebhookService.js'; + +export const meta = { + tags: ['admin', 'system-webhook'], + + requireCredential: true, + requireModerator: true, + secure: true, + kind: 'write:admin:system-webhook', + + res: { + type: 'object', + ref: 'SystemWebhook', + }, + + errors: { + noSuchSystemWebhook: { + message: 'No such SystemWebhook.', + code: 'NO_SUCH_SYSTEM_WEBHOOK', + id: '38dd1ffe-04b4-6ff5-d8ba-4e6a6ae22c9d', + kind: 'server', + httpStatusCode: 404, + }, + }, +} as const; + +export const paramDef = { + type: 'object', + properties: { + id: { + type: 'string', + format: 'misskey:id', + }, + }, + required: ['id'], +} as const; + +@Injectable() +export default class extends Endpoint { // eslint-disable-line import/no-default-export + constructor( + private systemWebhookService: SystemWebhookService, + private systemWebhookEntityService: SystemWebhookEntityService, + ) { + super(meta, paramDef, async (ps) => { + const webhooks = await this.systemWebhookService.fetchSystemWebhooks({ ids: [ps.id] }); + if (webhooks.length === 0) { + throw new ApiError(meta.errors.noSuchSystemWebhook); + } + + return this.systemWebhookEntityService.pack(webhooks[0]); + }); + } +} diff --git a/packages/backend/src/server/api/endpoints/admin/system-webhook/update.ts b/packages/backend/src/server/api/endpoints/admin/system-webhook/update.ts new file mode 100644 index 0000000000..8d68bb8f87 --- /dev/null +++ b/packages/backend/src/server/api/endpoints/admin/system-webhook/update.ts @@ -0,0 +1,91 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { Injectable } from '@nestjs/common'; +import { Endpoint } from '@/server/api/endpoint-base.js'; +import { SystemWebhookEntityService } from '@/core/entities/SystemWebhookEntityService.js'; +import { systemWebhookEventTypes } from '@/models/SystemWebhook.js'; +import { SystemWebhookService } from '@/core/SystemWebhookService.js'; + +export const meta = { + tags: ['admin', 'system-webhook'], + + requireCredential: true, + requireModerator: true, + secure: true, + kind: 'write:admin:system-webhook', + + res: { + type: 'object', + ref: 'SystemWebhook', + }, +} as const; + +export const paramDef = { + type: 'object', + properties: { + id: { + type: 'string', + format: 'misskey:id', + }, + isActive: { + type: 'boolean', + }, + name: { + type: 'string', + minLength: 1, + maxLength: 255, + }, + on: { + type: 'array', + items: { + type: 'string', + enum: systemWebhookEventTypes, + }, + }, + url: { + type: 'string', + minLength: 1, + maxLength: 1024, + }, + secret: { + type: 'string', + minLength: 1, + maxLength: 1024, + }, + }, + required: [ + 'id', + 'isActive', + 'name', + 'on', + 'url', + 'secret', + ], +} as const; + +@Injectable() +export default class extends Endpoint { // eslint-disable-line import/no-default-export + constructor( + private systemWebhookService: SystemWebhookService, + private systemWebhookEntityService: SystemWebhookEntityService, + ) { + super(meta, paramDef, async (ps, me) => { + const result = await this.systemWebhookService.updateSystemWebhook( + { + id: ps.id, + isActive: ps.isActive, + name: ps.name, + on: ps.on, + url: ps.url, + secret: ps.secret, + }, + me, + ); + + return this.systemWebhookEntityService.pack(result); + }); + } +} diff --git a/packages/backend/src/server/api/endpoints/antennas/create.ts b/packages/backend/src/server/api/endpoints/antennas/create.ts index ec08198514..577b9e1b1f 100644 --- a/packages/backend/src/server/api/endpoints/antennas/create.ts +++ b/packages/backend/src/server/api/endpoints/antennas/create.ts @@ -93,7 +93,7 @@ export default class extends Endpoint { // eslint- const currentAntennasCount = await this.antennasRepository.countBy({ userId: me.id, }); - if (currentAntennasCount > (await this.roleService.getUserPolicies(me.id)).antennaLimit) { + if (currentAntennasCount >= (await this.roleService.getUserPolicies(me.id)).antennaLimit) { throw new ApiError(meta.errors.tooManyAntennas); } diff --git a/packages/backend/src/server/api/endpoints/clips/update.ts b/packages/backend/src/server/api/endpoints/clips/update.ts index 3b44ba81b3..603a3ccf3d 100644 --- a/packages/backend/src/server/api/endpoints/clips/update.ts +++ b/packages/backend/src/server/api/endpoints/clips/update.ts @@ -3,7 +3,7 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import { Inject, Injectable } from '@nestjs/common'; +import { Injectable } from '@nestjs/common'; import { Endpoint } from '@/server/api/endpoint-base.js'; import { ClipEntityService } from '@/core/entities/ClipEntityService.js'; import { ClipService } from '@/core/ClipService.js'; @@ -41,7 +41,7 @@ export const paramDef = { isPublic: { type: 'boolean' }, description: { type: 'string', nullable: true, minLength: 1, maxLength: 2048 }, }, - required: ['clipId', 'name'], + required: ['clipId'], } as const; @Injectable() diff --git a/packages/backend/src/server/api/endpoints/drive/folders/update.ts b/packages/backend/src/server/api/endpoints/drive/folders/update.ts index 52b8b335b5..62b04e1df3 100644 --- a/packages/backend/src/server/api/endpoints/drive/folders/update.ts +++ b/packages/backend/src/server/api/endpoints/drive/folders/update.ts @@ -95,15 +95,14 @@ export default class extends Endpoint { // eslint- // Check if the circular reference will occur const checkCircle = async (folderId: string): Promise => { - // Fetch folder - const folder2 = await this.driveFoldersRepository.findOneBy({ + const folder2 = await this.driveFoldersRepository.findOneByOrFail({ id: folderId, }); - if (folder2!.id === folder!.id) { + if (folder2.id === folder.id) { return true; - } else if (folder2!.parentId) { - return await checkCircle(folder2!.parentId); + } else if (folder2.parentId) { + return await checkCircle(folder2.parentId); } else { return false; } diff --git a/packages/backend/src/server/api/endpoints/federation/instances.ts b/packages/backend/src/server/api/endpoints/federation/instances.ts index 4ef4315fb3..36f4bf5aa6 100644 --- a/packages/backend/src/server/api/endpoints/federation/instances.ts +++ b/packages/backend/src/server/api/endpoints/federation/instances.ts @@ -117,9 +117,9 @@ export default class extends Endpoint { // eslint- if (typeof ps.suspended === 'boolean') { if (ps.suspended) { - query.andWhere('instance.isSuspended = TRUE'); + query.andWhere('instance.suspensionState != \'none\''); } else { - query.andWhere('instance.isSuspended = FALSE'); + query.andWhere('instance.suspensionState = \'none\''); } } diff --git a/packages/backend/src/server/api/endpoints/gallery/posts/create.ts b/packages/backend/src/server/api/endpoints/gallery/posts/create.ts index 46f8998810..504a9c789e 100644 --- a/packages/backend/src/server/api/endpoints/gallery/posts/create.ts +++ b/packages/backend/src/server/api/endpoints/gallery/posts/create.ts @@ -12,7 +12,6 @@ import type { MiDriveFile } from '@/models/DriveFile.js'; import { IdService } from '@/core/IdService.js'; import { GalleryPostEntityService } from '@/core/entities/GalleryPostEntityService.js'; import { DI } from '@/di-symbols.js'; -import { isNotNull } from '@/misc/is-not-null.js'; export const meta = { tags: ['gallery'], @@ -70,7 +69,7 @@ export default class extends Endpoint { // eslint- id: fileId, userId: me.id, }), - ))).filter(isNotNull); + ))).filter(x => x != null); if (files.length === 0) { throw new Error(); diff --git a/packages/backend/src/server/api/endpoints/gallery/posts/update.ts b/packages/backend/src/server/api/endpoints/gallery/posts/update.ts index 8bd83ff5ba..5243ee9603 100644 --- a/packages/backend/src/server/api/endpoints/gallery/posts/update.ts +++ b/packages/backend/src/server/api/endpoints/gallery/posts/update.ts @@ -10,7 +10,6 @@ import type { DriveFilesRepository, GalleryPostsRepository } from '@/models/_.js import type { MiDriveFile } from '@/models/DriveFile.js'; import { GalleryPostEntityService } from '@/core/entities/GalleryPostEntityService.js'; import { DI } from '@/di-symbols.js'; -import { isNotNull } from '@/misc/is-not-null.js'; export const meta = { tags: ['gallery'], @@ -48,7 +47,7 @@ export const paramDef = { } }, isSensitive: { type: 'boolean', default: false }, }, - required: ['postId', 'title', 'fileIds'], + required: ['postId'], } as const; @Injectable() @@ -63,15 +62,19 @@ export default class extends Endpoint { // eslint- private galleryPostEntityService: GalleryPostEntityService, ) { super(meta, paramDef, async (ps, me) => { - const files = (await Promise.all(ps.fileIds.map(fileId => - this.driveFilesRepository.findOneBy({ - id: fileId, - userId: me.id, - }), - ))).filter(isNotNull); + let files: Array | undefined; - if (files.length === 0) { - throw new Error(); + if (ps.fileIds) { + files = (await Promise.all(ps.fileIds.map(fileId => + this.driveFilesRepository.findOneBy({ + id: fileId, + userId: me.id, + }), + ))).filter(x => x != null); + + if (files.length === 0) { + throw new Error(); + } } await this.galleryPostsRepository.update({ @@ -82,7 +85,7 @@ export default class extends Endpoint { // eslint- title: ps.title, description: ps.description, isSensitive: ps.isSensitive, - fileIds: files.map(file => file.id), + fileIds: files ? files.map(file => file.id) : undefined, }); const post = await this.galleryPostsRepository.findOneByOrFail({ id: ps.postId }); diff --git a/packages/backend/src/server/api/endpoints/i/import-antennas.ts b/packages/backend/src/server/api/endpoints/i/import-antennas.ts index b4661a93e2..bc46163e3d 100644 --- a/packages/backend/src/server/api/endpoints/i/import-antennas.ts +++ b/packages/backend/src/server/api/endpoints/i/import-antennas.ts @@ -78,7 +78,7 @@ export default class extends Endpoint { if (file.size === 0) throw new ApiError(meta.errors.emptyFile); const antennas: (_Antenna & { userListAccts: string[] | null })[] = JSON.parse(await this.downloadService.downloadTextFile(file.url)); const currentAntennasCount = await this.antennasRepository.countBy({ userId: me.id }); - if (currentAntennasCount + antennas.length > (await this.roleService.getUserPolicies(me.id)).antennaLimit) { + if (currentAntennasCount + antennas.length >= (await this.roleService.getUserPolicies(me.id)).antennaLimit) { throw new ApiError(meta.errors.tooManyAntennas); } this.queueService.createImportAntennasJob(me, antennas); diff --git a/packages/backend/src/server/api/endpoints/i/update.ts b/packages/backend/src/server/api/endpoints/i/update.ts index a8e702f328..a1e2fa5e4c 100644 --- a/packages/backend/src/server/api/endpoints/i/update.ts +++ b/packages/backend/src/server/api/endpoints/i/update.ts @@ -25,7 +25,7 @@ import { UserFollowingService } from '@/core/UserFollowingService.js'; import { AccountUpdateService } from '@/core/AccountUpdateService.js'; import { HashtagService } from '@/core/HashtagService.js'; import { DI } from '@/di-symbols.js'; -import { RoleService } from '@/core/RoleService.js'; +import { RolePolicies, RoleService } from '@/core/RoleService.js'; import { CacheService } from '@/core/CacheService.js'; import { RemoteUserResolveService } from '@/core/RemoteUserResolveService.js'; import { DriveFileEntityService } from '@/core/entities/DriveFileEntityService.js'; @@ -256,8 +256,16 @@ export default class extends Endpoint { // eslint- const profileUpdates = {} as Partial; const profile = await this.userProfilesRepository.findOneByOrFail({ userId: user.id }); + let policies: RolePolicies | null = null; - if (ps.name !== undefined) updates.name = ps.name; + if (ps.name !== undefined) { + if (ps.name === null) { + updates.name = null; + } else { + const trimmedName = ps.name.trim(); + updates.name = trimmedName === '' ? null : trimmedName; + } + } if (ps.description !== undefined) profileUpdates.description = ps.description; if (ps.lang !== undefined) profileUpdates.lang = ps.lang; if (ps.location !== undefined) profileUpdates.location = ps.location; @@ -289,14 +297,16 @@ export default class extends Endpoint { // eslint- } if (ps.mutedWords !== undefined) { - checkMuteWordCount(ps.mutedWords, (await this.roleService.getUserPolicies(user.id)).wordMuteLimit); + policies ??= await this.roleService.getUserPolicies(user.id); + checkMuteWordCount(ps.mutedWords, policies.wordMuteLimit); validateMuteWordRegex(ps.mutedWords); profileUpdates.mutedWords = ps.mutedWords; profileUpdates.enableWordMute = ps.mutedWords.length > 0; } if (ps.hardMutedWords !== undefined) { - checkMuteWordCount(ps.hardMutedWords, (await this.roleService.getUserPolicies(user.id)).wordMuteLimit); + policies ??= await this.roleService.getUserPolicies(user.id); + checkMuteWordCount(ps.hardMutedWords, policies.wordMuteLimit); validateMuteWordRegex(ps.hardMutedWords); profileUpdates.hardMutedWords = ps.hardMutedWords; } @@ -315,13 +325,17 @@ export default class extends Endpoint { // eslint- if (typeof ps.injectFeaturedNote === 'boolean') profileUpdates.injectFeaturedNote = ps.injectFeaturedNote; if (typeof ps.receiveAnnouncementEmail === 'boolean') profileUpdates.receiveAnnouncementEmail = ps.receiveAnnouncementEmail; if (typeof ps.alwaysMarkNsfw === 'boolean') { - if ((await roleService.getUserPolicies(user.id)).alwaysMarkNsfw) throw new ApiError(meta.errors.restrictedByRole); + policies ??= await this.roleService.getUserPolicies(user.id); + if (policies.alwaysMarkNsfw) throw new ApiError(meta.errors.restrictedByRole); profileUpdates.alwaysMarkNsfw = ps.alwaysMarkNsfw; } if (typeof ps.autoSensitive === 'boolean') profileUpdates.autoSensitive = ps.autoSensitive; if (ps.emailNotificationTypes !== undefined) profileUpdates.emailNotificationTypes = ps.emailNotificationTypes; if (ps.avatarId) { + policies ??= await this.roleService.getUserPolicies(user.id); + if (!policies.canUpdateBioMedia) throw new ApiError(meta.errors.restrictedByRole); + const avatar = await this.driveFilesRepository.findOneBy({ id: ps.avatarId }); if (avatar == null || avatar.userId !== user.id) throw new ApiError(meta.errors.noSuchAvatar); @@ -337,6 +351,9 @@ export default class extends Endpoint { // eslint- } if (ps.bannerId) { + policies ??= await this.roleService.getUserPolicies(user.id); + if (!policies.canUpdateBioMedia) throw new ApiError(meta.errors.restrictedByRole); + const banner = await this.driveFilesRepository.findOneBy({ id: ps.bannerId }); if (banner == null || banner.userId !== user.id) throw new ApiError(meta.errors.noSuchBanner); @@ -352,14 +369,15 @@ export default class extends Endpoint { // eslint- } if (ps.avatarDecorations) { + policies ??= await this.roleService.getUserPolicies(user.id); const decorations = await this.avatarDecorationService.getAll(true); - const [myRoles, myPolicies] = await Promise.all([this.roleService.getUserRoles(user.id), this.roleService.getUserPolicies(user.id)]); + const myRoles = await this.roleService.getUserRoles(user.id); const allRoles = await this.roleService.getRoles(); const decorationIds = decorations .filter(d => d.roleIdsThatCanBeUsedThisDecoration.filter(roleId => allRoles.some(r => r.id === roleId)).length === 0 || myRoles.some(r => d.roleIdsThatCanBeUsedThisDecoration.includes(r.id))) .map(d => d.id); - if (ps.avatarDecorations.length > myPolicies.avatarDecorationLimit) throw new ApiError(meta.errors.restrictedByRole); + if (ps.avatarDecorations.length > policies.avatarDecorationLimit) throw new ApiError(meta.errors.restrictedByRole); updates.avatarDecorations = ps.avatarDecorations.filter(d => decorationIds.includes(d.id)).map(d => ({ id: d.id, diff --git a/packages/backend/src/server/api/endpoints/i/webhooks/create.ts b/packages/backend/src/server/api/endpoints/i/webhooks/create.ts index c692380288..9eb7f5b3a0 100644 --- a/packages/backend/src/server/api/endpoints/i/webhooks/create.ts +++ b/packages/backend/src/server/api/endpoints/i/webhooks/create.ts @@ -85,7 +85,7 @@ export default class extends Endpoint { // eslint- const currentWebhooksCount = await this.webhooksRepository.countBy({ userId: me.id, }); - if (currentWebhooksCount > (await this.roleService.getUserPolicies(me.id)).webhookLimit) { + if (currentWebhooksCount >= (await this.roleService.getUserPolicies(me.id)).webhookLimit) { throw new ApiError(meta.errors.tooManyWebhooks); } diff --git a/packages/backend/src/server/api/endpoints/i/webhooks/update.ts b/packages/backend/src/server/api/endpoints/i/webhooks/update.ts index 6e380d76f8..07a25bd82a 100644 --- a/packages/backend/src/server/api/endpoints/i/webhooks/update.ts +++ b/packages/backend/src/server/api/endpoints/i/webhooks/update.ts @@ -34,13 +34,13 @@ export const paramDef = { webhookId: { type: 'string', format: 'misskey:id' }, name: { type: 'string', minLength: 1, maxLength: 100 }, url: { type: 'string', minLength: 1, maxLength: 1024 }, - secret: { type: 'string', maxLength: 1024, default: '' }, + secret: { type: 'string', nullable: true, maxLength: 1024 }, on: { type: 'array', items: { type: 'string', enum: webhookEventTypes, } }, active: { type: 'boolean' }, }, - required: ['webhookId', 'name', 'url', 'on', 'active'], + required: ['webhookId'], } as const; // TODO: ロジックをサービスに切り出す @@ -66,7 +66,7 @@ export default class extends Endpoint { // eslint- await this.webhooksRepository.update(webhook.id, { name: ps.name, url: ps.url, - secret: ps.secret, + secret: ps.secret === null ? '' : ps.secret, on: ps.on, active: ps.active, }); diff --git a/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts b/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts index 5acc9706d3..f6084b5763 100644 --- a/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts +++ b/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts @@ -139,6 +139,7 @@ export default class extends Endpoint { // eslint- timelineConfig = [ `homeTimeline:${me.id}`, 'localTimeline', + `localTimelineWithReplyTo:${me.id}`, ]; } diff --git a/packages/backend/src/server/api/endpoints/notes/reactions/create.ts b/packages/backend/src/server/api/endpoints/notes/reactions/create.ts index b9899608bf..0f0dcca605 100644 --- a/packages/backend/src/server/api/endpoints/notes/reactions/create.ts +++ b/packages/backend/src/server/api/endpoints/notes/reactions/create.ts @@ -36,6 +36,12 @@ export const meta = { code: 'YOU_HAVE_BEEN_BLOCKED', id: '20ef5475-9f38-4e4c-bd33-de6d979498ec', }, + + cannotReactToRenote: { + message: 'You cannot react to Renote.', + code: 'CANNOT_REACT_TO_RENOTE', + id: 'eaccdc08-ddef-43fe-908f-d108faad57f5', + }, }, } as const; @@ -62,6 +68,7 @@ export default class extends Endpoint { // eslint- await this.reactionService.create(me, note, ps.reaction).catch(err => { if (err.id === '51c42bb4-931a-456b-bff7-e5a8a70dd298') throw new ApiError(meta.errors.alreadyReacted); if (err.id === 'e70412a4-7197-4726-8e74-f3e0deb92aa7') throw new ApiError(meta.errors.youHaveBeenBlocked); + if (err.id === '12c35529-3c79-4327-b1cc-e2cf63a71925') throw new ApiError(meta.errors.cannotReactToRenote); throw err; }); return; diff --git a/packages/backend/src/server/api/endpoints/pages/update.ts b/packages/backend/src/server/api/endpoints/pages/update.ts index b8e5e70a25..f11bbbcb1a 100644 --- a/packages/backend/src/server/api/endpoints/pages/update.ts +++ b/packages/backend/src/server/api/endpoints/pages/update.ts @@ -70,7 +70,7 @@ export const paramDef = { alignCenter: { type: 'boolean' }, hideTitleWhenPinned: { type: 'boolean' }, }, - required: ['pageId', 'title', 'name', 'content', 'variables', 'script'], + required: ['pageId'], } as const; @Injectable() @@ -91,9 +91,8 @@ export default class extends Endpoint { // eslint- throw new ApiError(meta.errors.accessDenied); } - let eyeCatchingImage = null; if (ps.eyeCatchingImageId != null) { - eyeCatchingImage = await this.driveFilesRepository.findOneBy({ + const eyeCatchingImage = await this.driveFilesRepository.findOneBy({ id: ps.eyeCatchingImageId, userId: me.id, }); @@ -116,23 +115,15 @@ export default class extends Endpoint { // eslint- await this.pagesRepository.update(page.id, { updatedAt: new Date(), title: ps.title, - // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - name: ps.name === undefined ? page.name : ps.name, + name: ps.name, summary: ps.summary === undefined ? page.summary : ps.summary, content: ps.content, variables: ps.variables, script: ps.script, - // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - alignCenter: ps.alignCenter === undefined ? page.alignCenter : ps.alignCenter, - // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - hideTitleWhenPinned: ps.hideTitleWhenPinned === undefined ? page.hideTitleWhenPinned : ps.hideTitleWhenPinned, - // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - font: ps.font === undefined ? page.font : ps.font, - eyeCatchingImageId: ps.eyeCatchingImageId === null - ? null - : ps.eyeCatchingImageId === undefined - ? page.eyeCatchingImageId - : eyeCatchingImage!.id, + alignCenter: ps.alignCenter, + hideTitleWhenPinned: ps.hideTitleWhenPinned, + font: ps.font, + eyeCatchingImageId: ps.eyeCatchingImageId, }); }); } diff --git a/packages/backend/src/server/api/endpoints/pinned-users.ts b/packages/backend/src/server/api/endpoints/pinned-users.ts index 784766bcb5..15832ef7f8 100644 --- a/packages/backend/src/server/api/endpoints/pinned-users.ts +++ b/packages/backend/src/server/api/endpoints/pinned-users.ts @@ -12,7 +12,6 @@ import { Endpoint } from '@/server/api/endpoint-base.js'; import { MetaService } from '@/core/MetaService.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { DI } from '@/di-symbols.js'; -import { isNotNull } from '@/misc/is-not-null.js'; export const meta = { tags: ['users'], @@ -53,7 +52,7 @@ export default class extends Endpoint { // eslint- host: acct.host ?? IsNull(), }))); - return await this.userEntityService.packMany(users.filter(isNotNull), me, { schema: 'UserDetailed' }); + return await this.userEntityService.packMany(users.filter(x => x != null), me, { schema: 'UserDetailed' }); }); } } diff --git a/packages/backend/src/server/api/endpoints/renote-mute/create.ts b/packages/backend/src/server/api/endpoints/renote-mute/create.ts index 39bf0cc428..84a1f010d4 100644 --- a/packages/backend/src/server/api/endpoints/renote-mute/create.ts +++ b/packages/backend/src/server/api/endpoints/renote-mute/create.ts @@ -6,12 +6,11 @@ import { Inject, Injectable } from '@nestjs/common'; import ms from 'ms'; import { Endpoint } from '@/server/api/endpoint-base.js'; -import { IdService } from '@/core/IdService.js'; -import type { RenoteMutingsRepository } from '@/models/_.js'; -import type { MiRenoteMuting } from '@/models/RenoteMuting.js'; import { DI } from '@/di-symbols.js'; import { GetterService } from '@/server/api/GetterService.js'; import { ApiError } from '../../error.js'; +import { UserRenoteMutingService } from "@/core/UserRenoteMutingService.js"; +import type { RenoteMutingsRepository } from '@/models/_.js'; export const meta = { tags: ['account'], @@ -62,7 +61,7 @@ export default class extends Endpoint { // eslint- private renoteMutingsRepository: RenoteMutingsRepository, private getterService: GetterService, - private idService: IdService, + private userRenoteMutingService: UserRenoteMutingService, ) { super(meta, paramDef, async (ps, me) => { const muter = me; @@ -79,21 +78,19 @@ export default class extends Endpoint { // eslint- }); // Check if already muting - const exist = await this.renoteMutingsRepository.findOneBy({ - muterId: muter.id, - muteeId: mutee.id, + const exist = await this.renoteMutingsRepository.exists({ + where: { + muterId: muter.id, + muteeId: mutee.id, + }, }); - if (exist != null) { + if (exist === true) { throw new ApiError(meta.errors.alreadyMuting); } // Create mute - await this.renoteMutingsRepository.insert({ - id: this.idService.gen(), - muterId: muter.id, - muteeId: mutee.id, - } as MiRenoteMuting); + await this.userRenoteMutingService.mute(muter, mutee); }); } } diff --git a/packages/backend/src/server/api/endpoints/renote-mute/delete.ts b/packages/backend/src/server/api/endpoints/renote-mute/delete.ts index 6e037cc07e..1a584b8404 100644 --- a/packages/backend/src/server/api/endpoints/renote-mute/delete.ts +++ b/packages/backend/src/server/api/endpoints/renote-mute/delete.ts @@ -5,10 +5,11 @@ import { Inject, Injectable } from '@nestjs/common'; import { Endpoint } from '@/server/api/endpoint-base.js'; -import type { RenoteMutingsRepository } from '@/models/_.js'; import { DI } from '@/di-symbols.js'; import { GetterService } from '@/server/api/GetterService.js'; import { ApiError } from '../../error.js'; +import { UserRenoteMutingService } from "@/core/UserRenoteMutingService.js"; +import type { RenoteMutingsRepository } from '@/models/_.js'; export const meta = { tags: ['account'], @@ -53,6 +54,7 @@ export default class extends Endpoint { // eslint- private renoteMutingsRepository: RenoteMutingsRepository, private getterService: GetterService, + private userRenoteMutingService: UserRenoteMutingService, ) { super(meta, paramDef, async (ps, me) => { const muter = me; @@ -79,9 +81,7 @@ export default class extends Endpoint { // eslint- } // Delete mute - await this.renoteMutingsRepository.delete({ - id: exist.id, - }); + await this.userRenoteMutingService.unmute([exist]); }); } } diff --git a/packages/backend/src/server/api/endpoints/users/lists/create-from-public.ts b/packages/backend/src/server/api/endpoints/users/lists/create-from-public.ts index 8504da0209..7e44d501ab 100644 --- a/packages/backend/src/server/api/endpoints/users/lists/create-from-public.ts +++ b/packages/backend/src/server/api/endpoints/users/lists/create-from-public.ts @@ -100,7 +100,7 @@ export default class extends Endpoint { // eslint- const currentCount = await this.userListsRepository.countBy({ userId: me.id, }); - if (currentCount > (await this.roleService.getUserPolicies(me.id)).userListLimit) { + if (currentCount >= (await this.roleService.getUserPolicies(me.id)).userListLimit) { throw new ApiError(meta.errors.tooManyUserLists); } diff --git a/packages/backend/src/server/api/endpoints/users/lists/create.ts b/packages/backend/src/server/api/endpoints/users/lists/create.ts index 9378bde5cb..7daf05ba4e 100644 --- a/packages/backend/src/server/api/endpoints/users/lists/create.ts +++ b/packages/backend/src/server/api/endpoints/users/lists/create.ts @@ -61,7 +61,7 @@ export default class extends Endpoint { // eslint- const currentCount = await this.userListsRepository.countBy({ userId: me.id, }); - if (currentCount > (await this.roleService.getUserPolicies(me.id)).userListLimit) { + if (currentCount >= (await this.roleService.getUserPolicies(me.id)).userListLimit) { throw new ApiError(meta.errors.tooManyUserLists); } diff --git a/packages/backend/src/server/api/endpoints/users/reactions.ts b/packages/backend/src/server/api/endpoints/users/reactions.ts index aca883a052..7805ae3288 100644 --- a/packages/backend/src/server/api/endpoints/users/reactions.ts +++ b/packages/backend/src/server/api/endpoints/users/reactions.ts @@ -12,6 +12,7 @@ import { DI } from '@/di-symbols.js'; import { CacheService } from '@/core/CacheService.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { RoleService } from '@/core/RoleService.js'; +import { isUserRelated } from '@/misc/is-user-related.js'; import { ApiError } from '../../error.js'; export const meta = { @@ -74,6 +75,7 @@ export default class extends Endpoint { // eslint- private roleService: RoleService, ) { super(meta, paramDef, async (ps, me) => { + const userIdsWhoBlockingMe = me ? await this.cacheService.userBlockedCache.fetch(me.id) : new Set(); const iAmModerator = me ? await this.roleService.isModerator(me) : false; // Moderators can see reactions of all users if (!iAmModerator) { const user = await this.cacheService.findUserById(ps.userId); @@ -85,8 +87,15 @@ export default class extends Endpoint { // eslint- if ((me == null || me.id !== ps.userId) && !profile.publicReactions) { throw new ApiError(meta.errors.reactionsNotPublic); } + + // early return if me is blocked by requesting user + if (userIdsWhoBlockingMe.has(ps.userId)) { + return []; + } } + const userIdsWhoMeMuting = me ? await this.cacheService.userMutingsCache.fetch(me.id) : new Set(); + const query = this.queryService.makePaginationQuery(this.noteReactionsRepository.createQueryBuilder('reaction'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate) .andWhere('reaction.userId = :userId', { userId: ps.userId }) @@ -94,9 +103,15 @@ export default class extends Endpoint { // eslint- this.queryService.generateVisibilityQuery(query, me); - const reactions = await query + const reactions = (await query .limit(ps.limit) - .getMany(); + .getMany()).filter(reaction => { + if (reaction.note?.userId === ps.userId) return true; // we can see reactions to note of requesting user + if (me && isUserRelated(reaction.note, userIdsWhoBlockingMe)) return false; + if (me && isUserRelated(reaction.note, userIdsWhoMeMuting)) return false; + + return true; + }); return await this.noteReactionEntityService.packMany(reactions, me, { withNote: true }); }); diff --git a/packages/backend/src/server/api/endpoints/users/report-abuse.ts b/packages/backend/src/server/api/endpoints/users/report-abuse.ts index 48e14b68cc..5ff6de37d2 100644 --- a/packages/backend/src/server/api/endpoints/users/report-abuse.ts +++ b/packages/backend/src/server/api/endpoints/users/report-abuse.ts @@ -3,17 +3,11 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import sanitizeHtml from 'sanitize-html'; -import { Inject, Injectable } from '@nestjs/common'; -import type { AbuseUserReportsRepository } from '@/models/_.js'; -import { IdService } from '@/core/IdService.js'; +import { Injectable } from '@nestjs/common'; import { Endpoint } from '@/server/api/endpoint-base.js'; -import { GlobalEventService } from '@/core/GlobalEventService.js'; -import { MetaService } from '@/core/MetaService.js'; -import { EmailService } from '@/core/EmailService.js'; -import { DI } from '@/di-symbols.js'; import { GetterService } from '@/server/api/GetterService.js'; import { RoleService } from '@/core/RoleService.js'; +import { AbuseReportService } from '@/core/AbuseReportService.js'; import { ApiError } from '../../error.js'; export const meta = { @@ -57,60 +51,32 @@ export const paramDef = { @Injectable() export default class extends Endpoint { // eslint-disable-line import/no-default-export constructor( - @Inject(DI.abuseUserReportsRepository) - private abuseUserReportsRepository: AbuseUserReportsRepository, - - private idService: IdService, - private metaService: MetaService, - private emailService: EmailService, private getterService: GetterService, private roleService: RoleService, - private globalEventService: GlobalEventService, + private abuseReportService: AbuseReportService, ) { super(meta, paramDef, async (ps, me) => { // Lookup user - const user = await this.getterService.getUser(ps.userId).catch(err => { + const targetUser = await this.getterService.getUser(ps.userId).catch(err => { if (err.id === '15348ddd-432d-49c2-8a5a-8069753becff') throw new ApiError(meta.errors.noSuchUser); throw err; }); - if (user.id === me.id) { + if (targetUser.id === me.id) { throw new ApiError(meta.errors.cannotReportYourself); } - if (await this.roleService.isAdministrator(user)) { + if (await this.roleService.isAdministrator(targetUser)) { throw new ApiError(meta.errors.cannotReportAdmin); } - const report = await this.abuseUserReportsRepository.insertOne({ - id: this.idService.gen(), - targetUserId: user.id, - targetUserHost: user.host, + await this.abuseReportService.report([{ + targetUserId: targetUser.id, + targetUserHost: targetUser.host, reporterId: me.id, reporterHost: null, comment: ps.comment, - }); - - // Publish event to moderators - setImmediate(async () => { - const moderators = await this.roleService.getModerators(); - - for (const moderator of moderators) { - this.globalEventService.publishAdminStream(moderator.id, 'newAbuseUserReport', { - id: report.id, - targetUserId: report.targetUserId, - reporterId: report.reporterId, - comment: report.comment, - }); - } - - const meta = await this.metaService.fetch(); - if (meta.email) { - this.emailService.sendEmail(meta.email, 'New abuse report', - sanitizeHtml(ps.comment), - sanitizeHtml(ps.comment)); - } - }); + }]); }); } } diff --git a/packages/backend/src/server/api/endpoints/users/search-by-username-and-host.ts b/packages/backend/src/server/api/endpoints/users/search-by-username-and-host.ts index 7b3bdab327..8ff952dcb5 100644 --- a/packages/backend/src/server/api/endpoints/users/search-by-username-and-host.ts +++ b/packages/backend/src/server/api/endpoints/users/search-by-username-and-host.ts @@ -3,15 +3,9 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import { Brackets } from 'typeorm'; -import { Inject, Injectable } from '@nestjs/common'; -import type { UsersRepository, FollowingsRepository } from '@/models/_.js'; -import type { Config } from '@/config.js'; -import type { MiUser } from '@/models/User.js'; +import { Injectable } from '@nestjs/common'; import { Endpoint } from '@/server/api/endpoint-base.js'; -import { UserEntityService } from '@/core/entities/UserEntityService.js'; -import { DI } from '@/di-symbols.js'; -import { sqlLikeEscape } from '@/misc/sql-like-escape.js'; +import { UserSearchService } from '@/core/UserSearchService.js'; export const meta = { tags: ['users'], @@ -49,89 +43,16 @@ export const paramDef = { @Injectable() export default class extends Endpoint { // eslint-disable-line import/no-default-export constructor( - @Inject(DI.config) - private config: Config, - - @Inject(DI.usersRepository) - private usersRepository: UsersRepository, - - @Inject(DI.followingsRepository) - private followingsRepository: FollowingsRepository, - - private userEntityService: UserEntityService, + private userSearchService: UserSearchService, ) { - super(meta, paramDef, async (ps, me) => { - const setUsernameAndHostQuery = (query = this.usersRepository.createQueryBuilder('user')) => { - if (ps.username) { - query.andWhere('user.usernameLower LIKE :username', { username: sqlLikeEscape(ps.username.toLowerCase()) + '%' }); - } - - if (ps.host) { - if (ps.host === this.config.hostname || ps.host === '.') { - query.andWhere('user.host IS NULL'); - } else { - query.andWhere('user.host LIKE :host', { - host: sqlLikeEscape(ps.host.toLowerCase()) + '%', - }); - } - } - - return query; - }; - - const activeThreshold = new Date(Date.now() - (1000 * 60 * 60 * 24 * 30)); // 30日 - - let users: MiUser[] = []; - - if (me) { - const followingQuery = this.followingsRepository.createQueryBuilder('following') - .select('following.followeeId') - .where('following.followerId = :followerId', { followerId: me.id }); - - const query = setUsernameAndHostQuery() - .andWhere(`user.id IN (${ followingQuery.getQuery() })`) - .andWhere('user.id != :meId', { meId: me.id }) - .andWhere('user.isSuspended = FALSE') - .andWhere(new Brackets(qb => { - qb - .where('user.updatedAt IS NULL') - .orWhere('user.updatedAt > :activeThreshold', { activeThreshold: activeThreshold }); - })); - - query.setParameters(followingQuery.getParameters()); - - users = await query - .orderBy('user.usernameLower', 'ASC') - .limit(ps.limit) - .getMany(); - - if (users.length < ps.limit) { - const otherQuery = setUsernameAndHostQuery() - .andWhere(`user.id NOT IN (${ followingQuery.getQuery() })`) - .andWhere('user.isSuspended = FALSE') - .andWhere('user.updatedAt IS NOT NULL'); - - otherQuery.setParameters(followingQuery.getParameters()); - - const otherUsers = await otherQuery - .orderBy('user.updatedAt', 'DESC') - .limit(ps.limit - users.length) - .getMany(); - - users = users.concat(otherUsers); - } - } else { - const query = setUsernameAndHostQuery() - .andWhere('user.isSuspended = FALSE') - .andWhere('user.updatedAt IS NOT NULL'); - - users = await query - .orderBy('user.updatedAt', 'DESC') - .limit(ps.limit - users.length) - .getMany(); - } - - return await this.userEntityService.packMany(users, me, { schema: ps.detail ? 'UserDetailed' : 'UserLite' }); + super(meta, paramDef, (ps, me) => { + return this.userSearchService.search({ + username: ps.username, + host: ps.host, + }, { + limit: ps.limit, + detail: ps.detail, + }, me); }); } } diff --git a/packages/backend/src/server/api/openapi/OpenApiServerService.ts b/packages/backend/src/server/api/openapi/OpenApiServerService.ts index 5210e4d2bc..f124aa9f39 100644 --- a/packages/backend/src/server/api/openapi/OpenApiServerService.ts +++ b/packages/backend/src/server/api/openapi/OpenApiServerService.ts @@ -25,7 +25,7 @@ export class OpenApiServerService { public createServer(fastify: FastifyInstance, _options: FastifyPluginOptions, done: (err?: Error) => void) { fastify.get('/api-doc', async (_request, reply) => { reply.header('Cache-Control', 'public, max-age=86400'); - return await reply.sendFile('/redoc.html', staticAssets); + return await reply.sendFile('/api-doc.html', staticAssets); }); fastify.get('/api.json', (_request, reply) => { reply.header('Cache-Control', 'public, max-age=600'); diff --git a/packages/backend/src/server/api/openapi/gen-spec.ts b/packages/backend/src/server/api/openapi/gen-spec.ts index 2a14270a24..efa47a6986 100644 --- a/packages/backend/src/server/api/openapi/gen-spec.ts +++ b/packages/backend/src/server/api/openapi/gen-spec.ts @@ -15,7 +15,6 @@ export function genOpenapiSpec(config: Config, includeSelfRef = false) { info: { version: config.version, title: 'Misskey API', - 'x-logo': { url: '/static-assets/api-doc.png' }, }, externalDocs: { diff --git a/packages/backend/src/server/api/stream/Connection.ts b/packages/backend/src/server/api/stream/Connection.ts index 41c0feccc7..96082827f8 100644 --- a/packages/backend/src/server/api/stream/Connection.ts +++ b/packages/backend/src/server/api/stream/Connection.ts @@ -14,6 +14,7 @@ import { CacheService } from '@/core/CacheService.js'; import { MiFollowing, MiUserProfile } from '@/models/_.js'; import type { StreamEventEmitter, GlobalEvents } from '@/core/GlobalEventService.js'; import { ChannelFollowingService } from '@/core/ChannelFollowingService.js'; +import type { JsonObject } from '@/misc/json-value.js'; import type { ChannelsService } from './ChannelsService.js'; import type { EventEmitter } from 'events'; import type Channel from './channel.js'; @@ -28,7 +29,7 @@ export default class Connection { private wsConnection: WebSocket.WebSocket; public subscriber: StreamEventEmitter; private channels: Channel[] = []; - private subscribingNotes: any = {}; + private subscribingNotes: Partial> = {}; private cachedNotes: Packed<'Note'>[] = []; public userProfile: MiUserProfile | null = null; public following: Record | undefined> = {}; @@ -101,7 +102,7 @@ export default class Connection { */ @bindThis private async onWsConnectionMessage(data: WebSocket.RawData) { - let obj: Record; + let obj: JsonObject; try { obj = JSON.parse(data.toString()); @@ -111,6 +112,8 @@ export default class Connection { const { type, body } = obj; + if (typeof body !== 'object' || body === null || Array.isArray(body)) return; + switch (type) { case 'readNotification': this.onReadNotification(body); break; case 'subNote': this.onSubscribeNote(body); break; @@ -151,7 +154,7 @@ export default class Connection { } @bindThis - private readNote(body: any) { + private readNote(body: JsonObject) { const id = body.id; const note = this.cachedNotes.find(n => n.id === id); @@ -163,7 +166,7 @@ export default class Connection { } @bindThis - private onReadNotification(payload: any) { + private onReadNotification(payload: JsonObject) { this.notificationService.readAllNotification(this.user!.id); } @@ -171,16 +174,14 @@ export default class Connection { * 投稿購読要求時 */ @bindThis - private onSubscribeNote(payload: any) { - if (!payload.id) return; + private onSubscribeNote(payload: JsonObject) { + if (!payload.id || typeof payload.id !== 'string') return; - if (this.subscribingNotes[payload.id] == null) { - this.subscribingNotes[payload.id] = 0; - } + const current = this.subscribingNotes[payload.id] ?? 0; + const updated = current + 1; + this.subscribingNotes[payload.id] = updated; - this.subscribingNotes[payload.id]++; - - if (this.subscribingNotes[payload.id] === 1) { + if (updated === 1) { this.subscriber.on(`noteStream:${payload.id}`, this.onNoteStreamMessage); } } @@ -189,11 +190,14 @@ export default class Connection { * 投稿購読解除要求時 */ @bindThis - private onUnsubscribeNote(payload: any) { - if (!payload.id) return; + private onUnsubscribeNote(payload: JsonObject) { + if (!payload.id || typeof payload.id !== 'string') return; - this.subscribingNotes[payload.id]--; - if (this.subscribingNotes[payload.id] <= 0) { + const current = this.subscribingNotes[payload.id]; + if (current == null) return; + const updated = current - 1; + this.subscribingNotes[payload.id] = updated; + if (updated <= 0) { delete this.subscribingNotes[payload.id]; this.subscriber.off(`noteStream:${payload.id}`, this.onNoteStreamMessage); } @@ -212,17 +216,22 @@ export default class Connection { * チャンネル接続要求時 */ @bindThis - private onChannelConnectRequested(payload: any) { + private onChannelConnectRequested(payload: JsonObject) { const { channel, id, params, pong } = payload; - this.connectChannel(id, params, channel, pong); + if (typeof id !== 'string') return; + if (typeof channel !== 'string') return; + if (typeof pong !== 'boolean' && typeof pong !== 'undefined' && pong !== null) return; + if (typeof params !== 'undefined' && (typeof params !== 'object' || params === null || Array.isArray(params))) return; + this.connectChannel(id, params, channel, pong ?? undefined); } /** * チャンネル切断要求時 */ @bindThis - private onChannelDisconnectRequested(payload: any) { + private onChannelDisconnectRequested(payload: JsonObject) { const { id } = payload; + if (typeof id !== 'string') return; this.disconnectChannel(id); } @@ -230,7 +239,7 @@ export default class Connection { * クライアントにメッセージ送信 */ @bindThis - public sendMessageToWs(type: string, payload: any) { + public sendMessageToWs(type: string, payload: JsonObject) { this.wsConnection.send(JSON.stringify({ type: type, body: payload, @@ -241,7 +250,7 @@ export default class Connection { * チャンネルに接続 */ @bindThis - public connectChannel(id: string, params: any, channel: string, pong = false) { + public connectChannel(id: string, params: JsonObject | undefined, channel: string, pong = false) { const channelService = this.channelsService.getChannelService(channel); if (channelService.requireCredential && this.user == null) { @@ -288,7 +297,11 @@ export default class Connection { * @param data メッセージ */ @bindThis - private onChannelMessageRequested(data: any) { + private onChannelMessageRequested(data: JsonObject) { + if (typeof data.id !== 'string') return; + if (typeof data.type !== 'string') return; + if (typeof data.body === 'undefined') return; + const channel = this.channels.find(c => c.id === data.id); if (channel != null && channel.onMessage != null) { channel.onMessage(data.type, data.body); diff --git a/packages/backend/src/server/api/stream/channel.ts b/packages/backend/src/server/api/stream/channel.ts index a267d27fba..84cb552369 100644 --- a/packages/backend/src/server/api/stream/channel.ts +++ b/packages/backend/src/server/api/stream/channel.ts @@ -8,6 +8,7 @@ import { isInstanceMuted } from '@/misc/is-instance-muted.js'; import { isUserRelated } from '@/misc/is-user-related.js'; import { isRenotePacked, isQuotePacked } from '@/misc/is-renote.js'; import type { Packed } from '@/misc/json-schema.js'; +import type { JsonObject, JsonValue } from '@/misc/json-value.js'; import type Connection from './Connection.js'; /** @@ -81,10 +82,12 @@ export default abstract class Channel { this.connection = connection; } + public send(payload: { type: string, body: JsonValue }): void + public send(type: string, payload: JsonValue): void @bindThis - public send(typeOrPayload: any, payload?: any) { - const type = payload === undefined ? typeOrPayload.type : typeOrPayload; - const body = payload === undefined ? typeOrPayload.body : payload; + public send(typeOrPayload: { type: string, body: JsonValue } | string, payload?: JsonValue) { + const type = payload === undefined ? (typeOrPayload as { type: string, body: JsonValue }).type : (typeOrPayload as string); + const body = payload === undefined ? (typeOrPayload as { type: string, body: JsonValue }).body : payload; this.connection.sendMessageToWs('channel', { id: this.id, @@ -93,11 +96,11 @@ export default abstract class Channel { }); } - public abstract init(params: any): void; + public abstract init(params: JsonObject): void; public dispose?(): void; - public onMessage?(type: string, body: any): void; + public onMessage?(type: string, body: JsonValue): void; } export type MiChannelService = { diff --git a/packages/backend/src/server/api/stream/channels/admin.ts b/packages/backend/src/server/api/stream/channels/admin.ts index 92b6d2ac04..355d5dba21 100644 --- a/packages/backend/src/server/api/stream/channels/admin.ts +++ b/packages/backend/src/server/api/stream/channels/admin.ts @@ -5,6 +5,7 @@ import { Injectable } from '@nestjs/common'; import { bindThis } from '@/decorators.js'; +import type { JsonObject } from '@/misc/json-value.js'; import Channel, { type MiChannelService } from '../channel.js'; class AdminChannel extends Channel { @@ -14,7 +15,7 @@ class AdminChannel extends Channel { public static kind = 'read:admin:stream'; @bindThis - public async init(params: any) { + public async init(params: JsonObject) { // Subscribe admin stream this.subscriber.on(`adminStream:${this.user!.id}`, data => { this.send(data); diff --git a/packages/backend/src/server/api/stream/channels/antenna.ts b/packages/backend/src/server/api/stream/channels/antenna.ts index 4a1d2dd109..53dc7f18b6 100644 --- a/packages/backend/src/server/api/stream/channels/antenna.ts +++ b/packages/backend/src/server/api/stream/channels/antenna.ts @@ -7,6 +7,7 @@ import { Injectable } from '@nestjs/common'; import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; import { bindThis } from '@/decorators.js'; import type { GlobalEvents } from '@/core/GlobalEventService.js'; +import type { JsonObject } from '@/misc/json-value.js'; import Channel, { type MiChannelService } from '../channel.js'; class AntennaChannel extends Channel { @@ -27,8 +28,9 @@ class AntennaChannel extends Channel { } @bindThis - public async init(params: any) { - this.antennaId = params.antennaId as string; + public async init(params: JsonObject) { + if (typeof params.antennaId !== 'string') return; + this.antennaId = params.antennaId; // Subscribe stream this.subscriber.on(`antennaStream:${this.antennaId}`, this.onEvent); diff --git a/packages/backend/src/server/api/stream/channels/channel.ts b/packages/backend/src/server/api/stream/channels/channel.ts index 140dd3dd9b..7108e0cd6e 100644 --- a/packages/backend/src/server/api/stream/channels/channel.ts +++ b/packages/backend/src/server/api/stream/channels/channel.ts @@ -8,6 +8,7 @@ import type { Packed } from '@/misc/json-schema.js'; import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; import { bindThis } from '@/decorators.js'; import { isRenotePacked, isQuotePacked } from '@/misc/is-renote.js'; +import type { JsonObject } from '@/misc/json-value.js'; import Channel, { type MiChannelService } from '../channel.js'; class ChannelChannel extends Channel { @@ -27,8 +28,9 @@ class ChannelChannel extends Channel { } @bindThis - public async init(params: any) { - this.channelId = params.channelId as string; + public async init(params: JsonObject) { + if (typeof params.channelId !== 'string') return; + this.channelId = params.channelId; // Subscribe stream this.subscriber.on('notesStream', this.onNote); diff --git a/packages/backend/src/server/api/stream/channels/drive.ts b/packages/backend/src/server/api/stream/channels/drive.ts index 0d9b486305..03768f3d23 100644 --- a/packages/backend/src/server/api/stream/channels/drive.ts +++ b/packages/backend/src/server/api/stream/channels/drive.ts @@ -5,6 +5,7 @@ import { Injectable } from '@nestjs/common'; import { bindThis } from '@/decorators.js'; +import type { JsonObject } from '@/misc/json-value.js'; import Channel, { type MiChannelService } from '../channel.js'; class DriveChannel extends Channel { @@ -14,7 +15,7 @@ class DriveChannel extends Channel { public static kind = 'read:account'; @bindThis - public async init(params: any) { + public async init(params: JsonObject) { // Subscribe drive stream this.subscriber.on(`driveStream:${this.user!.id}`, data => { this.send(data); diff --git a/packages/backend/src/server/api/stream/channels/global-timeline.ts b/packages/backend/src/server/api/stream/channels/global-timeline.ts index 17116258d8..ed56fe0d40 100644 --- a/packages/backend/src/server/api/stream/channels/global-timeline.ts +++ b/packages/backend/src/server/api/stream/channels/global-timeline.ts @@ -10,6 +10,7 @@ import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; import { bindThis } from '@/decorators.js'; import { RoleService } from '@/core/RoleService.js'; import { isRenotePacked, isQuotePacked } from '@/misc/is-renote.js'; +import type { JsonObject } from '@/misc/json-value.js'; import Channel, { type MiChannelService } from '../channel.js'; class GlobalTimelineChannel extends Channel { @@ -32,12 +33,12 @@ class GlobalTimelineChannel extends Channel { } @bindThis - public async init(params: any) { + public async init(params: JsonObject) { const policies = await this.roleService.getUserPolicies(this.user ? this.user.id : null); if (!policies.gtlAvailable) return; - this.withRenotes = params.withRenotes ?? true; - this.withFiles = params.withFiles ?? false; + this.withRenotes = !!(params.withRenotes ?? true); + this.withFiles = !!(params.withFiles ?? false); // Subscribe events this.subscriber.on('notesStream', this.onNote); diff --git a/packages/backend/src/server/api/stream/channels/hashtag.ts b/packages/backend/src/server/api/stream/channels/hashtag.ts index 57bada5d9c..8105f15cb1 100644 --- a/packages/backend/src/server/api/stream/channels/hashtag.ts +++ b/packages/backend/src/server/api/stream/channels/hashtag.ts @@ -9,6 +9,7 @@ import type { Packed } from '@/misc/json-schema.js'; import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; import { bindThis } from '@/decorators.js'; import { isRenotePacked, isQuotePacked } from '@/misc/is-renote.js'; +import type { JsonObject } from '@/misc/json-value.js'; import Channel, { type MiChannelService } from '../channel.js'; class HashtagChannel extends Channel { @@ -28,11 +29,11 @@ class HashtagChannel extends Channel { } @bindThis - public async init(params: any) { + public async init(params: JsonObject) { + if (!Array.isArray(params.q)) return; + if (!params.q.every(x => Array.isArray(x) && x.every(y => typeof y === 'string'))) return; this.q = params.q; - if (this.q == null) return; - // Subscribe stream this.subscriber.on('notesStream', this.onNote); } diff --git a/packages/backend/src/server/api/stream/channels/home-timeline.ts b/packages/backend/src/server/api/stream/channels/home-timeline.ts index 878a3180cb..1f440732a6 100644 --- a/packages/backend/src/server/api/stream/channels/home-timeline.ts +++ b/packages/backend/src/server/api/stream/channels/home-timeline.ts @@ -8,6 +8,7 @@ import type { Packed } from '@/misc/json-schema.js'; import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; import { bindThis } from '@/decorators.js'; import { isRenotePacked, isQuotePacked } from '@/misc/is-renote.js'; +import type { JsonObject } from '@/misc/json-value.js'; import Channel, { type MiChannelService } from '../channel.js'; class HomeTimelineChannel extends Channel { @@ -29,9 +30,9 @@ class HomeTimelineChannel extends Channel { } @bindThis - public async init(params: any) { - this.withRenotes = params.withRenotes ?? true; - this.withFiles = params.withFiles ?? false; + public async init(params: JsonObject) { + this.withRenotes = !!(params.withRenotes ?? true); + this.withFiles = !!(params.withFiles ?? false); this.subscriber.on('notesStream', this.onNote); } diff --git a/packages/backend/src/server/api/stream/channels/hybrid-timeline.ts b/packages/backend/src/server/api/stream/channels/hybrid-timeline.ts index 575d23d53c..6938b6e3ea 100644 --- a/packages/backend/src/server/api/stream/channels/hybrid-timeline.ts +++ b/packages/backend/src/server/api/stream/channels/hybrid-timeline.ts @@ -10,6 +10,7 @@ import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; import { bindThis } from '@/decorators.js'; import { RoleService } from '@/core/RoleService.js'; import { isRenotePacked, isQuotePacked } from '@/misc/is-renote.js'; +import type { JsonObject } from '@/misc/json-value.js'; import Channel, { type MiChannelService } from '../channel.js'; class HybridTimelineChannel extends Channel { @@ -34,13 +35,13 @@ class HybridTimelineChannel extends Channel { } @bindThis - public async init(params: any): Promise { + public async init(params: JsonObject): Promise { const policies = await this.roleService.getUserPolicies(this.user ? this.user.id : null); if (!policies.ltlAvailable) return; - this.withRenotes = params.withRenotes ?? true; - this.withReplies = params.withReplies ?? false; - this.withFiles = params.withFiles ?? false; + this.withRenotes = !!(params.withRenotes ?? true); + this.withReplies = !!(params.withReplies ?? false); + this.withFiles = !!(params.withFiles ?? false); // Subscribe events this.subscriber.on('notesStream', this.onNote); diff --git a/packages/backend/src/server/api/stream/channels/local-timeline.ts b/packages/backend/src/server/api/stream/channels/local-timeline.ts index 442d08ae51..491029f5de 100644 --- a/packages/backend/src/server/api/stream/channels/local-timeline.ts +++ b/packages/backend/src/server/api/stream/channels/local-timeline.ts @@ -10,6 +10,7 @@ import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; import { bindThis } from '@/decorators.js'; import { RoleService } from '@/core/RoleService.js'; import { isQuotePacked, isRenotePacked } from '@/misc/is-renote.js'; +import type { JsonObject } from '@/misc/json-value.js'; import Channel, { type MiChannelService } from '../channel.js'; class LocalTimelineChannel extends Channel { @@ -33,13 +34,13 @@ class LocalTimelineChannel extends Channel { } @bindThis - public async init(params: any) { + public async init(params: JsonObject) { const policies = await this.roleService.getUserPolicies(this.user ? this.user.id : null); if (!policies.ltlAvailable) return; - this.withRenotes = params.withRenotes ?? true; - this.withReplies = params.withReplies ?? false; - this.withFiles = params.withFiles ?? false; + this.withRenotes = !!(params.withRenotes ?? true); + this.withReplies = !!(params.withReplies ?? false); + this.withFiles = !!(params.withFiles ?? false); // Subscribe events this.subscriber.on('notesStream', this.onNote); diff --git a/packages/backend/src/server/api/stream/channels/main.ts b/packages/backend/src/server/api/stream/channels/main.ts index a12976d69d..863d7f4c4e 100644 --- a/packages/backend/src/server/api/stream/channels/main.ts +++ b/packages/backend/src/server/api/stream/channels/main.ts @@ -7,6 +7,7 @@ import { Injectable } from '@nestjs/common'; import { isInstanceMuted, isUserFromMutedInstance } from '@/misc/is-instance-muted.js'; import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; import { bindThis } from '@/decorators.js'; +import type { JsonObject } from '@/misc/json-value.js'; import Channel, { type MiChannelService } from '../channel.js'; class MainChannel extends Channel { @@ -25,7 +26,7 @@ class MainChannel extends Channel { } @bindThis - public async init(params: any) { + public async init(params: JsonObject) { // Subscribe main stream channel this.subscriber.on(`mainStream:${this.user!.id}`, async data => { switch (data.type) { diff --git a/packages/backend/src/server/api/stream/channels/queue-stats.ts b/packages/backend/src/server/api/stream/channels/queue-stats.ts index 061aa76904..ff7e740226 100644 --- a/packages/backend/src/server/api/stream/channels/queue-stats.ts +++ b/packages/backend/src/server/api/stream/channels/queue-stats.ts @@ -6,6 +6,7 @@ import Xev from 'xev'; import { Injectable } from '@nestjs/common'; import { bindThis } from '@/decorators.js'; +import type { JsonObject, JsonValue } from '@/misc/json-value.js'; import Channel, { type MiChannelService } from '../channel.js'; const ev = new Xev(); @@ -22,19 +23,22 @@ class QueueStatsChannel extends Channel { } @bindThis - public async init(params: any) { + public async init(params: JsonObject) { ev.addListener('queueStats', this.onStats); } @bindThis - private onStats(stats: any) { + private onStats(stats: JsonObject) { this.send('stats', stats); } @bindThis - public onMessage(type: string, body: any) { + public onMessage(type: string, body: JsonValue) { switch (type) { case 'requestLog': + if (typeof body !== 'object' || body === null || Array.isArray(body)) return; + if (typeof body.id !== 'string') return; + if (typeof body.length !== 'number') return; ev.once(`queueStatsLog:${body.id}`, statsLog => { this.send('statsLog', statsLog); }); diff --git a/packages/backend/src/server/api/stream/channels/reversi-game.ts b/packages/backend/src/server/api/stream/channels/reversi-game.ts index 51b1284e9a..0619274918 100644 --- a/packages/backend/src/server/api/stream/channels/reversi-game.ts +++ b/packages/backend/src/server/api/stream/channels/reversi-game.ts @@ -9,6 +9,7 @@ import { DI } from '@/di-symbols.js'; import { bindThis } from '@/decorators.js'; import { ReversiService } from '@/core/ReversiService.js'; import { ReversiGameEntityService } from '@/core/entities/ReversiGameEntityService.js'; +import type { JsonObject, JsonValue } from '@/misc/json-value.js'; import Channel, { type MiChannelService } from '../channel.js'; class ReversiGameChannel extends Channel { @@ -28,26 +29,42 @@ class ReversiGameChannel extends Channel { } @bindThis - public async init(params: any) { - this.gameId = params.gameId as string; + public async init(params: JsonObject) { + if (typeof params.gameId !== 'string') return; + this.gameId = params.gameId; this.subscriber.on(`reversiGameStream:${this.gameId}`, this.send); } @bindThis - public onMessage(type: string, body: any) { + public onMessage(type: string, body: JsonValue) { switch (type) { - case 'ready': this.ready(body); break; - case 'updateSettings': this.updateSettings(body.key, body.value); break; - case 'cancel': this.cancelGame(); break; - case 'putStone': this.putStone(body.pos, body.id); break; + case 'ready': + if (typeof body !== 'boolean') return; + this.ready(body); + break; + case 'updateSettings': + if (typeof body !== 'object' || body === null || Array.isArray(body)) return; + if (typeof body.key !== 'string') return; + if (typeof body.value !== 'object' || body.value === null || Array.isArray(body.value)) return; + this.updateSettings(body.key, body.value); + break; + case 'cancel': + this.cancelGame(); + break; + case 'putStone': + if (typeof body !== 'object' || body === null || Array.isArray(body)) return; + if (typeof body.pos !== 'number') return; + if (typeof body.id !== 'string') return; + this.putStone(body.pos, body.id); + break; case 'claimTimeIsUp': this.claimTimeIsUp(); break; case 'reaction': this.sendReaction(body); break; } } @bindThis - private async updateSettings(key: string, value: any) { + private async updateSettings(key: string, value: JsonObject) { if (this.user == null) return; this.reversiService.updateSettings(this.gameId!, this.user, key, value); diff --git a/packages/backend/src/server/api/stream/channels/reversi.ts b/packages/backend/src/server/api/stream/channels/reversi.ts index 3998a0fd36..6e88939724 100644 --- a/packages/backend/src/server/api/stream/channels/reversi.ts +++ b/packages/backend/src/server/api/stream/channels/reversi.ts @@ -5,6 +5,7 @@ import { Injectable } from '@nestjs/common'; import { bindThis } from '@/decorators.js'; +import type { JsonObject } from '@/misc/json-value.js'; import Channel, { type MiChannelService } from '../channel.js'; class ReversiChannel extends Channel { @@ -21,7 +22,7 @@ class ReversiChannel extends Channel { } @bindThis - public async init(params: any) { + public async init(params: JsonObject) { this.subscriber.on(`reversiStream:${this.user!.id}`, this.send); } diff --git a/packages/backend/src/server/api/stream/channels/role-timeline.ts b/packages/backend/src/server/api/stream/channels/role-timeline.ts index 6a4ad22460..fcfa26c38b 100644 --- a/packages/backend/src/server/api/stream/channels/role-timeline.ts +++ b/packages/backend/src/server/api/stream/channels/role-timeline.ts @@ -8,6 +8,7 @@ import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; import { bindThis } from '@/decorators.js'; import { RoleService } from '@/core/RoleService.js'; import type { GlobalEvents } from '@/core/GlobalEventService.js'; +import type { JsonObject } from '@/misc/json-value.js'; import Channel, { type MiChannelService } from '../channel.js'; class RoleTimelineChannel extends Channel { @@ -28,8 +29,9 @@ class RoleTimelineChannel extends Channel { } @bindThis - public async init(params: any) { - this.roleId = params.roleId as string; + public async init(params: JsonObject) { + if (typeof params.roleId !== 'string') return; + this.roleId = params.roleId; this.subscriber.on(`roleTimelineStream:${this.roleId}`, this.onEvent); } diff --git a/packages/backend/src/server/api/stream/channels/server-stats.ts b/packages/backend/src/server/api/stream/channels/server-stats.ts index eb4d8c9992..6258afba35 100644 --- a/packages/backend/src/server/api/stream/channels/server-stats.ts +++ b/packages/backend/src/server/api/stream/channels/server-stats.ts @@ -6,6 +6,7 @@ import Xev from 'xev'; import { Injectable } from '@nestjs/common'; import { bindThis } from '@/decorators.js'; +import type { JsonObject, JsonValue } from '@/misc/json-value.js'; import Channel, { type MiChannelService } from '../channel.js'; const ev = new Xev(); @@ -22,19 +23,20 @@ class ServerStatsChannel extends Channel { } @bindThis - public async init(params: any) { + public async init(params: JsonObject) { ev.addListener('serverStats', this.onStats); } @bindThis - private onStats(stats: any) { + private onStats(stats: JsonObject) { this.send('stats', stats); } @bindThis - public onMessage(type: string, body: any) { + public onMessage(type: string, body: JsonValue) { switch (type) { case 'requestLog': + if (typeof body !== 'object' || body === null || Array.isArray(body)) return; ev.once(`serverStatsLog:${body.id}`, statsLog => { this.send('statsLog', statsLog); }); diff --git a/packages/backend/src/server/api/stream/channels/user-list.ts b/packages/backend/src/server/api/stream/channels/user-list.ts index 14b30a157c..4f38351e94 100644 --- a/packages/backend/src/server/api/stream/channels/user-list.ts +++ b/packages/backend/src/server/api/stream/channels/user-list.ts @@ -10,6 +10,7 @@ import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; import { DI } from '@/di-symbols.js'; import { bindThis } from '@/decorators.js'; import { isRenotePacked, isQuotePacked } from '@/misc/is-renote.js'; +import type { JsonObject } from '@/misc/json-value.js'; import Channel, { type MiChannelService } from '../channel.js'; class UserListChannel extends Channel { @@ -36,10 +37,11 @@ class UserListChannel extends Channel { } @bindThis - public async init(params: any) { - this.listId = params.listId as string; - this.withFiles = params.withFiles ?? false; - this.withRenotes = params.withRenotes ?? true; + public async init(params: JsonObject) { + if (typeof params.listId !== 'string') return; + this.listId = params.listId; + this.withFiles = !!(params.withFiles ?? false); + this.withRenotes = !!(params.withRenotes ?? true); // Check existence and owner const listExist = await this.userListsRepository.exists({ diff --git a/packages/backend/src/server/web/ClientServerService.ts b/packages/backend/src/server/web/ClientServerService.ts index ab03489c0d..f55790b636 100644 --- a/packages/backend/src/server/web/ClientServerService.ts +++ b/packages/backend/src/server/web/ClientServerService.ts @@ -25,7 +25,16 @@ import { getNoteSummary } from '@/misc/get-note-summary.js'; import { DI } from '@/di-symbols.js'; import * as Acct from '@/misc/acct.js'; import { MetaService } from '@/core/MetaService.js'; -import type { DbQueue, DeliverQueue, EndedPollNotificationQueue, InboxQueue, ObjectStorageQueue, SystemQueue, WebhookDeliverQueue } from '@/core/QueueModule.js'; +import type { + DbQueue, + DeliverQueue, + EndedPollNotificationQueue, + InboxQueue, + ObjectStorageQueue, + SystemQueue, + UserWebhookDeliverQueue, + SystemWebhookDeliverQueue, +} from '@/core/QueueModule.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; import { PageEntityService } from '@/core/entities/PageEntityService.js'; @@ -111,7 +120,8 @@ export class ClientServerService { @Inject('queue:inbox') public inboxQueue: InboxQueue, @Inject('queue:db') public dbQueue: DbQueue, @Inject('queue:objectStorage') public objectStorageQueue: ObjectStorageQueue, - @Inject('queue:webhookDeliver') public webhookDeliverQueue: WebhookDeliverQueue, + @Inject('queue:userWebhookDeliver') public userWebhookDeliverQueue: UserWebhookDeliverQueue, + @Inject('queue:systemWebhookDeliver') public systemWebhookDeliverQueue: SystemWebhookDeliverQueue, ) { //this.createServer = this.createServer.bind(this); } @@ -239,7 +249,8 @@ export class ClientServerService { this.inboxQueue, this.dbQueue, this.objectStorageQueue, - this.webhookDeliverQueue, + this.userWebhookDeliverQueue, + this.systemWebhookDeliverQueue, ].map(q => new BullMQAdapter(q)), serverAdapter, }); diff --git a/packages/backend/src/server/web/FeedService.ts b/packages/backend/src/server/web/FeedService.ts index 10e3ed2682..9d810ddc84 100644 --- a/packages/backend/src/server/web/FeedService.ts +++ b/packages/backend/src/server/web/FeedService.ts @@ -14,6 +14,8 @@ import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { DriveFileEntityService } from '@/core/entities/DriveFileEntityService.js'; import { bindThis } from '@/decorators.js'; import { IdService } from '@/core/IdService.js'; +import { MfmService } from "@/core/MfmService.js"; +import { parse as mfmParse } from 'mfm-js'; @Injectable() export class FeedService { @@ -33,6 +35,7 @@ export class FeedService { private userEntityService: UserEntityService, private driveFileEntityService: DriveFileEntityService, private idService: IdService, + private mfmService: MfmService, ) { } @@ -76,13 +79,14 @@ export class FeedService { id: In(note.fileIds), }) : []; const file = files.find(file => file.type.startsWith('image/')); + const text = note.text; feed.addItem({ title: `New note by ${author.name}`, link: `${this.config.url}/notes/${note.id}`, date: this.idService.parse(note.id).date, description: note.cw ?? undefined, - content: note.text ?? undefined, + content: text ? this.mfmService.toHtml(mfmParse(text), JSON.parse(note.mentionedRemoteUsers)) ?? undefined : undefined, image: file ? this.driveFileEntityService.getPublicUrl(file) : undefined, }); } diff --git a/packages/backend/src/server/web/boot.js b/packages/backend/src/server/web/boot.js index 396536948e..4275dc9527 100644 --- a/packages/backend/src/server/web/boot.js +++ b/packages/backend/src/server/web/boot.js @@ -29,7 +29,8 @@ let forceError = localStorage.getItem('forceError'); if (forceError != null) { - renderError('FORCED_ERROR', 'This error is forced by having forceError in local storage.') + renderError('FORCED_ERROR', 'This error is forced by having forceError in local storage.'); + return; } //#region Detect language & fetch translations @@ -155,7 +156,12 @@ document.head.appendChild(css); } - function renderError(code, details) { + async function renderError(code, details) { + // Cannot set property 'innerHTML' of null を回避 + if (document.readyState === 'loading') { + await new Promise(resolve => window.addEventListener('DOMContentLoaded', resolve)); + } + let errorsElement = document.getElementById('errors'); if (!errorsElement) { @@ -314,6 +320,6 @@ #errorInfo { width: 50%; } - `) + }`) } })(); diff --git a/packages/backend/src/types.ts b/packages/backend/src/types.ts index 929070d0d2..ecbbee4eff 100644 --- a/packages/backend/src/types.ts +++ b/packages/backend/src/types.ts @@ -90,6 +90,12 @@ export const moderationLogTypes = [ 'deleteAvatarDecoration', 'unsetUserAvatar', 'unsetUserBanner', + 'createSystemWebhook', + 'updateSystemWebhook', + 'deleteSystemWebhook', + 'createAbuseReportNotificationRecipient', + 'updateAbuseReportNotificationRecipient', + 'deleteAbuseReportNotificationRecipient', ] as const; export type ModerationLogPayloads = { @@ -282,6 +288,32 @@ export type ModerationLogPayloads = { userHost: string | null; fileId: string; }; + createSystemWebhook: { + systemWebhookId: string; + webhook: any; + }; + updateSystemWebhook: { + systemWebhookId: string; + before: any; + after: any; + }; + deleteSystemWebhook: { + systemWebhookId: string; + webhook: any; + }; + createAbuseReportNotificationRecipient: { + recipientId: string; + recipient: any; + }; + updateAbuseReportNotificationRecipient: { + recipientId: string; + before: any; + after: any; + }; + deleteAbuseReportNotificationRecipient: { + recipientId: string; + recipient: any; + }; }; export type Serialized = { diff --git a/packages/backend/test-server/.eslintrc.cjs b/packages/backend/test-server/.eslintrc.cjs deleted file mode 100644 index c261741a36..0000000000 --- a/packages/backend/test-server/.eslintrc.cjs +++ /dev/null @@ -1,32 +0,0 @@ -module.exports = { - parserOptions: { - tsconfigRootDir: __dirname, - project: ['./tsconfig.json'], - }, - extends: [ - '../../shared/.eslintrc.js', - ], - rules: { - 'import/order': ['warn', { - 'groups': ['builtin', 'external', 'internal', 'parent', 'sibling', 'index', 'object', 'type'], - 'pathGroups': [ - { - 'pattern': '@/**', - 'group': 'external', - 'position': 'after' - } - ], - }], - 'no-restricted-globals': [ - 'error', - { - 'name': '__dirname', - 'message': 'Not in ESModule. Use `import.meta.url` instead.' - }, - { - 'name': '__filename', - 'message': 'Not in ESModule. Use `import.meta.url` instead.' - } - ] - }, -}; diff --git a/packages/backend/test-server/eslint.config.js b/packages/backend/test-server/eslint.config.js new file mode 100644 index 0000000000..b9c16d469f --- /dev/null +++ b/packages/backend/test-server/eslint.config.js @@ -0,0 +1,43 @@ +import tsParser from '@typescript-eslint/parser'; +import sharedConfig from '../../shared/eslint.config.js'; + +export default [ + ...sharedConfig, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + parser: tsParser, + project: ['./tsconfig.json'], + sourceType: 'module', + tsconfigRootDir: import.meta.dirname, + }, + }, + rules: { + 'import/order': ['warn', { + groups: [ + 'builtin', + 'external', + 'internal', + 'parent', + 'sibling', + 'index', + 'object', + 'type', + ], + pathGroups: [{ + pattern: '@/**', + group: 'external', + position: 'after', + }], + }], + 'no-restricted-globals': ['error', { + name: '__dirname', + message: 'Not in ESModule. Use `import.meta.url` instead.', + }, { + name: '__filename', + message: 'Not in ESModule. Use `import.meta.url` instead.', + }], + }, + }, +]; diff --git a/packages/backend/test/.eslintrc.cjs b/packages/backend/test/.eslintrc.cjs deleted file mode 100644 index 41ecea0c3f..0000000000 --- a/packages/backend/test/.eslintrc.cjs +++ /dev/null @@ -1,11 +0,0 @@ -module.exports = { - parserOptions: { - tsconfigRootDir: __dirname, - project: ['./tsconfig.json'], - }, - extends: ['../.eslintrc.cjs'], - env: { - node: true, - jest: true, - }, -}; diff --git a/packages/backend/test/docker-compose.yml b/packages/backend/test/compose.yml similarity index 94% rename from packages/backend/test/docker-compose.yml rename to packages/backend/test/compose.yml index f2d8990758..6593fc33dd 100644 --- a/packages/backend/test/docker-compose.yml +++ b/packages/backend/test/compose.yml @@ -1,5 +1,3 @@ -version: "3" - services: redistest: image: redis:7 diff --git a/packages/backend/test/e2e/2fa.ts b/packages/backend/test/e2e/2fa.ts index 13c56b88a6..06548fa7da 100644 --- a/packages/backend/test/e2e/2fa.ts +++ b/packages/backend/test/e2e/2fa.ts @@ -206,7 +206,7 @@ describe('2要素認証', () => { username, }, alice); assert.strictEqual(usersShowResponse.status, 200); - assert.strictEqual(usersShowResponse.body.twoFactorEnabled, true); + assert.strictEqual((usersShowResponse.body as unknown as { twoFactorEnabled: boolean }).twoFactorEnabled, true); const signinResponse = await api('signin', { ...signinParam(), @@ -248,7 +248,7 @@ describe('2要素認証', () => { keyName, credentialId, creationOptions: registerKeyResponse.body, - }) as any, alice); + } as any) as any, alice); assert.strictEqual(keyDoneResponse.status, 200); assert.strictEqual(keyDoneResponse.body.id, credentialId.toString('base64url')); assert.strictEqual(keyDoneResponse.body.name, keyName); @@ -257,22 +257,22 @@ describe('2要素認証', () => { username, }); assert.strictEqual(usersShowResponse.status, 200); - assert.strictEqual(usersShowResponse.body.securityKeys, true); + assert.strictEqual((usersShowResponse.body as unknown as { securityKeys: boolean }).securityKeys, true); const signinResponse = await api('signin', { ...signinParam(), }); assert.strictEqual(signinResponse.status, 200); assert.strictEqual(signinResponse.body.i, undefined); - assert.notEqual(signinResponse.body.challenge, undefined); - assert.notEqual(signinResponse.body.allowCredentials, undefined); - assert.strictEqual(signinResponse.body.allowCredentials[0].id, credentialId.toString('base64url')); + assert.notEqual((signinResponse.body as unknown as { challenge: unknown | undefined }).challenge, undefined); + assert.notEqual((signinResponse.body as unknown as { allowCredentials: unknown | undefined }).allowCredentials, undefined); + assert.strictEqual((signinResponse.body as unknown as { allowCredentials: {id: string}[] }).allowCredentials[0].id, credentialId.toString('base64url')); const signinResponse2 = await api('signin', signinWithSecurityKeyParam({ keyName, credentialId, requestOptions: signinResponse.body, - })); + } as any)); assert.strictEqual(signinResponse2.status, 200); assert.notEqual(signinResponse2.body.i, undefined); @@ -307,7 +307,7 @@ describe('2要素認証', () => { keyName, credentialId, creationOptions: registerKeyResponse.body, - }) as any, alice); + } as any) as any, alice); assert.strictEqual(keyDoneResponse.status, 200); const passwordLessResponse = await api('i/2fa/password-less', { @@ -319,7 +319,7 @@ describe('2要素認証', () => { username, }); assert.strictEqual(usersShowResponse.status, 200); - assert.strictEqual(usersShowResponse.body.usePasswordLessLogin, true); + assert.strictEqual((usersShowResponse.body as unknown as { usePasswordLessLogin: boolean }).usePasswordLessLogin, true); const signinResponse = await api('signin', { ...signinParam(), @@ -333,7 +333,7 @@ describe('2要素認証', () => { keyName, credentialId, requestOptions: signinResponse.body, - }), + } as any), password: '', }); assert.strictEqual(signinResponse2.status, 200); @@ -370,7 +370,7 @@ describe('2要素認証', () => { keyName, credentialId, creationOptions: registerKeyResponse.body, - }) as any, alice); + } as any) as any, alice); assert.strictEqual(keyDoneResponse.status, 200); const renamedKey = 'other-key'; @@ -383,6 +383,7 @@ describe('2要素認証', () => { const iResponse = await api('i', { }, alice); assert.strictEqual(iResponse.status, 200); + assert.ok(iResponse.body.securityKeysList); const securityKeys = iResponse.body.securityKeysList.filter((s: { id: string; }) => s.id === credentialId.toString('base64url')); assert.strictEqual(securityKeys.length, 1); assert.strictEqual(securityKeys[0].name, renamedKey); @@ -419,13 +420,14 @@ describe('2要素認証', () => { keyName, credentialId, creationOptions: registerKeyResponse.body, - }) as any, alice); + } as any) as any, alice); assert.strictEqual(keyDoneResponse.status, 200); // テストの実行順によっては複数残ってるので全部消す const iResponse = await api('i', { }, alice); assert.strictEqual(iResponse.status, 200); + assert.ok(iResponse.body.securityKeysList); for (const key of iResponse.body.securityKeysList) { const removeKeyResponse = await api('i/2fa/remove-key', { token: otpToken(registerResponse.body.secret), @@ -439,7 +441,7 @@ describe('2要素認証', () => { username, }); assert.strictEqual(usersShowResponse.status, 200); - assert.strictEqual(usersShowResponse.body.securityKeys, false); + assert.strictEqual((usersShowResponse.body as unknown as { securityKeys: boolean }).securityKeys, false); const signinResponse = await api('signin', { ...signinParam(), @@ -470,7 +472,7 @@ describe('2要素認証', () => { username, }); assert.strictEqual(usersShowResponse.status, 200); - assert.strictEqual(usersShowResponse.body.twoFactorEnabled, true); + assert.strictEqual((usersShowResponse.body as unknown as { twoFactorEnabled: boolean }).twoFactorEnabled, true); const unregisterResponse = await api('i/2fa/unregister', { token: otpToken(registerResponse.body.secret), diff --git a/packages/backend/test/e2e/antennas.ts b/packages/backend/test/e2e/antennas.ts index 101238b601..6ac14cd8dc 100644 --- a/packages/backend/test/e2e/antennas.ts +++ b/packages/backend/test/e2e/antennas.ts @@ -163,8 +163,7 @@ describe('アンテナ', () => { }); test('が上限いっぱいまで作成できること', async () => { - // antennaLimit + 1まで作れるのがキモ - const response = await Promise.all([...Array(DEFAULT_POLICIES.antennaLimit + 1)].map(() => successfulApiCall({ + const response = await Promise.all([...Array(DEFAULT_POLICIES.antennaLimit)].map(() => successfulApiCall({ endpoint: 'antennas/create', parameters: { ...defaultParam }, user: alice, diff --git a/packages/backend/test/e2e/api-visibility.ts b/packages/backend/test/e2e/api-visibility.ts index c61b0c2a86..2dd645d97a 100644 --- a/packages/backend/test/e2e/api-visibility.ts +++ b/packages/backend/test/e2e/api-visibility.ts @@ -410,21 +410,21 @@ describe('API visibility', () => { test('[HTL] public-post が 自分が見れる', async () => { const res = await api('notes/timeline', { limit: 100 }, alice); assert.strictEqual(res.status, 200); - const notes = res.body.filter((n: any) => n.id === pub.id); + const notes = res.body.filter(n => n.id === pub.id); assert.strictEqual(notes[0].text, 'x'); }); test('[HTL] public-post が 非フォロワーから見れない', async () => { const res = await api('notes/timeline', { limit: 100 }, other); assert.strictEqual(res.status, 200); - const notes = res.body.filter((n: any) => n.id === pub.id); + const notes = res.body.filter(n => n.id === pub.id); assert.strictEqual(notes.length, 0); }); test('[HTL] followers-post が フォロワーから見れる', async () => { const res = await api('notes/timeline', { limit: 100 }, follower); assert.strictEqual(res.status, 200); - const notes = res.body.filter((n: any) => n.id === fol.id); + const notes = res.body.filter(n => n.id === fol.id); assert.strictEqual(notes[0].text, 'x'); }); //#endregion @@ -433,21 +433,21 @@ describe('API visibility', () => { test('[replies] followers-reply が フォロワーから見れる', async () => { const res = await api('notes/replies', { noteId: tgt.id, limit: 100 }, follower); assert.strictEqual(res.status, 200); - const notes = res.body.filter((n: any) => n.id === folR.id); + const notes = res.body.filter(n => n.id === folR.id); assert.strictEqual(notes[0].text, 'x'); }); test('[replies] followers-reply が 非フォロワー (リプライ先ではない) から見れない', async () => { const res = await api('notes/replies', { noteId: tgt.id, limit: 100 }, other); assert.strictEqual(res.status, 200); - const notes = res.body.filter((n: any) => n.id === folR.id); + const notes = res.body.filter(n => n.id === folR.id); assert.strictEqual(notes.length, 0); }); test('[replies] followers-reply が 非フォロワー (リプライ先である) から見れる', async () => { const res = await api('notes/replies', { noteId: tgt.id, limit: 100 }, target); assert.strictEqual(res.status, 200); - const notes = res.body.filter((n: any) => n.id === folR.id); + const notes = res.body.filter(n => n.id === folR.id); assert.strictEqual(notes[0].text, 'x'); }); //#endregion @@ -456,14 +456,14 @@ describe('API visibility', () => { test('[mentions] followers-reply が 非フォロワー (リプライ先である) から見れる', async () => { const res = await api('notes/mentions', { limit: 100 }, target); assert.strictEqual(res.status, 200); - const notes = res.body.filter((n: any) => n.id === folR.id); + const notes = res.body.filter(n => n.id === folR.id); assert.strictEqual(notes[0].text, 'x'); }); test('[mentions] followers-mention が 非フォロワー (メンション先である) から見れる', async () => { const res = await api('notes/mentions', { limit: 100 }, target); assert.strictEqual(res.status, 200); - const notes = res.body.filter((n: any) => n.id === folM.id); + const notes = res.body.filter(n => n.id === folM.id); assert.strictEqual(notes[0].text, '@target x'); }); //#endregion diff --git a/packages/backend/test/e2e/block.ts b/packages/backend/test/e2e/block.ts index e4f798498f..35b0e59383 100644 --- a/packages/backend/test/e2e/block.ts +++ b/packages/backend/test/e2e/block.ts @@ -6,7 +6,7 @@ process.env.NODE_ENV = 'test'; import * as assert from 'assert'; -import { api, post, signup } from '../utils.js'; +import { api, castAsError, post, signup } from '../utils.js'; import type * as misskey from 'misskey-js'; describe('Block', () => { @@ -33,7 +33,7 @@ describe('Block', () => { const res = await api('following/create', { userId: alice.id }, bob); assert.strictEqual(res.status, 400); - assert.strictEqual(res.body.error.id, 'c4ab57cc-4e41-45e9-bfd9-584f61e35ce0'); + assert.strictEqual(castAsError(res.body).error.id, 'c4ab57cc-4e41-45e9-bfd9-584f61e35ce0'); }); test('ブロックされているユーザーにリアクションできない', async () => { @@ -42,7 +42,8 @@ describe('Block', () => { const res = await api('notes/reactions/create', { noteId: note.id, reaction: '👍' }, bob); assert.strictEqual(res.status, 400); - assert.strictEqual(res.body.error.id, '20ef5475-9f38-4e4c-bd33-de6d979498ec'); + assert.ok(res.body); + assert.strictEqual(castAsError(res.body).error.id, '20ef5475-9f38-4e4c-bd33-de6d979498ec'); }); test('ブロックされているユーザーに返信できない', async () => { @@ -51,7 +52,8 @@ describe('Block', () => { const res = await api('notes/create', { replyId: note.id, text: 'yo' }, bob); assert.strictEqual(res.status, 400); - assert.strictEqual(res.body.error.id, 'b390d7e1-8a5e-46ed-b625-06271cafd3d3'); + assert.ok(res.body); + assert.strictEqual(castAsError(res.body).error.id, 'b390d7e1-8a5e-46ed-b625-06271cafd3d3'); }); test('ブロックされているユーザーのノートをRenoteできない', async () => { @@ -60,7 +62,7 @@ describe('Block', () => { const res = await api('notes/create', { renoteId: note.id, text: 'yo' }, bob); assert.strictEqual(res.status, 400); - assert.strictEqual(res.body.error.id, 'b390d7e1-8a5e-46ed-b625-06271cafd3d3'); + assert.strictEqual(castAsError(res.body).error.id, 'b390d7e1-8a5e-46ed-b625-06271cafd3d3'); }); // TODO: ユーザーリストに入れられないテスト diff --git a/packages/backend/test/e2e/clips.ts b/packages/backend/test/e2e/clips.ts index ba6f9d6a65..a130c3698d 100644 --- a/packages/backend/test/e2e/clips.ts +++ b/packages/backend/test/e2e/clips.ts @@ -79,14 +79,14 @@ describe('クリップ', () => { }; const deleteClip = async (parameters: Misskey.entities.ClipsDeleteRequest, request: Partial> = {}): Promise => { - return await successfulApiCall({ + await successfulApiCall({ endpoint: 'clips/delete', parameters, user: alice, ...request, }, { status: 204, - }) as any as void; + }); }; const show = async (parameters: Misskey.entities.ClipsShowRequest, request: Partial> = {}): Promise => { @@ -153,8 +153,7 @@ describe('クリップ', () => { }); test('の作成はポリシーで定められた数以上はできない。', async () => { - // ポリシー + 1まで作れるという所がミソ - const clipLimit = DEFAULT_POLICIES.clipLimit + 1; + const clipLimit = DEFAULT_POLICIES.clipLimit; for (let i = 0; i < clipLimit; i++) { await create(); } @@ -327,7 +326,7 @@ describe('クリップ', () => { }); test('の一覧(clips/list)が取得できる(上限いっぱい)', async () => { - const clipLimit = DEFAULT_POLICIES.clipLimit + 1; + const clipLimit = DEFAULT_POLICIES.clipLimit; const clips = await createMany({}, clipLimit); const res = await list({ parameters: { limit: 1 }, // FIXME: 無視されて11全部返ってくる @@ -455,25 +454,25 @@ describe('クリップ', () => { let aliceClip: Misskey.entities.Clip; const favorite = async (parameters: Misskey.entities.ClipsFavoriteRequest, request: Partial> = {}): Promise => { - return successfulApiCall({ + await successfulApiCall({ endpoint: 'clips/favorite', parameters, user: alice, ...request, }, { status: 204, - }) as any as void; + }); }; const unfavorite = async (parameters: Misskey.entities.ClipsUnfavoriteRequest, request: Partial> = {}): Promise => { - return successfulApiCall({ + await successfulApiCall({ endpoint: 'clips/unfavorite', parameters, user: alice, ...request, }, { status: 204, - }) as any as void; + }); }; const myFavorites = async (request: Partial> = {}): Promise => { @@ -705,7 +704,7 @@ describe('クリップ', () => { // TODO: 17000msくらいかかる... test('をポリシーで定められた上限いっぱい(200)を超えて追加はできない。', async () => { - const noteLimit = DEFAULT_POLICIES.noteEachClipsLimit + 1; + const noteLimit = DEFAULT_POLICIES.noteEachClipsLimit; const noteList = await Promise.all([...Array(noteLimit)].map((_, i) => post(alice, { text: `test ${i}`, }) as unknown)) as Misskey.entities.Note[]; diff --git a/packages/backend/test/e2e/drive.ts b/packages/backend/test/e2e/drive.ts index 828c5200ef..43a73163eb 100644 --- a/packages/backend/test/e2e/drive.ts +++ b/packages/backend/test/e2e/drive.ts @@ -23,7 +23,7 @@ describe('Drive', () => { const marker = Math.random().toString(); - const url = 'https://raw.githubusercontent.com/misskey-dev/misskey/develop/packages/backend/test/resources/Lenna.jpg'; + const url = 'https://raw.githubusercontent.com/misskey-dev/misskey/develop/packages/backend/test/resources/192.jpg'; const catcher = makeStreamCatcher( alice, @@ -41,14 +41,14 @@ describe('Drive', () => { const file = await catcher; assert.strictEqual(res.status, 204); - assert.strictEqual(file.name, 'Lenna.jpg'); + assert.strictEqual(file.name, '192.jpg'); assert.strictEqual(file.type, 'image/jpeg'); }); test('ローカルからアップロードできる', async () => { // APIレスポンスを直接使用するので utils.js uploadFile が通過することで成功とする - const res = await uploadFile(alice, { path: 'Lenna.jpg', name: 'テスト画像' }); + const res = await uploadFile(alice, { path: '192.jpg', name: 'テスト画像' }); assert.strictEqual(res.body?.name, 'テスト画像.jpg'); assert.strictEqual(res.body.type, 'image/jpeg'); diff --git a/packages/backend/test/e2e/endpoints.ts b/packages/backend/test/e2e/endpoints.ts index bc89dc37f4..5aaec7f6f9 100644 --- a/packages/backend/test/e2e/endpoints.ts +++ b/packages/backend/test/e2e/endpoints.ts @@ -10,7 +10,7 @@ import * as assert from 'assert'; // https://github.com/node-fetch/node-fetch/pull/1664 import { Blob } from 'node-fetch'; import { MiUser } from '@/models/_.js'; -import { api, initTestDb, post, signup, simpleGet, uploadFile } from '../utils.js'; +import { api, castAsError, initTestDb, post, signup, simpleGet, uploadFile } from '../utils.js'; import type * as misskey from 'misskey-js'; describe('Endpoints', () => { @@ -117,12 +117,21 @@ describe('Endpoints', () => { assert.strictEqual(res.body.birthday, myBirthday); }); - test('名前を空白にできる', async () => { + test('名前を空白のみにした場合nullになる', async () => { const res = await api('i/update', { name: ' ', }, alice); assert.strictEqual(res.status, 200); - assert.strictEqual(res.body.name, ' '); + assert.strictEqual(res.body.name, null); + }); + + test('名前の前後に空白(ホワイトスペース)を入れてもトリムされる', async () => { + const res = await api('i/update', { + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#white_space + name: ' あ い う \u0009\u000b\u000c\u0020\u00a0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\ufeff', + }, alice); + assert.strictEqual(res.status, 200); + assert.strictEqual(res.body.name, 'あ い う'); }); test('誕生日の設定を削除できる', async () => { @@ -155,7 +164,7 @@ describe('Endpoints', () => { assert.strictEqual(res.status, 200); assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true); - assert.strictEqual(res.body.id, alice.id); + assert.strictEqual((res.body as unknown as { id: string }).id, alice.id); }); test('ユーザーが存在しなかったら怒る', async () => { @@ -266,6 +275,68 @@ describe('Endpoints', () => { assert.strictEqual(res.status, 400); }); + test('リノートにリアクションできない', async () => { + const bobNote = await post(bob, { text: 'hi' }); + const bobRenote = await post(bob, { renoteId: bobNote.id }); + + const res = await api('notes/reactions/create', { + noteId: bobRenote.id, + reaction: '🚀', + }, alice); + + assert.strictEqual(res.status, 400); + assert.ok(res.body); + assert.strictEqual(castAsError(res.body).error.code, 'CANNOT_REACT_TO_RENOTE'); + }); + + test('引用にリアクションできる', async () => { + const bobNote = await post(bob, { text: 'hi' }); + const bobRenote = await post(bob, { text: 'hi again', renoteId: bobNote.id }); + + const res = await api('notes/reactions/create', { + noteId: bobRenote.id, + reaction: '🚀', + }, alice); + + assert.strictEqual(res.status, 204); + }); + + test('空文字列のリアクションは\u2764にフォールバックされる', async () => { + const bobNote = await post(bob, { text: 'hi' }); + + const res = await api('notes/reactions/create', { + noteId: bobNote.id, + reaction: '', + }, alice); + + assert.strictEqual(res.status, 204); + + const reaction = await api('notes/reactions', { + noteId: bobNote.id, + }); + + assert.strictEqual(reaction.body.length, 1); + assert.strictEqual(reaction.body[0].type, '\u2764'); + }); + + test('絵文字ではない文字列のリアクションは\u2764にフォールバックされる', async () => { + const bobNote = await post(bob, { text: 'hi' }); + + const res = await api('notes/reactions/create', { + noteId: bobNote.id, + reaction: 'Hello!', + }, alice); + + assert.strictEqual(res.status, 204); + + const reaction = await api('notes/reactions', { + noteId: bobNote.id, + }); + + assert.strictEqual(reaction.body.length, 1); + assert.strictEqual(reaction.body[0].type, '\u2764'); + }); + test('空のパラメータで怒られる', async () => { // @ts-expect-error param must not be empty const res = await api('notes/reactions/create', {}, alice); @@ -523,7 +594,7 @@ describe('Endpoints', () => { assert.strictEqual(res.status, 200); assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true); - assert.strictEqual(res.body!.name, 'Lenna.jpg'); + assert.strictEqual(res.body!.name, '192.jpg'); }); test('ファイルに名前を付けられる', async () => { @@ -993,7 +1064,7 @@ describe('Endpoints', () => { userId: bob.id, }, alice); assert.strictEqual(res1.status, 204); - assert.strictEqual(res2.body?.memo, memo); + assert.strictEqual((res2.body as unknown as { memo: string })?.memo, memo); }); test('自分に関するメモを更新できる', async () => { @@ -1008,7 +1079,7 @@ describe('Endpoints', () => { userId: alice.id, }, alice); assert.strictEqual(res1.status, 204); - assert.strictEqual(res2.body?.memo, memo); + assert.strictEqual((res2.body as unknown as { memo: string })?.memo, memo); }); test('メモを削除できる', async () => { @@ -1029,7 +1100,7 @@ describe('Endpoints', () => { }, alice); // memoには常に文字列かnullが入っている(5cac151) - assert.strictEqual(res.body.memo, null); + assert.strictEqual((res.body as unknown as { memo: string | null }).memo, null); }); test('メモは個人ごとに独立して保存される', async () => { @@ -1056,8 +1127,8 @@ describe('Endpoints', () => { }, carol), ]); - assert.strictEqual(resAlice.body.memo, memoAliceToBob); - assert.strictEqual(resCarol.body.memo, memoCarolToBob); + assert.strictEqual((resAlice.body as unknown as { memo: string }).memo, memoAliceToBob); + assert.strictEqual((resCarol.body as unknown as { memo: string }).memo, memoCarolToBob); }); }); }); diff --git a/packages/backend/test/e2e/exports.ts b/packages/backend/test/e2e/exports.ts index 80a5331a6d..4bcecc9716 100644 --- a/packages/backend/test/e2e/exports.ts +++ b/packages/backend/test/e2e/exports.ts @@ -61,14 +61,14 @@ describe('export-clips', () => { }); test('basic export', async () => { - let res = await api('clips/create', { + const res1 = await api('clips/create', { name: 'foo', description: 'bar', }, alice); - assert.strictEqual(res.status, 200); + assert.strictEqual(res1.status, 200); - res = await api('i/export-clips', {}, alice); - assert.strictEqual(res.status, 204); + const res2 = await api('i/export-clips', {}, alice); + assert.strictEqual(res2.status, 204); const exported = await pollFirstDriveFile(); assert.strictEqual(exported[0].name, 'foo'); @@ -77,7 +77,7 @@ describe('export-clips', () => { }); test('export with notes', async () => { - let res = await api('clips/create', { + const res = await api('clips/create', { name: 'foo', description: 'bar', }, alice); @@ -96,15 +96,15 @@ describe('export-clips', () => { }); for (const note of [note1, note2]) { - res = await api('clips/add-note', { + const res2 = await api('clips/add-note', { clipId: clip.id, noteId: note.id, }, alice); - assert.strictEqual(res.status, 204); + assert.strictEqual(res2.status, 204); } - res = await api('i/export-clips', {}, alice); - assert.strictEqual(res.status, 204); + const res3 = await api('i/export-clips', {}, alice); + assert.strictEqual(res3.status, 204); const exported = await pollFirstDriveFile(); assert.strictEqual(exported[0].name, 'foo'); @@ -116,19 +116,19 @@ describe('export-clips', () => { }); test('multiple clips', async () => { - let res = await api('clips/create', { + const res1 = await api('clips/create', { name: 'kawaii', description: 'kawaii', }, alice); - assert.strictEqual(res.status, 200); - const clip1 = res.body; + assert.strictEqual(res1.status, 200); + const clip1 = res1.body; - res = await api('clips/create', { + const res2 = await api('clips/create', { name: 'yuri', description: 'yuri', }, alice); - assert.strictEqual(res.status, 200); - const clip2 = res.body; + assert.strictEqual(res2.status, 200); + const clip2 = res2.body; const note1 = await post(alice, { text: 'baz1', @@ -138,20 +138,26 @@ describe('export-clips', () => { text: 'baz2', }); - res = await api('clips/add-note', { - clipId: clip1.id, - noteId: note1.id, - }, alice); - assert.strictEqual(res.status, 204); + { + const res = await api('clips/add-note', { + clipId: clip1.id, + noteId: note1.id, + }, alice); + assert.strictEqual(res.status, 204); + } - res = await api('clips/add-note', { - clipId: clip2.id, - noteId: note2.id, - }, alice); - assert.strictEqual(res.status, 204); + { + const res = await api('clips/add-note', { + clipId: clip2.id, + noteId: note2.id, + }, alice); + assert.strictEqual(res.status, 204); + } - res = await api('i/export-clips', {}, alice); - assert.strictEqual(res.status, 204); + { + const res = await api('i/export-clips', {}, alice); + assert.strictEqual(res.status, 204); + } const exported = await pollFirstDriveFile(); assert.strictEqual(exported[0].name, 'kawaii'); @@ -163,7 +169,7 @@ describe('export-clips', () => { }); test('Clipping other user\'s note', async () => { - let res = await api('clips/create', { + const res = await api('clips/create', { name: 'kawaii', description: 'kawaii', }, alice); @@ -175,14 +181,14 @@ describe('export-clips', () => { visibility: 'followers', }); - res = await api('clips/add-note', { + const res2 = await api('clips/add-note', { clipId: clip.id, noteId: note.id, }, alice); - assert.strictEqual(res.status, 204); + assert.strictEqual(res2.status, 204); - res = await api('i/export-clips', {}, alice); - assert.strictEqual(res.status, 204); + const res3 = await api('i/export-clips', {}, alice); + assert.strictEqual(res3.status, 204); const exported = await pollFirstDriveFile(); assert.strictEqual(exported[0].name, 'kawaii'); diff --git a/packages/backend/test/e2e/fetch-resource.ts b/packages/backend/test/e2e/fetch-resource.ts index 4851ed14be..7efd688ec2 100644 --- a/packages/backend/test/e2e/fetch-resource.ts +++ b/packages/backend/test/e2e/fetch-resource.ts @@ -153,6 +153,23 @@ describe('Webリソース', () => { path: path('nonexisting'), status: 404, })); + + describe(' has entry such ', () => { + beforeEach(() => { + post(alice, { text: "**a**" }) + }); + + test('MFMを含まない。', async () => { + const content = await simpleGet(path(alice.username), "*/*", undefined, res => res.text()); + const _body: unknown = content.body; + // JSONフィードのときは改めて文字列化する + const body: string = typeof (_body) === "object" ? JSON.stringify(_body) : _body as string; + + if (body.includes("**a**")) { + throw new Error("MFM shouldn't be included"); + } + }); + }) }); describe.each([{ path: '/api/foo' }])('$path', ({ path }) => { diff --git a/packages/backend/test/e2e/move.ts b/packages/backend/test/e2e/move.ts index 74cf61a785..fd798bdb25 100644 --- a/packages/backend/test/e2e/move.ts +++ b/packages/backend/test/e2e/move.ts @@ -7,19 +7,20 @@ import { INestApplicationContext } from '@nestjs/common'; process.env.NODE_ENV = 'test'; +import { setTimeout } from 'node:timers/promises'; import * as assert from 'assert'; import { loadConfig } from '@/config.js'; import { MiRepository, MiUser, UsersRepository, miRepository } from '@/models/_.js'; import { secureRndstr } from '@/misc/secure-rndstr.js'; import { jobQueue } from '@/boot/common.js'; -import { api, initTestDb, signup, sleep, successfulApiCall, uploadFile } from '../utils.js'; +import { api, castAsError, initTestDb, signup, successfulApiCall, uploadFile } from '../utils.js'; import type * as misskey from 'misskey-js'; describe('Account Move', () => { let jq: INestApplicationContext; let url: URL; - let root: any; + let root: misskey.entities.SignupResponse; let alice: misskey.entities.SignupResponse; let bob: misskey.entities.SignupResponse; let carol: misskey.entities.SignupResponse; @@ -92,8 +93,8 @@ describe('Account Move', () => { }, bob); assert.strictEqual(res.status, 400); - assert.strictEqual(res.body.error.code, 'NO_SUCH_USER'); - assert.strictEqual(res.body.error.id, 'fcd2eef9-a9b2-4c4f-8624-038099e90aa5'); + assert.strictEqual(castAsError(res.body).error.code, 'NO_SUCH_USER'); + assert.strictEqual(castAsError(res.body).error.id, 'fcd2eef9-a9b2-4c4f-8624-038099e90aa5'); }); test('Unable to add duplicated aliases to alsoKnownAs', async () => { @@ -102,8 +103,8 @@ describe('Account Move', () => { }, bob); assert.strictEqual(res.status, 400); - assert.strictEqual(res.body.error.code, 'INVALID_PARAM'); - assert.strictEqual(res.body.error.id, '3d81ceae-475f-4600-b2a8-2bc116157532'); + assert.strictEqual(castAsError(res.body).error.code, 'INVALID_PARAM'); + assert.strictEqual(castAsError(res.body).error.id, '3d81ceae-475f-4600-b2a8-2bc116157532'); }); test('Unable to add itself', async () => { @@ -112,8 +113,8 @@ describe('Account Move', () => { }, bob); assert.strictEqual(res.status, 400); - assert.strictEqual(res.body.error.code, 'FORBIDDEN_TO_SET_YOURSELF'); - assert.strictEqual(res.body.error.id, '25c90186-4ab0-49c8-9bba-a1fa6c202ba4'); + assert.strictEqual(castAsError(res.body).error.code, 'FORBIDDEN_TO_SET_YOURSELF'); + assert.strictEqual(castAsError(res.body).error.id, '25c90186-4ab0-49c8-9bba-a1fa6c202ba4'); }); test('Unable to add a nonexisting local account to alsoKnownAs', async () => { @@ -122,16 +123,16 @@ describe('Account Move', () => { }, bob); assert.strictEqual(res1.status, 400); - assert.strictEqual(res1.body.error.code, 'NO_SUCH_USER'); - assert.strictEqual(res1.body.error.id, 'fcd2eef9-a9b2-4c4f-8624-038099e90aa5'); + assert.strictEqual(castAsError(res1.body).error.code, 'NO_SUCH_USER'); + assert.strictEqual(castAsError(res1.body).error.id, 'fcd2eef9-a9b2-4c4f-8624-038099e90aa5'); const res2 = await api('i/update', { alsoKnownAs: ['@alice', 'nonexist'], }, bob); assert.strictEqual(res2.status, 400); - assert.strictEqual(res2.body.error.code, 'NO_SUCH_USER'); - assert.strictEqual(res2.body.error.id, 'fcd2eef9-a9b2-4c4f-8624-038099e90aa5'); + assert.strictEqual(castAsError(res2.body).error.code, 'NO_SUCH_USER'); + assert.strictEqual(castAsError(res2.body).error.id, 'fcd2eef9-a9b2-4c4f-8624-038099e90aa5'); }); test('Able to add two existing local account to alsoKnownAs', async () => { @@ -240,8 +241,8 @@ describe('Account Move', () => { }, root); assert.strictEqual(res.status, 400); - assert.strictEqual(res.body.error.code, 'NOT_ROOT_FORBIDDEN'); - assert.strictEqual(res.body.error.id, '4362e8dc-731f-4ad8-a694-be2a88922a24'); + assert.strictEqual(castAsError(res.body).error.code, 'NOT_ROOT_FORBIDDEN'); + assert.strictEqual(castAsError(res.body).error.id, '4362e8dc-731f-4ad8-a694-be2a88922a24'); }); test('Unable to move to a nonexisting local account', async () => { @@ -250,8 +251,8 @@ describe('Account Move', () => { }, alice); assert.strictEqual(res.status, 400); - assert.strictEqual(res.body.error.code, 'NO_SUCH_USER'); - assert.strictEqual(res.body.error.id, 'fcd2eef9-a9b2-4c4f-8624-038099e90aa5'); + assert.strictEqual(castAsError(res.body).error.code, 'NO_SUCH_USER'); + assert.strictEqual(castAsError(res.body).error.id, 'fcd2eef9-a9b2-4c4f-8624-038099e90aa5'); }); test('Unable to move if alsoKnownAs is invalid', async () => { @@ -260,8 +261,8 @@ describe('Account Move', () => { }, alice); assert.strictEqual(res.status, 400); - assert.strictEqual(res.body.error.code, 'DESTINATION_ACCOUNT_FORBIDS'); - assert.strictEqual(res.body.error.id, 'b5c90186-4ab0-49c8-9bba-a1f766282ba4'); + assert.strictEqual(castAsError(res.body).error.code, 'DESTINATION_ACCOUNT_FORBIDS'); + assert.strictEqual(castAsError(res.body).error.id, 'b5c90186-4ab0-49c8-9bba-a1f766282ba4'); }); test('Relationships have been properly migrated', async () => { @@ -271,43 +272,51 @@ describe('Account Move', () => { assert.strictEqual(move.status, 200); - await sleep(1000 * 3); // wait for jobs to finish + await setTimeout(1000 * 3); // wait for jobs to finish // Unfollow delayed? const aliceFollowings = await api('users/following', { userId: alice.id, }, alice); assert.strictEqual(aliceFollowings.status, 200); + assert.ok(aliceFollowings); assert.strictEqual(aliceFollowings.body.length, 3); const carolFollowings = await api('users/following', { userId: carol.id, }, carol); assert.strictEqual(carolFollowings.status, 200); + assert.ok(carolFollowings); assert.strictEqual(carolFollowings.body.length, 2); assert.strictEqual(carolFollowings.body[0].followeeId, bob.id); assert.strictEqual(carolFollowings.body[1].followeeId, alice.id); const blockings = await api('blocking/list', {}, dave); assert.strictEqual(blockings.status, 200); + assert.ok(blockings); assert.strictEqual(blockings.body.length, 2); assert.strictEqual(blockings.body[0].blockeeId, bob.id); assert.strictEqual(blockings.body[1].blockeeId, alice.id); const mutings = await api('mute/list', {}, dave); assert.strictEqual(mutings.status, 200); + assert.ok(mutings); assert.strictEqual(mutings.body.length, 2); assert.strictEqual(mutings.body[0].muteeId, bob.id); assert.strictEqual(mutings.body[1].muteeId, alice.id); const rootLists = await api('users/lists/list', {}, root); assert.strictEqual(rootLists.status, 200); + assert.ok(rootLists); + assert.ok(rootLists.body[0].userIds); assert.strictEqual(rootLists.body[0].userIds.length, 2); assert.ok(rootLists.body[0].userIds.find((id: string) => id === bob.id)); assert.ok(rootLists.body[0].userIds.find((id: string) => id === alice.id)); const eveLists = await api('users/lists/list', {}, eve); assert.strictEqual(eveLists.status, 200); + assert.ok(eveLists); + assert.ok(eveLists.body[0].userIds); assert.strictEqual(eveLists.body[0].userIds.length, 1); assert.ok(eveLists.body[0].userIds.find((id: string) => id === bob.id)); }); @@ -330,7 +339,7 @@ describe('Account Move', () => { }); test('Unfollowed after 10 sec (24 hours in production).', async () => { - await sleep(1000 * 8); + await setTimeout(1000 * 8); const following = await api('users/following', { userId: alice.id, @@ -346,8 +355,8 @@ describe('Account Move', () => { }, bob); assert.strictEqual(res.status, 400); - assert.strictEqual(res.body.error.code, 'DESTINATION_ACCOUNT_FORBIDS'); - assert.strictEqual(res.body.error.id, 'b5c90186-4ab0-49c8-9bba-a1f766282ba4'); + assert.strictEqual(castAsError(res.body).error.code, 'DESTINATION_ACCOUNT_FORBIDS'); + assert.strictEqual(castAsError(res.body).error.id, 'b5c90186-4ab0-49c8-9bba-a1f766282ba4'); }); test('Follow and follower counts are properly adjusted', async () => { @@ -418,8 +427,9 @@ describe('Account Move', () => { ] as const)('Prohibit access after moving: %s', async (endpoint) => { const res = await api(endpoint, {}, alice); assert.strictEqual(res.status, 403); - assert.strictEqual(res.body.error.code, 'YOUR_ACCOUNT_MOVED'); - assert.strictEqual(res.body.error.id, '56f20ec9-fd06-4fa5-841b-edd6d7d4fa31'); + assert.ok(res.body); + assert.strictEqual(castAsError(res.body).error.code, 'YOUR_ACCOUNT_MOVED'); + assert.strictEqual(castAsError(res.body).error.id, '56f20ec9-fd06-4fa5-841b-edd6d7d4fa31'); }); test('Prohibit access after moving: /antennas/update', async () => { @@ -437,16 +447,19 @@ describe('Account Move', () => { }, alice); assert.strictEqual(res.status, 403); - assert.strictEqual(res.body.error.code, 'YOUR_ACCOUNT_MOVED'); - assert.strictEqual(res.body.error.id, '56f20ec9-fd06-4fa5-841b-edd6d7d4fa31'); + assert.ok(res.body); + assert.strictEqual(castAsError(res.body).error.code, 'YOUR_ACCOUNT_MOVED'); + assert.strictEqual(castAsError(res.body).error.id, '56f20ec9-fd06-4fa5-841b-edd6d7d4fa31'); }); test('Prohibit access after moving: /drive/files/create', async () => { + // FIXME: 一旦逃げておく const res = await uploadFile(alice); assert.strictEqual(res.status, 403); - assert.strictEqual((res.body! as any as { error: misskey.api.APIError }).error.code, 'YOUR_ACCOUNT_MOVED'); - assert.strictEqual((res.body! as any as { error: misskey.api.APIError }).error.id, '56f20ec9-fd06-4fa5-841b-edd6d7d4fa31'); + assert.ok(res.body); + assert.strictEqual(castAsError(res.body).error.code, 'YOUR_ACCOUNT_MOVED'); + assert.strictEqual(castAsError(res.body).error.id, '56f20ec9-fd06-4fa5-841b-edd6d7d4fa31'); }); test('Prohibit updating alsoKnownAs after moving', async () => { @@ -455,8 +468,8 @@ describe('Account Move', () => { }, alice); assert.strictEqual(res.status, 403); - assert.strictEqual(res.body.error.code, 'YOUR_ACCOUNT_MOVED'); - assert.strictEqual(res.body.error.id, '56f20ec9-fd06-4fa5-841b-edd6d7d4fa31'); + assert.strictEqual(castAsError(res.body).error.code, 'YOUR_ACCOUNT_MOVED'); + assert.strictEqual(castAsError(res.body).error.id, '56f20ec9-fd06-4fa5-841b-edd6d7d4fa31'); }); }); }); diff --git a/packages/backend/test/e2e/mute.ts b/packages/backend/test/e2e/mute.ts index 0e52c5decc..f37da288b7 100644 --- a/packages/backend/test/e2e/mute.ts +++ b/packages/backend/test/e2e/mute.ts @@ -47,8 +47,8 @@ describe('Mute', () => { assert.strictEqual(res.status, 200); assert.strictEqual(Array.isArray(res.body), true); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true); - assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false); + assert.strictEqual(res.body.some(note => note.id === bobNote.id), true); + assert.strictEqual(res.body.some(note => note.id === carolNote.id), false); }); test('ミュートしているユーザーからメンションされても、hasUnreadMentions が true にならない', async () => { @@ -92,9 +92,9 @@ describe('Mute', () => { assert.strictEqual(res.status, 200); assert.strictEqual(Array.isArray(res.body), true); - assert.strictEqual(res.body.some((note: any) => note.id === aliceNote.id), true); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true); - assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false); + assert.strictEqual(res.body.some(note => note.id === aliceNote.id), true); + assert.strictEqual(res.body.some(note => note.id === bobNote.id), true); + assert.strictEqual(res.body.some(note => note.id === carolNote.id), false); }); test('タイムラインにミュートしているユーザーの投稿のRenoteが含まれない', async () => { @@ -108,9 +108,9 @@ describe('Mute', () => { assert.strictEqual(res.status, 200); assert.strictEqual(Array.isArray(res.body), true); - assert.strictEqual(res.body.some((note: any) => note.id === aliceNote.id), true); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false); - assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false); + assert.strictEqual(res.body.some(note => note.id === aliceNote.id), true); + assert.strictEqual(res.body.some(note => note.id === bobNote.id), false); + assert.strictEqual(res.body.some(note => note.id === carolNote.id), false); }); }); @@ -124,8 +124,8 @@ describe('Mute', () => { assert.strictEqual(res.status, 200); assert.strictEqual(Array.isArray(res.body), true); - assert.strictEqual(res.body.some((notification: any) => notification.userId === bob.id), true); - assert.strictEqual(res.body.some((notification: any) => notification.userId === carol.id), false); + assert.strictEqual(res.body.some(notification => 'userId' in notification && notification.userId === bob.id), true); + assert.strictEqual(res.body.some(notification => 'userId' in notification && notification.userId === carol.id), false); }); test('通知にミュートしているユーザーからのリプライが含まれない', async () => { @@ -138,8 +138,8 @@ describe('Mute', () => { assert.strictEqual(res.status, 200); assert.strictEqual(Array.isArray(res.body), true); - assert.strictEqual(res.body.some((notification: any) => notification.userId === bob.id), true); - assert.strictEqual(res.body.some((notification: any) => notification.userId === carol.id), false); + assert.strictEqual(res.body.some(notification => 'userId' in notification && notification.userId === bob.id), true); + assert.strictEqual(res.body.some(notification => 'userId' in notification && notification.userId === carol.id), false); }); test('通知にミュートしているユーザーからのリプライが含まれない', async () => { @@ -152,8 +152,8 @@ describe('Mute', () => { assert.strictEqual(res.status, 200); assert.strictEqual(Array.isArray(res.body), true); - assert.strictEqual(res.body.some((notification: any) => notification.userId === bob.id), true); - assert.strictEqual(res.body.some((notification: any) => notification.userId === carol.id), false); + assert.strictEqual(res.body.some(notification => 'userId' in notification && notification.userId === bob.id), true); + assert.strictEqual(res.body.some(notification => 'userId' in notification && notification.userId === carol.id), false); }); test('通知にミュートしているユーザーからの引用リノートが含まれない', async () => { @@ -166,8 +166,8 @@ describe('Mute', () => { assert.strictEqual(res.status, 200); assert.strictEqual(Array.isArray(res.body), true); - assert.strictEqual(res.body.some((notification: any) => notification.userId === bob.id), true); - assert.strictEqual(res.body.some((notification: any) => notification.userId === carol.id), false); + assert.strictEqual(res.body.some(notification => 'userId' in notification && notification.userId === bob.id), true); + assert.strictEqual(res.body.some(notification => 'userId' in notification && notification.userId === carol.id), false); }); test('通知にミュートしているユーザーからのリノートが含まれない', async () => { @@ -180,8 +180,8 @@ describe('Mute', () => { assert.strictEqual(res.status, 200); assert.strictEqual(Array.isArray(res.body), true); - assert.strictEqual(res.body.some((notification: any) => notification.userId === bob.id), true); - assert.strictEqual(res.body.some((notification: any) => notification.userId === carol.id), false); + assert.strictEqual(res.body.some(notification => 'userId' in notification && notification.userId === bob.id), true); + assert.strictEqual(res.body.some(notification => 'userId' in notification && notification.userId === carol.id), false); }); test('通知にミュートしているユーザーからのフォロー通知が含まれない', async () => { @@ -193,8 +193,8 @@ describe('Mute', () => { assert.strictEqual(res.status, 200); assert.strictEqual(Array.isArray(res.body), true); - assert.strictEqual(res.body.some((notification: any) => notification.userId === bob.id), true); - assert.strictEqual(res.body.some((notification: any) => notification.userId === carol.id), false); + assert.strictEqual(res.body.some(notification => 'userId' in notification && notification.userId === bob.id), true); + assert.strictEqual(res.body.some(notification => 'userId' in notification && notification.userId === carol.id), false); await api('following/delete', { userId: alice.id }, bob); await api('following/delete', { userId: alice.id }, carol); @@ -210,8 +210,8 @@ describe('Mute', () => { assert.strictEqual(res.status, 200); assert.strictEqual(Array.isArray(res.body), true); - assert.strictEqual(res.body.some((notification: any) => notification.userId === bob.id), true); - assert.strictEqual(res.body.some((notification: any) => notification.userId === carol.id), false); + assert.strictEqual(res.body.some(notification => 'userId' in notification && notification.userId === bob.id), true); + assert.strictEqual(res.body.some(notification => 'userId' in notification && notification.userId === carol.id), false); await api('following/delete', { userId: alice.id }, bob); await api('following/delete', { userId: alice.id }, carol); @@ -228,8 +228,8 @@ describe('Mute', () => { assert.strictEqual(res.status, 200); assert.strictEqual(Array.isArray(res.body), true); - assert.strictEqual(res.body.some((notification: any) => notification.userId === bob.id), true); - assert.strictEqual(res.body.some((notification: any) => notification.userId === carol.id), false); + assert.strictEqual(res.body.some(notification => 'userId' in notification && notification.userId === bob.id), true); + assert.strictEqual(res.body.some(notification => 'userId' in notification && notification.userId === carol.id), false); }); test('通知にミュートしているユーザーからのリプライが含まれない', async () => { const aliceNote = await post(alice, { text: 'hi' }); @@ -241,8 +241,8 @@ describe('Mute', () => { assert.strictEqual(res.status, 200); assert.strictEqual(Array.isArray(res.body), true); - assert.strictEqual(res.body.some((notification: any) => notification.userId === bob.id), true); - assert.strictEqual(res.body.some((notification: any) => notification.userId === carol.id), false); + assert.strictEqual(res.body.some(notification => 'userId' in notification && notification.userId === bob.id), true); + assert.strictEqual(res.body.some(notification => 'userId' in notification && notification.userId === carol.id), false); }); test('通知にミュートしているユーザーからのリプライが含まれない', async () => { @@ -255,8 +255,8 @@ describe('Mute', () => { assert.strictEqual(res.status, 200); assert.strictEqual(Array.isArray(res.body), true); - assert.strictEqual(res.body.some((notification: any) => notification.userId === bob.id), true); - assert.strictEqual(res.body.some((notification: any) => notification.userId === carol.id), false); + assert.strictEqual(res.body.some(notification => 'userId' in notification && notification.userId === bob.id), true); + assert.strictEqual(res.body.some(notification => 'userId' in notification && notification.userId === carol.id), false); }); test('通知にミュートしているユーザーからの引用リノートが含まれない', async () => { @@ -269,8 +269,8 @@ describe('Mute', () => { assert.strictEqual(res.status, 200); assert.strictEqual(Array.isArray(res.body), true); - assert.strictEqual(res.body.some((notification: any) => notification.userId === bob.id), true); - assert.strictEqual(res.body.some((notification: any) => notification.userId === carol.id), false); + assert.strictEqual(res.body.some(notification => 'userId' in notification && notification.userId === bob.id), true); + assert.strictEqual(res.body.some(notification => 'userId' in notification && notification.userId === carol.id), false); }); test('通知にミュートしているユーザーからのリノートが含まれない', async () => { @@ -283,8 +283,8 @@ describe('Mute', () => { assert.strictEqual(res.status, 200); assert.strictEqual(Array.isArray(res.body), true); - assert.strictEqual(res.body.some((notification: any) => notification.userId === bob.id), true); - assert.strictEqual(res.body.some((notification: any) => notification.userId === carol.id), false); + assert.strictEqual(res.body.some(notification => 'userId' in notification && notification.userId === bob.id), true); + assert.strictEqual(res.body.some(notification => 'userId' in notification && notification.userId === carol.id), false); }); test('通知にミュートしているユーザーからのフォロー通知が含まれない', async () => { @@ -296,8 +296,8 @@ describe('Mute', () => { assert.strictEqual(res.status, 200); assert.strictEqual(Array.isArray(res.body), true); - assert.strictEqual(res.body.some((notification: any) => notification.userId === bob.id), true); - assert.strictEqual(res.body.some((notification: any) => notification.userId === carol.id), false); + assert.strictEqual(res.body.some(notification => 'userId' in notification && notification.userId === bob.id), true); + assert.strictEqual(res.body.some(notification => 'userId' in notification && notification.userId === carol.id), false); await api('following/delete', { userId: alice.id }, bob); await api('following/delete', { userId: alice.id }, carol); @@ -313,8 +313,8 @@ describe('Mute', () => { assert.strictEqual(res.status, 200); assert.strictEqual(Array.isArray(res.body), true); - assert.strictEqual(res.body.some((notification: any) => notification.userId === bob.id), true); - assert.strictEqual(res.body.some((notification: any) => notification.userId === carol.id), false); + assert.strictEqual(res.body.some(notification => 'userId' in notification && notification.userId === bob.id), true); + assert.strictEqual(res.body.some(notification => 'userId' in notification && notification.userId === carol.id), false); }); }); }); diff --git a/packages/backend/test/e2e/note.ts b/packages/backend/test/e2e/note.ts index bda31d9640..5937eb9b49 100644 --- a/packages/backend/test/e2e/note.ts +++ b/packages/backend/test/e2e/note.ts @@ -3,16 +3,18 @@ * SPDX-License-Identifier: AGPL-3.0-only */ +import type { Repository } from "typeorm"; + process.env.NODE_ENV = 'test'; import * as assert from 'assert'; import { MiNote } from '@/models/Note.js'; import { MAX_NOTE_TEXT_LENGTH } from '@/const.js'; -import { api, initTestDb, post, role, signup, uploadFile, uploadUrl } from '../utils.js'; +import { api, castAsError, initTestDb, post, role, signup, uploadFile, uploadUrl } from '../utils.js'; import type * as misskey from 'misskey-js'; describe('Note', () => { - let Notes: any; + let Notes: Repository; let root: misskey.entities.SignupResponse; let alice: misskey.entities.SignupResponse; @@ -41,7 +43,7 @@ describe('Note', () => { }); test('ファイルを添付できる', async () => { - const file = await uploadUrl(alice, 'https://raw.githubusercontent.com/misskey-dev/misskey/develop/packages/backend/test/resources/Lenna.jpg'); + const file = await uploadUrl(alice, 'https://raw.githubusercontent.com/misskey-dev/misskey/develop/packages/backend/test/resources/192.jpg'); const res = await api('notes/create', { fileIds: [file.id], @@ -53,7 +55,7 @@ describe('Note', () => { }, 1000 * 10); test('他人のファイルで怒られる', async () => { - const file = await uploadUrl(bob, 'https://raw.githubusercontent.com/misskey-dev/misskey/develop/packages/backend/test/resources/Lenna.jpg'); + const file = await uploadUrl(bob, 'https://raw.githubusercontent.com/misskey-dev/misskey/develop/packages/backend/test/resources/192.jpg'); const res = await api('notes/create', { text: 'test', @@ -61,8 +63,8 @@ describe('Note', () => { }, alice); assert.strictEqual(res.status, 400); - assert.strictEqual(res.body.error.code, 'NO_SUCH_FILE'); - assert.strictEqual(res.body.error.id, 'b6992544-63e7-67f0-fa7f-32444b1b5306'); + assert.strictEqual(castAsError(res.body).error.code, 'NO_SUCH_FILE'); + assert.strictEqual(castAsError(res.body).error.id, 'b6992544-63e7-67f0-fa7f-32444b1b5306'); }, 1000 * 10); test('存在しないファイルで怒られる', async () => { @@ -72,8 +74,8 @@ describe('Note', () => { }, alice); assert.strictEqual(res.status, 400); - assert.strictEqual(res.body.error.code, 'NO_SUCH_FILE'); - assert.strictEqual(res.body.error.id, 'b6992544-63e7-67f0-fa7f-32444b1b5306'); + assert.strictEqual(castAsError(res.body).error.code, 'NO_SUCH_FILE'); + assert.strictEqual(castAsError(res.body).error.id, 'b6992544-63e7-67f0-fa7f-32444b1b5306'); }); test('不正なファイルIDで怒られる', async () => { @@ -81,8 +83,8 @@ describe('Note', () => { fileIds: ['kyoppie'], }, alice); assert.strictEqual(res.status, 400); - assert.strictEqual(res.body.error.code, 'NO_SUCH_FILE'); - assert.strictEqual(res.body.error.id, 'b6992544-63e7-67f0-fa7f-32444b1b5306'); + assert.strictEqual(castAsError(res.body).error.code, 'NO_SUCH_FILE'); + assert.strictEqual(castAsError(res.body).error.id, 'b6992544-63e7-67f0-fa7f-32444b1b5306'); }); test('返信できる', async () => { @@ -101,6 +103,7 @@ describe('Note', () => { assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true); assert.strictEqual(res.body.createdNote.text, alicePost.text); assert.strictEqual(res.body.createdNote.replyId, alicePost.replyId); + assert.ok(res.body.createdNote.reply); assert.strictEqual(res.body.createdNote.reply.text, bobPost.text); }); @@ -118,6 +121,7 @@ describe('Note', () => { assert.strictEqual(res.status, 200); assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true); assert.strictEqual(res.body.createdNote.renoteId, alicePost.renoteId); + assert.ok(res.body.createdNote.renote); assert.strictEqual(res.body.createdNote.renote.text, bobPost.text); }); @@ -137,6 +141,7 @@ describe('Note', () => { assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true); assert.strictEqual(res.body.createdNote.text, alicePost.text); assert.strictEqual(res.body.createdNote.renoteId, alicePost.renoteId); + assert.ok(res.body.createdNote.renote); assert.strictEqual(res.body.createdNote.renote.text, bobPost.text); }); @@ -218,7 +223,7 @@ describe('Note', () => { }, bob); assert.strictEqual(bobReply.status, 400); - assert.strictEqual(bobReply.body.error.code, 'CANNOT_REPLY_TO_AN_INVISIBLE_NOTE'); + assert.strictEqual(castAsError(bobReply.body).error.code, 'CANNOT_REPLY_TO_AN_INVISIBLE_NOTE'); }); test('visibility: specifiedなノートに対してvisibility: specifiedで返信できる', async () => { @@ -256,7 +261,7 @@ describe('Note', () => { }, bob); assert.strictEqual(bobReply.status, 400); - assert.strictEqual(bobReply.body.error.code, 'CANNOT_REPLY_TO_SPECIFIED_VISIBILITY_NOTE_WITH_EXTENDED_VISIBILITY'); + assert.strictEqual(castAsError(bobReply.body).error.code, 'CANNOT_REPLY_TO_SPECIFIED_VISIBILITY_NOTE_WITH_EXTENDED_VISIBILITY'); }); test('文字数ぎりぎりで怒られない', async () => { @@ -333,6 +338,7 @@ describe('Note', () => { assert.strictEqual(res.body.createdNote.text, post.text); const noteDoc = await Notes.findOneBy({ id: res.body.createdNote.id }); + assert.ok(noteDoc); assert.deepStrictEqual(noteDoc.mentions, [bob.id]); }); @@ -345,6 +351,7 @@ describe('Note', () => { assert.strictEqual(res.status, 200); assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true); + assert.ok(res.body.createdNote.files); assert.strictEqual(res.body.createdNote.files.length, 1); assert.strictEqual(res.body.createdNote.files[0].id, file.body!.id); }); @@ -363,8 +370,9 @@ describe('Note', () => { assert.strictEqual(res.status, 200); assert.strictEqual(Array.isArray(res.body), true); - const myNote = res.body.find((note: { id: string; files: { id: string }[] }) => note.id === createdNote.body.createdNote.id); - assert.notEqual(myNote, null); + const myNote = res.body.find(note => note.id === createdNote.body.createdNote.id); + assert.ok(myNote); + assert.ok(myNote.files); assert.strictEqual(myNote.files.length, 1); assert.strictEqual(myNote.files[0].id, file.body!.id); }); @@ -389,7 +397,9 @@ describe('Note', () => { assert.strictEqual(res.status, 200); assert.strictEqual(Array.isArray(res.body), true); const myNote = res.body.find((note: { id: string }) => note.id === renoted.body.createdNote.id); - assert.notEqual(myNote, null); + assert.ok(myNote); + assert.ok(myNote.renote); + assert.ok(myNote.renote.files); assert.strictEqual(myNote.renote.files.length, 1); assert.strictEqual(myNote.renote.files[0].id, file.body!.id); }); @@ -415,7 +425,9 @@ describe('Note', () => { assert.strictEqual(res.status, 200); assert.strictEqual(Array.isArray(res.body), true); const myNote = res.body.find((note: { id: string }) => note.id === reply.body.createdNote.id); - assert.notEqual(myNote, null); + assert.ok(myNote); + assert.ok(myNote.reply); + assert.ok(myNote.reply.files); assert.strictEqual(myNote.reply.files.length, 1); assert.strictEqual(myNote.reply.files[0].id, file.body!.id); }); @@ -446,7 +458,10 @@ describe('Note', () => { assert.strictEqual(res.status, 200); assert.strictEqual(Array.isArray(res.body), true); const myNote = res.body.find((note: { id: string }) => note.id === renoted.body.createdNote.id); - assert.notEqual(myNote, null); + assert.ok(myNote); + assert.ok(myNote.renote); + assert.ok(myNote.renote.reply); + assert.ok(myNote.renote.reply.files); assert.strictEqual(myNote.renote.reply.files.length, 1); assert.strictEqual(myNote.renote.reply.files[0].id, file.body!.id); }); @@ -474,7 +489,7 @@ describe('Note', () => { priority: 0, value: true, }, - } as any, + }, }, root); assert.strictEqual(res.status, 200); @@ -498,7 +513,7 @@ describe('Note', () => { }, alice); assert.strictEqual(liftnsfw.status, 400); - assert.strictEqual(liftnsfw.body.error.code, 'RESTRICTED_BY_ROLE'); + assert.strictEqual(castAsError(liftnsfw.body).error.code, 'RESTRICTED_BY_ROLE'); const oldaddnsfw = await api('drive/files/update', { fileId: file.body!.id, @@ -710,7 +725,7 @@ describe('Note', () => { }, alice); assert.strictEqual(note1.status, 400); - assert.strictEqual(note1.body.error.code, 'CONTAINS_PROHIBITED_WORDS'); + assert.strictEqual(castAsError(note1.body).error.code, 'CONTAINS_PROHIBITED_WORDS'); }); test('禁止ワードを含む投稿はエラーになる (正規表現)', async () => { @@ -727,7 +742,7 @@ describe('Note', () => { }, alice); assert.strictEqual(note2.status, 400); - assert.strictEqual(note2.body.error.code, 'CONTAINS_PROHIBITED_WORDS'); + assert.strictEqual(castAsError(note2.body).error.code, 'CONTAINS_PROHIBITED_WORDS'); }); test('禁止ワードを含む投稿はエラーになる (スペースアンド)', async () => { @@ -744,7 +759,7 @@ describe('Note', () => { }, alice); assert.strictEqual(note2.status, 400); - assert.strictEqual(note2.body.error.code, 'CONTAINS_PROHIBITED_WORDS'); + assert.strictEqual(castAsError(note2.body).error.code, 'CONTAINS_PROHIBITED_WORDS'); }); test('禁止ワードを含んでるリモートノートもエラーになる', async () => { @@ -786,7 +801,7 @@ describe('Note', () => { priority: 1, value: 0, }, - } as any, + }, }, root); assert.strictEqual(res.status, 200); @@ -807,7 +822,7 @@ describe('Note', () => { }, alice); assert.strictEqual(note.status, 400); - assert.strictEqual(note.body.error.code, 'CONTAINS_TOO_MANY_MENTIONS'); + assert.strictEqual(castAsError(note.body).error.code, 'CONTAINS_TOO_MANY_MENTIONS'); await api('admin/roles/unassign', { userId: alice.id, @@ -840,7 +855,7 @@ describe('Note', () => { priority: 1, value: 0, }, - } as any, + }, }, root); assert.strictEqual(res.status, 200); @@ -863,7 +878,7 @@ describe('Note', () => { }, alice); assert.strictEqual(note.status, 400); - assert.strictEqual(note.body.error.code, 'CONTAINS_TOO_MANY_MENTIONS'); + assert.strictEqual(castAsError(note.body).error.code, 'CONTAINS_TOO_MANY_MENTIONS'); await api('admin/roles/unassign', { userId: alice.id, @@ -896,7 +911,7 @@ describe('Note', () => { priority: 1, value: 1, }, - } as any, + }, }, root); assert.strictEqual(res.status, 200); @@ -951,6 +966,7 @@ describe('Note', () => { assert.strictEqual(deleteOneRes.status, 204); let mainNote = await Notes.findOneBy({ id: mainNoteRes.body.createdNote.id }); + assert.ok(mainNote); assert.strictEqual(mainNote.repliesCount, 1); const deleteTwoRes = await api('notes/delete', { @@ -959,6 +975,7 @@ describe('Note', () => { assert.strictEqual(deleteTwoRes.status, 204); mainNote = await Notes.findOneBy({ id: mainNoteRes.body.createdNote.id }); + assert.ok(mainNote); assert.strictEqual(mainNote.repliesCount, 0); }); }); @@ -980,7 +997,7 @@ describe('Note', () => { }, alice); assert.strictEqual(res.status, 400); - assert.strictEqual(res.body.error.code, 'UNAVAILABLE'); + assert.strictEqual(castAsError(res.body).error.code, 'UNAVAILABLE'); }); afterAll(async () => { @@ -992,7 +1009,7 @@ describe('Note', () => { const res = await api('notes/translate', { noteId: 'foo', targetLang: 'ja' }, alice); assert.strictEqual(res.status, 400); - assert.strictEqual(res.body.error.code, 'NO_SUCH_NOTE'); + assert.strictEqual(castAsError(res.body).error.code, 'NO_SUCH_NOTE'); }); test('不可視なノートは翻訳できない', async () => { @@ -1000,7 +1017,7 @@ describe('Note', () => { const bobTranslateAttempt = await api('notes/translate', { noteId: aliceNote.id, targetLang: 'ja' }, bob); assert.strictEqual(bobTranslateAttempt.status, 400); - assert.strictEqual(bobTranslateAttempt.body.error.code, 'CANNOT_TRANSLATE_INVISIBLE_NOTE'); + assert.strictEqual(castAsError(bobTranslateAttempt.body).error.code, 'CANNOT_TRANSLATE_INVISIBLE_NOTE'); }); test('text: null なノートを翻訳すると空のレスポンスが返ってくる', async () => { @@ -1016,7 +1033,7 @@ describe('Note', () => { // NOTE: デフォルトでは登録されていないので落ちる assert.strictEqual(res.status, 400); - assert.strictEqual(res.body.error.code, 'UNAVAILABLE'); + assert.strictEqual(castAsError(res.body).error.code, 'UNAVAILABLE'); }); }); }); diff --git a/packages/backend/test/e2e/renote-mute.ts b/packages/backend/test/e2e/renote-mute.ts index 1abbb4f044..0f636b9ae2 100644 --- a/packages/backend/test/e2e/renote-mute.ts +++ b/packages/backend/test/e2e/renote-mute.ts @@ -6,7 +6,8 @@ process.env.NODE_ENV = 'test'; import * as assert from 'assert'; -import { api, post, signup, sleep, waitFire } from '../utils.js'; +import { setTimeout } from 'node:timers/promises'; +import { api, post, signup, waitFire } from '../utils.js'; import type * as misskey from 'misskey-js'; describe('Renote Mute', () => { @@ -35,15 +36,15 @@ describe('Renote Mute', () => { const carolNote = await post(carol, { text: 'hi' }); // redisに追加されるのを待つ - await sleep(100); + await setTimeout(100); const res = await api('notes/local-timeline', {}, alice); assert.strictEqual(res.status, 200); assert.strictEqual(Array.isArray(res.body), true); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true); - assert.strictEqual(res.body.some((note: any) => note.id === carolRenote.id), false); - assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), true); + assert.strictEqual(res.body.some(note => note.id === bobNote.id), true); + assert.strictEqual(res.body.some(note => note.id === carolRenote.id), false); + assert.strictEqual(res.body.some(note => note.id === carolNote.id), true); }); test('タイムラインにリノートミュートしているユーザーの引用が含まれる', async () => { @@ -52,15 +53,15 @@ describe('Renote Mute', () => { const carolNote = await post(carol, { text: 'hi' }); // redisに追加されるのを待つ - await sleep(100); + await setTimeout(100); const res = await api('notes/local-timeline', {}, alice); assert.strictEqual(res.status, 200); assert.strictEqual(Array.isArray(res.body), true); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true); - assert.strictEqual(res.body.some((note: any) => note.id === carolRenote.id), true); - assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), true); + assert.strictEqual(res.body.some(note => note.id === bobNote.id), true); + assert.strictEqual(res.body.some(note => note.id === carolRenote.id), true); + assert.strictEqual(res.body.some(note => note.id === carolNote.id), true); }); // #12956 @@ -69,14 +70,14 @@ describe('Renote Mute', () => { const bobRenote = await post(bob, { renoteId: carolNote.id }); // redisに追加されるのを待つ - await sleep(100); + await setTimeout(100); const res = await api('notes/local-timeline', {}, alice); assert.strictEqual(res.status, 200); assert.strictEqual(Array.isArray(res.body), true); - assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), true); - assert.strictEqual(res.body.some((note: any) => note.id === bobRenote.id), true); + assert.strictEqual(res.body.some(note => note.id === carolNote.id), true); + assert.strictEqual(res.body.some(note => note.id === bobRenote.id), true); }); test('ストリームにリノートミュートしているユーザーのリノートが流れない', async () => { diff --git a/packages/backend/test/e2e/synalio/abuse-report.ts b/packages/backend/test/e2e/synalio/abuse-report.ts new file mode 100644 index 0000000000..b0cc3d13ec --- /dev/null +++ b/packages/backend/test/e2e/synalio/abuse-report.ts @@ -0,0 +1,401 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { entities } from 'misskey-js'; +import { beforeEach, describe, test } from '@jest/globals'; +import Fastify from 'fastify'; +import { api, randomString, role, signup, startJobQueue, UserToken } from '../../utils.js'; +import type { INestApplicationContext } from '@nestjs/common'; + +const WEBHOOK_HOST = 'http://localhost:15080'; +const WEBHOOK_PORT = 15080; +process.env.NODE_ENV = 'test'; + +describe('[シナリオ] ユーザ通報', () => { + let queue: INestApplicationContext; + let admin: entities.SignupResponse; + let alice: entities.SignupResponse; + let bob: entities.SignupResponse; + + type SystemWebhookPayload = { + server: string; + hookId: string; + eventId: string; + createdAt: string; + type: string; + body: any; + } + + // ------------------------------------------------------------------------------------------- + + async function captureWebhook(postAction: () => Promise): Promise { + const fastify = Fastify(); + + let timeoutHandle: NodeJS.Timeout | null = null; + const result = await new Promise(async (resolve, reject) => { + fastify.all('/', async (req, res) => { + timeoutHandle && clearTimeout(timeoutHandle); + + const body = JSON.stringify(req.body); + res.status(200).send('ok'); + await fastify.close(); + resolve(body); + }); + + await fastify.listen({ port: WEBHOOK_PORT }); + + timeoutHandle = setTimeout(async () => { + await fastify.close(); + reject(new Error('timeout')); + }, 3000); + + try { + await postAction(); + } catch (e) { + await fastify.close(); + reject(e); + } + }); + + await fastify.close(); + + return JSON.parse(result) as T; + } + + async function createSystemWebhook(args?: Partial, credential?: UserToken): Promise { + const res = await api( + 'admin/system-webhook/create', + { + isActive: true, + name: randomString(), + on: ['abuseReport'], + url: WEBHOOK_HOST, + secret: randomString(), + ...args, + }, + credential ?? admin, + ); + return res.body; + } + + async function createAbuseReportNotificationRecipient(args?: Partial, credential?: UserToken): Promise { + const res = await api( + 'admin/abuse-report/notification-recipient/create', + { + isActive: true, + name: randomString(), + method: 'webhook', + ...args, + }, + credential ?? admin, + ); + return res.body; + } + + async function createAbuseReport(args?: Partial, credential?: UserToken): Promise { + const res = await api( + 'users/report-abuse', + { + userId: alice.id, + comment: randomString(), + ...args, + }, + credential ?? admin, + ); + return res.body; + } + + async function resolveAbuseReport(args?: Partial, credential?: UserToken): Promise { + const res = await api( + 'admin/resolve-abuse-user-report', + { + reportId: admin.id, + ...args, + }, + credential ?? admin, + ); + return res.body; + } + + // ------------------------------------------------------------------------------------------- + + beforeAll(async () => { + queue = await startJobQueue(); + admin = await signup({ username: 'admin' }); + alice = await signup({ username: 'alice' }); + bob = await signup({ username: 'bob' }); + + await role(admin, { isAdministrator: true }); + }, 1000 * 60 * 2); + + afterAll(async () => { + await queue.close(); + }); + + // ------------------------------------------------------------------------------------------- + + describe('SystemWebhook', () => { + beforeEach(async () => { + const webhooks = await api('admin/system-webhook/list', {}, admin); + for (const webhook of webhooks.body) { + await api('admin/system-webhook/delete', { id: webhook.id }, admin); + } + }); + + test('通報を受けた -> abuseReportが送出される', async () => { + const webhook = await createSystemWebhook({ + on: ['abuseReport'], + isActive: true, + }); + await createAbuseReportNotificationRecipient({ systemWebhookId: webhook.id }); + + // 通報(bob -> alice) + const abuse = { + userId: alice.id, + comment: randomString(), + }; + const webhookBody = await captureWebhook(async () => { + await createAbuseReport(abuse, bob); + }); + + console.log(JSON.stringify(webhookBody, null, 2)); + + expect(webhookBody.hookId).toBe(webhook.id); + expect(webhookBody.type).toBe('abuseReport'); + expect(webhookBody.body.targetUserId).toBe(alice.id); + expect(webhookBody.body.reporterId).toBe(bob.id); + expect(webhookBody.body.comment).toBe(abuse.comment); + }); + + test('通報を受けた -> abuseReportが送出される -> 解決 -> abuseReportResolvedが送出される', async () => { + const webhook = await createSystemWebhook({ + on: ['abuseReport', 'abuseReportResolved'], + isActive: true, + }); + await createAbuseReportNotificationRecipient({ systemWebhookId: webhook.id }); + + // 通報(bob -> alice) + const abuse = { + userId: alice.id, + comment: randomString(), + }; + const webhookBody1 = await captureWebhook(async () => { + await createAbuseReport(abuse, bob); + }); + + console.log(JSON.stringify(webhookBody1, null, 2)); + expect(webhookBody1.hookId).toBe(webhook.id); + expect(webhookBody1.type).toBe('abuseReport'); + expect(webhookBody1.body.targetUserId).toBe(alice.id); + expect(webhookBody1.body.reporterId).toBe(bob.id); + expect(webhookBody1.body.assigneeId).toBeNull(); + expect(webhookBody1.body.resolved).toBe(false); + expect(webhookBody1.body.comment).toBe(abuse.comment); + + // 解決 + const webhookBody2 = await captureWebhook(async () => { + await resolveAbuseReport({ + reportId: webhookBody1.body.id, + forward: false, + }, admin); + }); + + console.log(JSON.stringify(webhookBody2, null, 2)); + expect(webhookBody2.hookId).toBe(webhook.id); + expect(webhookBody2.type).toBe('abuseReportResolved'); + expect(webhookBody2.body.targetUserId).toBe(alice.id); + expect(webhookBody2.body.reporterId).toBe(bob.id); + expect(webhookBody2.body.assigneeId).toBe(admin.id); + expect(webhookBody2.body.resolved).toBe(true); + expect(webhookBody2.body.comment).toBe(abuse.comment); + }); + + test('通報を受けた -> abuseReportが未許可の場合は送出されない', async () => { + const webhook = await createSystemWebhook({ + on: [], + isActive: true, + }); + await createAbuseReportNotificationRecipient({ systemWebhookId: webhook.id }); + + // 通報(bob -> alice) + const abuse = { + userId: alice.id, + comment: randomString(), + }; + const webhookBody = await captureWebhook(async () => { + await createAbuseReport(abuse, bob); + }).catch(e => e.message); + + expect(webhookBody).toBe('timeout'); + }); + + test('通報を受けた -> abuseReportが未許可の場合は送出されない -> 解決 -> abuseReportResolvedが送出される', async () => { + const webhook = await createSystemWebhook({ + on: ['abuseReportResolved'], + isActive: true, + }); + await createAbuseReportNotificationRecipient({ systemWebhookId: webhook.id }); + + // 通報(bob -> alice) + const abuse = { + userId: alice.id, + comment: randomString(), + }; + const webhookBody1 = await captureWebhook(async () => { + await createAbuseReport(abuse, bob); + }).catch(e => e.message); + + expect(webhookBody1).toBe('timeout'); + + const abuseReportId = (await api('admin/abuse-user-reports', {}, admin)).body[0].id; + + // 解決 + const webhookBody2 = await captureWebhook(async () => { + await resolveAbuseReport({ + reportId: abuseReportId, + forward: false, + }, admin); + }); + + console.log(JSON.stringify(webhookBody2, null, 2)); + expect(webhookBody2.hookId).toBe(webhook.id); + expect(webhookBody2.type).toBe('abuseReportResolved'); + expect(webhookBody2.body.targetUserId).toBe(alice.id); + expect(webhookBody2.body.reporterId).toBe(bob.id); + expect(webhookBody2.body.assigneeId).toBe(admin.id); + expect(webhookBody2.body.resolved).toBe(true); + expect(webhookBody2.body.comment).toBe(abuse.comment); + }); + + test('通報を受けた -> abuseReportが送出される -> 解決 -> abuseReportResolvedが未許可の場合は送出されない', async () => { + const webhook = await createSystemWebhook({ + on: ['abuseReport'], + isActive: true, + }); + await createAbuseReportNotificationRecipient({ systemWebhookId: webhook.id }); + + // 通報(bob -> alice) + const abuse = { + userId: alice.id, + comment: randomString(), + }; + const webhookBody1 = await captureWebhook(async () => { + await createAbuseReport(abuse, bob); + }); + + console.log(JSON.stringify(webhookBody1, null, 2)); + expect(webhookBody1.hookId).toBe(webhook.id); + expect(webhookBody1.type).toBe('abuseReport'); + expect(webhookBody1.body.targetUserId).toBe(alice.id); + expect(webhookBody1.body.reporterId).toBe(bob.id); + expect(webhookBody1.body.assigneeId).toBeNull(); + expect(webhookBody1.body.resolved).toBe(false); + expect(webhookBody1.body.comment).toBe(abuse.comment); + + // 解決 + const webhookBody2 = await captureWebhook(async () => { + await resolveAbuseReport({ + reportId: webhookBody1.body.id, + forward: false, + }, admin); + }).catch(e => e.message); + + expect(webhookBody2).toBe('timeout'); + }); + + test('通報を受けた -> abuseReportが未許可の場合は送出されない -> 解決 -> abuseReportResolvedが未許可の場合は送出されない', async () => { + const webhook = await createSystemWebhook({ + on: [], + isActive: true, + }); + await createAbuseReportNotificationRecipient({ systemWebhookId: webhook.id }); + + // 通報(bob -> alice) + const abuse = { + userId: alice.id, + comment: randomString(), + }; + const webhookBody1 = await captureWebhook(async () => { + await createAbuseReport(abuse, bob); + }).catch(e => e.message); + + expect(webhookBody1).toBe('timeout'); + + const abuseReportId = (await api('admin/abuse-user-reports', {}, admin)).body[0].id; + + // 解決 + const webhookBody2 = await captureWebhook(async () => { + await resolveAbuseReport({ + reportId: abuseReportId, + forward: false, + }, admin); + }).catch(e => e.message); + + expect(webhookBody2).toBe('timeout'); + }); + + test('通報を受けた -> Webhookが無効の場合は送出されない', async () => { + const webhook = await createSystemWebhook({ + on: ['abuseReport', 'abuseReportResolved'], + isActive: false, + }); + await createAbuseReportNotificationRecipient({ systemWebhookId: webhook.id }); + + // 通報(bob -> alice) + const abuse = { + userId: alice.id, + comment: randomString(), + }; + const webhookBody1 = await captureWebhook(async () => { + await createAbuseReport(abuse, bob); + }).catch(e => e.message); + + expect(webhookBody1).toBe('timeout'); + + const abuseReportId = (await api('admin/abuse-user-reports', {}, admin)).body[0].id; + + // 解決 + const webhookBody2 = await captureWebhook(async () => { + await resolveAbuseReport({ + reportId: abuseReportId, + forward: false, + }, admin); + }).catch(e => e.message); + + expect(webhookBody2).toBe('timeout'); + }); + + test('通報を受けた -> 通知設定が無効の場合は送出されない', async () => { + const webhook = await createSystemWebhook({ + on: ['abuseReport', 'abuseReportResolved'], + isActive: true, + }); + await createAbuseReportNotificationRecipient({ systemWebhookId: webhook.id, isActive: false }); + + // 通報(bob -> alice) + const abuse = { + userId: alice.id, + comment: randomString(), + }; + const webhookBody1 = await captureWebhook(async () => { + await createAbuseReport(abuse, bob); + }).catch(e => e.message); + + expect(webhookBody1).toBe('timeout'); + + const abuseReportId = (await api('admin/abuse-user-reports', {}, admin)).body[0].id; + + // 解決 + const webhookBody2 = await captureWebhook(async () => { + await resolveAbuseReport({ + reportId: abuseReportId, + forward: false, + }, admin); + }).catch(e => e.message); + + expect(webhookBody2).toBe('timeout'); + }); + }); +}); diff --git a/packages/backend/test/e2e/thread-mute.ts b/packages/backend/test/e2e/thread-mute.ts index 53bb6eb765..1ac99df884 100644 --- a/packages/backend/test/e2e/thread-mute.ts +++ b/packages/backend/test/e2e/thread-mute.ts @@ -33,9 +33,9 @@ describe('Note thread mute', () => { assert.strictEqual(res.status, 200); assert.strictEqual(Array.isArray(res.body), true); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false); - assert.strictEqual(res.body.some((note: any) => note.id === carolReply.id), false); - assert.strictEqual(res.body.some((note: any) => note.id === carolReplyWithoutMention.id), false); + assert.strictEqual(res.body.some(note => note.id === bobNote.id), false); + assert.strictEqual(res.body.some(note => note.id === carolReply.id), false); + assert.strictEqual(res.body.some(note => note.id === carolReplyWithoutMention.id), false); }); test('ミュートしているスレッドからメンションされても、hasUnreadMentions が true にならない', async () => { @@ -93,8 +93,8 @@ describe('Note thread mute', () => { assert.strictEqual(res.status, 200); assert.strictEqual(Array.isArray(res.body), true); - assert.strictEqual(res.body.some((notification: any) => notification.note.id === carolReply.id), false); - assert.strictEqual(res.body.some((notification: any) => notification.note.id === carolReplyWithoutMention.id), false); + assert.strictEqual(res.body.some(notification => 'note' in notification && notification.note.id === carolReply.id), false); + assert.strictEqual(res.body.some(notification => 'note' in notification && notification.note.id === carolReplyWithoutMention.id), false); // NOTE: bobの投稿はスレッドミュート前に行われたため通知に含まれていてもよい }); diff --git a/packages/backend/test/e2e/timelines.ts b/packages/backend/test/e2e/timelines.ts index 5487292afc..fce1eacf00 100644 --- a/packages/backend/test/e2e/timelines.ts +++ b/packages/backend/test/e2e/timelines.ts @@ -7,17 +7,26 @@ // pnpm jest -- e2e/timelines.ts import * as assert from 'assert'; -import { api, post, randomString, sendEnvUpdateRequest, signup, sleep, uploadUrl } from '../utils.js'; +import { setTimeout } from 'node:timers/promises'; +import { Redis } from 'ioredis'; +import { loadConfig } from '@/config.js'; +import { api, post, randomString, sendEnvUpdateRequest, signup, uploadUrl } from '../utils.js'; function genHost() { return randomString() + '.example.com'; } function waitForPushToTl() { - return sleep(500); + return setTimeout(500); } +let redisForTimelines: Redis; + describe('Timelines', () => { + beforeAll(() => { + redisForTimelines = new Redis(loadConfig().redisForTimelines); + }); + describe('Home TL', () => { test.concurrent('自分の visibility: followers なノートが含まれる', async () => { const [alice] = await Promise.all([signup()]); @@ -28,15 +37,15 @@ describe('Timelines', () => { const res = await api('notes/timeline', { limit: 100 }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === aliceNote.id), true); - assert.strictEqual(res.body.find((note: any) => note.id === aliceNote.id).text, 'hi'); + assert.strictEqual(res.body.some(note => note.id === aliceNote.id), true); + assert.strictEqual(res.body.find(note => note.id === aliceNote.id)?.text, 'hi'); }); test.concurrent('フォローしているユーザーのノートが含まれる', async () => { const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]); await api('following/create', { userId: bob.id }, alice); - await sleep(1000); + await setTimeout(1000); const bobNote = await post(bob, { text: 'hi' }); const carolNote = await post(carol, { text: 'hi' }); @@ -44,15 +53,15 @@ describe('Timelines', () => { const res = await api('notes/timeline', { limit: 100 }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true); - assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false); + assert.strictEqual(res.body.some(note => note.id === bobNote.id), true); + assert.strictEqual(res.body.some(note => note.id === carolNote.id), false); }); test.concurrent('フォローしているユーザーの visibility: followers なノートが含まれる', async () => { const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]); await api('following/create', { userId: bob.id }, alice); - await sleep(1000); + await setTimeout(1000); const bobNote = await post(bob, { text: 'hi', visibility: 'followers' }); const carolNote = await post(carol, { text: 'hi' }); @@ -60,16 +69,16 @@ describe('Timelines', () => { const res = await api('notes/timeline', { limit: 100 }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true); - assert.strictEqual(res.body.find((note: any) => note.id === bobNote.id).text, 'hi'); - assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false); + assert.strictEqual(res.body.some(note => note.id === bobNote.id), true); + assert.strictEqual(res.body.find(note => note.id === bobNote.id)?.text, 'hi'); + assert.strictEqual(res.body.some(note => note.id === carolNote.id), false); }); test.concurrent('withReplies: false でフォローしているユーザーの他人への返信が含まれない', async () => { const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]); await api('following/create', { userId: bob.id }, alice); - await sleep(1000); + await setTimeout(1000); const carolNote = await post(carol, { text: 'hi' }); const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id }); @@ -77,8 +86,8 @@ describe('Timelines', () => { const res = await api('notes/timeline', { limit: 100 }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false); - assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false); + assert.strictEqual(res.body.some(note => note.id === bobNote.id), false); + assert.strictEqual(res.body.some(note => note.id === carolNote.id), false); }); test.concurrent('withReplies: true でフォローしているユーザーの他人への返信が含まれる', async () => { @@ -86,7 +95,7 @@ describe('Timelines', () => { await api('following/create', { userId: bob.id }, alice); await api('following/update', { userId: bob.id, withReplies: true }, alice); - await sleep(1000); + await setTimeout(1000); const carolNote = await post(carol, { text: 'hi' }); const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id }); @@ -94,8 +103,8 @@ describe('Timelines', () => { const res = await api('notes/timeline', { limit: 100 }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true); - assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false); + assert.strictEqual(res.body.some(note => note.id === bobNote.id), true); + assert.strictEqual(res.body.some(note => note.id === carolNote.id), false); }); test.concurrent('withReplies: true でフォローしているユーザーの他人へのDM返信が含まれない', async () => { @@ -103,7 +112,7 @@ describe('Timelines', () => { await api('following/create', { userId: bob.id }, alice); await api('following/update', { userId: bob.id, withReplies: true }, alice); - await sleep(1000); + await setTimeout(1000); const carolNote = await post(carol, { text: 'hi' }); const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id, visibility: 'specified', visibleUserIds: [carolNote.id] }); @@ -111,8 +120,8 @@ describe('Timelines', () => { const res = await api('notes/timeline', { limit: 100 }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false); - assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false); + assert.strictEqual(res.body.some(note => note.id === bobNote.id), false); + assert.strictEqual(res.body.some(note => note.id === carolNote.id), false); }); test.concurrent('withReplies: true でフォローしているユーザーの他人の visibility: followers な投稿への返信が含まれない', async () => { @@ -120,7 +129,7 @@ describe('Timelines', () => { await api('following/create', { userId: bob.id }, alice); await api('following/update', { userId: bob.id, withReplies: true }, alice); - await sleep(1000); + await setTimeout(1000); const carolNote = await post(carol, { text: 'hi', visibility: 'followers' }); const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id }); @@ -128,8 +137,8 @@ describe('Timelines', () => { const res = await api('notes/timeline', { limit: 100 }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false); - assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false); + assert.strictEqual(res.body.some(note => note.id === bobNote.id), false); + assert.strictEqual(res.body.some(note => note.id === carolNote.id), false); }); test.concurrent('withReplies: true でフォローしているユーザーの行った別のフォローしているユーザーの visibility: followers な投稿への返信が含まれる', async () => { @@ -139,7 +148,7 @@ describe('Timelines', () => { await api('following/create', { userId: carol.id }, alice); await api('following/create', { userId: carol.id }, bob); await api('following/update', { userId: bob.id, withReplies: true }, alice); - await sleep(1000); + await setTimeout(1000); const carolNote = await post(carol, { text: 'hi', visibility: 'followers' }); const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id }); @@ -147,9 +156,9 @@ describe('Timelines', () => { const res = await api('notes/timeline', { limit: 100 }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true); - assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), true); - assert.strictEqual(res.body.find((note: any) => note.id === carolNote.id).text, 'hi'); + assert.strictEqual(res.body.some(note => note.id === bobNote.id), true); + assert.strictEqual(res.body.some(note => note.id === carolNote.id), true); + assert.strictEqual(res.body.find(note => note.id === carolNote.id)?.text, 'hi'); }); test.concurrent('withReplies: true でフォローしているユーザーの行った別のフォローしているユーザーの投稿への visibility: specified な返信が含まれない', async () => { @@ -158,7 +167,7 @@ describe('Timelines', () => { await api('following/create', { userId: bob.id }, alice); await api('following/create', { userId: carol.id }, alice); await api('following/update', { userId: bob.id, withReplies: true }, alice); - await sleep(1000); + await setTimeout(1000); const carolNote = await post(carol, { text: 'hi' }); const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id, visibility: 'specified', visibleUserIds: [carolNote.id] }); @@ -166,15 +175,15 @@ describe('Timelines', () => { const res = await api('notes/timeline', { limit: 100 }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false); - assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), true); + assert.strictEqual(res.body.some(note => note.id === bobNote.id), false); + assert.strictEqual(res.body.some(note => note.id === carolNote.id), true); }); test.concurrent('withReplies: false でフォローしているユーザーのそのユーザー自身への返信が含まれる', async () => { const [alice, bob] = await Promise.all([signup(), signup()]); await api('following/create', { userId: bob.id }, alice); - await sleep(1000); + await setTimeout(1000); const bobNote1 = await post(bob, { text: 'hi' }); const bobNote2 = await post(bob, { text: 'hi', replyId: bobNote1.id }); @@ -182,15 +191,15 @@ describe('Timelines', () => { const res = await api('notes/timeline', { limit: 100 }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote1.id), true); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote2.id), true); + assert.strictEqual(res.body.some(note => note.id === bobNote1.id), true); + assert.strictEqual(res.body.some(note => note.id === bobNote2.id), true); }); test.concurrent('withReplies: false でフォローしているユーザーからの自分への返信が含まれる', async () => { const [alice, bob] = await Promise.all([signup(), signup()]); await api('following/create', { userId: bob.id }, alice); - await sleep(1000); + await setTimeout(1000); const aliceNote = await post(alice, { text: 'hi' }); const bobNote = await post(bob, { text: 'hi', replyId: aliceNote.id }); @@ -198,8 +207,8 @@ describe('Timelines', () => { const res = await api('notes/timeline', { limit: 100 }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === aliceNote.id), true); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true); + assert.strictEqual(res.body.some(note => note.id === aliceNote.id), true); + assert.strictEqual(res.body.some(note => note.id === bobNote.id), true); }); test.concurrent('自分の他人への返信が含まれる', async () => { @@ -212,15 +221,15 @@ describe('Timelines', () => { const res = await api('notes/timeline', { limit: 100 }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false); - assert.strictEqual(res.body.some((note: any) => note.id === aliceNote.id), true); + assert.strictEqual(res.body.some(note => note.id === bobNote.id), false); + assert.strictEqual(res.body.some(note => note.id === aliceNote.id), true); }); test.concurrent('フォローしているユーザーの他人の投稿のリノートが含まれる', async () => { const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]); await api('following/create', { userId: bob.id }, alice); - await sleep(1000); + await setTimeout(1000); const carolNote = await post(carol, { text: 'hi' }); const bobNote = await post(bob, { renoteId: carolNote.id }); @@ -228,15 +237,15 @@ describe('Timelines', () => { const res = await api('notes/timeline', { limit: 100 }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true); - assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false); + assert.strictEqual(res.body.some(note => note.id === bobNote.id), true); + assert.strictEqual(res.body.some(note => note.id === carolNote.id), false); }); test.concurrent('[withRenotes: false] フォローしているユーザーの他人の投稿のリノートが含まれない', async () => { const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]); await api('following/create', { userId: bob.id }, alice); - await sleep(1000); + await setTimeout(1000); const carolNote = await post(carol, { text: 'hi' }); const bobNote = await post(bob, { renoteId: carolNote.id }); @@ -246,15 +255,15 @@ describe('Timelines', () => { withRenotes: false, }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false); - assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false); + assert.strictEqual(res.body.some(note => note.id === bobNote.id), false); + assert.strictEqual(res.body.some(note => note.id === carolNote.id), false); }); test.concurrent('[withRenotes: false] フォローしているユーザーの他人の投稿の引用が含まれる', async () => { const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]); await api('following/create', { userId: bob.id }, alice); - await sleep(1000); + await setTimeout(1000); const carolNote = await post(carol, { text: 'hi' }); const bobNote = await post(bob, { text: 'hi', renoteId: carolNote.id }); @@ -264,22 +273,22 @@ describe('Timelines', () => { withRenotes: false, }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true); - assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false); + assert.strictEqual(res.body.some(note => note.id === bobNote.id), true); + assert.strictEqual(res.body.some(note => note.id === carolNote.id), false); }); test.concurrent('フォローしているユーザーの他人への visibility: specified なノートが含まれない', async () => { const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]); await api('following/create', { userId: bob.id }, alice); - await sleep(1000); + await setTimeout(1000); const bobNote = await post(bob, { text: 'hi', visibility: 'specified', visibleUserIds: [carol.id] }); await waitForPushToTl(); const res = await api('notes/timeline', { limit: 100 }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false); + assert.strictEqual(res.body.some(note => note.id === bobNote.id), false); }); test.concurrent('フォローしているユーザーが行ったミュートしているユーザーのリノートが含まれない', async () => { @@ -287,7 +296,7 @@ describe('Timelines', () => { await api('following/create', { userId: bob.id }, alice); await api('mute/create', { userId: carol.id }, alice); - await sleep(1000); + await setTimeout(1000); const carolNote = await post(carol, { text: 'hi' }); const bobNote = await post(bob, { text: 'hi', renoteId: carolNote.id }); @@ -295,8 +304,8 @@ describe('Timelines', () => { const res = await api('notes/timeline', { limit: 100 }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false); - assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false); + assert.strictEqual(res.body.some(note => note.id === bobNote.id), false); + assert.strictEqual(res.body.some(note => note.id === carolNote.id), false); }); test.concurrent('withReplies: true でフォローしているユーザーが行ったミュートしているユーザーの投稿への返信が含まれない', async () => { @@ -305,7 +314,7 @@ describe('Timelines', () => { await api('following/create', { userId: bob.id }, alice); await api('following/update', { userId: bob.id, withReplies: true }, alice); await api('mute/create', { userId: carol.id }, alice); - await sleep(1000); + await setTimeout(1000); const carolNote = await post(carol, { text: 'hi' }); const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id }); @@ -313,8 +322,8 @@ describe('Timelines', () => { const res = await api('notes/timeline', { limit: 100 }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false); - assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false); + assert.strictEqual(res.body.some(note => note.id === bobNote.id), false); + assert.strictEqual(res.body.some(note => note.id === carolNote.id), false); }); test.concurrent('フォローしているリモートユーザーのノートが含まれる', async () => { @@ -329,7 +338,7 @@ describe('Timelines', () => { const res = await api('notes/timeline', { limit: 100 }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true); + assert.strictEqual(res.body.some(note => note.id === bobNote.id), true); }); test.concurrent('フォローしているリモートユーザーの visibility: home なノートが含まれる', async () => { @@ -344,14 +353,14 @@ describe('Timelines', () => { const res = await api('notes/timeline', { limit: 100 }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true); + assert.strictEqual(res.body.some(note => note.id === bobNote.id), true); }); test.concurrent('[withFiles: true] フォローしているユーザーのファイル付きノートのみ含まれる', async () => { const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]); await api('following/create', { userId: bob.id }, alice); - await sleep(1000); + await setTimeout(1000); const [bobFile, carolFile] = await Promise.all([ uploadUrl(bob, 'https://raw.githubusercontent.com/misskey-dev/assets/main/public/icon.png'), uploadUrl(carol, 'https://raw.githubusercontent.com/misskey-dev/assets/main/public/icon.png'), @@ -365,25 +374,25 @@ describe('Timelines', () => { const res = await api('notes/timeline', { limit: 100, withFiles: true }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote1.id), false); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote2.id), true); - assert.strictEqual(res.body.some((note: any) => note.id === carolNote1.id), false); - assert.strictEqual(res.body.some((note: any) => note.id === carolNote2.id), false); - }, 1000 * 10); + assert.strictEqual(res.body.some(note => note.id === bobNote1.id), false); + assert.strictEqual(res.body.some(note => note.id === bobNote2.id), true); + assert.strictEqual(res.body.some(note => note.id === carolNote1.id), false); + assert.strictEqual(res.body.some(note => note.id === carolNote2.id), false); + }); test.concurrent('フォローしているユーザーのチャンネル投稿が含まれない', async () => { const [alice, bob] = await Promise.all([signup(), signup()]); const channel = await api('channels/create', { name: 'channel' }, bob).then(x => x.body); await api('following/create', { userId: bob.id }, alice); - await sleep(1000); + await setTimeout(1000); const bobNote = await post(bob, { text: 'hi', channelId: channel.id }); await waitForPushToTl(); const res = await api('notes/timeline', { limit: 100 }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false); + assert.strictEqual(res.body.some(note => note.id === bobNote.id), false); }); test.concurrent('自分の visibility: specified なノートが含まれる', async () => { @@ -395,23 +404,23 @@ describe('Timelines', () => { const res = await api('notes/timeline', { limit: 100 }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === aliceNote.id), true); - assert.strictEqual(res.body.find((note: any) => note.id === aliceNote.id).text, 'hi'); + assert.strictEqual(res.body.some(note => note.id === aliceNote.id), true); + assert.strictEqual(res.body.find(note => note.id === aliceNote.id)?.text, 'hi'); }); test.concurrent('フォローしているユーザーの自身を visibleUserIds に指定した visibility: specified なノートが含まれる', async () => { const [alice, bob] = await Promise.all([signup(), signup()]); await api('following/create', { userId: bob.id }, alice); - await sleep(1000); + await setTimeout(1000); const bobNote = await post(bob, { text: 'hi', visibility: 'specified', visibleUserIds: [alice.id] }); await waitForPushToTl(); const res = await api('notes/timeline', { limit: 100 }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true); - assert.strictEqual(res.body.find((note: any) => note.id === bobNote.id).text, 'hi'); + assert.strictEqual(res.body.some(note => note.id === bobNote.id), true); + assert.strictEqual(res.body.find(note => note.id === bobNote.id)?.text, 'hi'); }); test.concurrent('フォローしていないユーザーの自身を visibleUserIds に指定した visibility: specified なノートが含まれない', async () => { @@ -423,21 +432,21 @@ describe('Timelines', () => { const res = await api('notes/timeline', { limit: 100 }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false); + assert.strictEqual(res.body.some(note => note.id === bobNote.id), false); }); test.concurrent('フォローしているユーザーの自身を visibleUserIds に指定していない visibility: specified なノートが含まれない', async () => { const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]); await api('following/create', { userId: bob.id }, alice); - await sleep(1000); + await setTimeout(1000); const bobNote = await post(bob, { text: 'hi', visibility: 'specified', visibleUserIds: [carol.id] }); await waitForPushToTl(); const res = await api('notes/timeline', { limit: 100 }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false); + assert.strictEqual(res.body.some(note => note.id === bobNote.id), false); }); test.concurrent('フォローしていないユーザーからの visibility: specified なノートに返信したときの自身のノートが含まれる', async () => { @@ -450,8 +459,8 @@ describe('Timelines', () => { const res = await api('notes/timeline', { limit: 100 }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === aliceNote.id), true); - assert.strictEqual(res.body.find((note: any) => note.id === aliceNote.id).text, 'ok'); + assert.strictEqual(res.body.some(note => note.id === aliceNote.id), true); + assert.strictEqual(res.body.find(note => note.id === aliceNote.id)?.text, 'ok'); }); /* TODO @@ -465,8 +474,8 @@ describe('Timelines', () => { const res = await api('notes/timeline', { limit: 100 }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true); - assert.strictEqual(res.body.find((note: any) => note.id === bobNote.id).text, 'ok'); + assert.strictEqual(res.body.some(note => note.id === bobNote.id), true); + assert.strictEqual(res.body.find(note => note.id === bobNote.id).text, 'ok'); }); */ @@ -481,7 +490,7 @@ describe('Timelines', () => { const res = await api('notes/timeline', { limit: 100 }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false); + assert.strictEqual(res.body.some(note => note.id === bobNote.id), false); }); }); @@ -496,8 +505,8 @@ describe('Timelines', () => { const res = await api('notes/local-timeline', { limit: 100 }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true); - assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false); + assert.strictEqual(res.body.some(note => note.id === bobNote.id), true); + assert.strictEqual(res.body.some(note => note.id === carolNote.id), false); }); test.concurrent('他人の他人への返信が含まれない', async () => { @@ -510,8 +519,8 @@ describe('Timelines', () => { const res = await api('notes/local-timeline', { limit: 100 }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false); - assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), true); + assert.strictEqual(res.body.some(note => note.id === bobNote.id), false); + assert.strictEqual(res.body.some(note => note.id === carolNote.id), true); }); test.concurrent('他人のその人自身への返信が含まれる', async () => { @@ -524,8 +533,8 @@ describe('Timelines', () => { const res = await api('notes/local-timeline', { limit: 100 }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote1.id), true); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote2.id), true); + assert.strictEqual(res.body.some(note => note.id === bobNote1.id), true); + assert.strictEqual(res.body.some(note => note.id === bobNote2.id), true); }); test.concurrent('チャンネル投稿が含まれない', async () => { @@ -538,7 +547,7 @@ describe('Timelines', () => { const res = await api('notes/local-timeline', { limit: 100 }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false); + assert.strictEqual(res.body.some(note => note.id === bobNote.id), false); }); test.concurrent('リモートユーザーのノートが含まれない', async () => { @@ -550,7 +559,7 @@ describe('Timelines', () => { const res = await api('notes/local-timeline', { limit: 100 }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false); + assert.strictEqual(res.body.some(note => note.id === bobNote.id), false); }); // 含まれても良いと思うけど実装が面倒なので含まれない @@ -558,7 +567,7 @@ describe('Timelines', () => { const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]); await api('following/create', { userId: carol.id }, alice); - await sleep(1000); + await setTimeout(1000); const carolNote = await post(carol, { text: 'hi', visibility: 'home' }); const bobNote = await post(bob, { text: 'hi' }); @@ -566,15 +575,15 @@ describe('Timelines', () => { const res = await api('notes/local-timeline', { limit: 100 }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true); - assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false); + assert.strictEqual(res.body.some(note => note.id === bobNote.id), true); + assert.strictEqual(res.body.some(note => note.id === carolNote.id), false); }); test.concurrent('ミュートしているユーザーのノートが含まれない', async () => { const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]); await api('mute/create', { userId: carol.id }, alice); - await sleep(1000); + await setTimeout(1000); const carolNote = await post(carol, { text: 'hi' }); const bobNote = await post(bob, { text: 'hi' }); @@ -582,8 +591,8 @@ describe('Timelines', () => { const res = await api('notes/local-timeline', { limit: 100 }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true); - assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false); + assert.strictEqual(res.body.some(note => note.id === bobNote.id), true); + assert.strictEqual(res.body.some(note => note.id === carolNote.id), false); }); test.concurrent('フォローしているユーザーが行ったミュートしているユーザーのリノートが含まれない', async () => { @@ -591,7 +600,7 @@ describe('Timelines', () => { await api('following/create', { userId: bob.id }, alice); await api('mute/create', { userId: carol.id }, alice); - await sleep(1000); + await setTimeout(1000); const carolNote = await post(carol, { text: 'hi' }); const bobNote = await post(bob, { text: 'hi', renoteId: carolNote.id }); @@ -599,8 +608,8 @@ describe('Timelines', () => { const res = await api('notes/local-timeline', { limit: 100 }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false); - assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false); + assert.strictEqual(res.body.some(note => note.id === bobNote.id), false); + assert.strictEqual(res.body.some(note => note.id === carolNote.id), false); }); test.concurrent('withReplies: true でフォローしているユーザーが行ったミュートしているユーザーの投稿への返信が含まれない', async () => { @@ -609,7 +618,7 @@ describe('Timelines', () => { await api('following/create', { userId: bob.id }, alice); await api('following/update', { userId: bob.id, withReplies: true }, alice); await api('mute/create', { userId: carol.id }, alice); - await sleep(1000); + await setTimeout(1000); const carolNote = await post(carol, { text: 'hi' }); const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id }); @@ -617,15 +626,15 @@ describe('Timelines', () => { const res = await api('notes/local-timeline', { limit: 100 }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false); - assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), false); + assert.strictEqual(res.body.some(note => note.id === bobNote.id), false); + assert.strictEqual(res.body.some(note => note.id === carolNote.id), false); }); test.concurrent('withReplies: false でフォローしているユーザーからの自分への返信が含まれる', async () => { const [alice, bob] = await Promise.all([signup(), signup()]); await api('following/create', { userId: bob.id }, alice); - await sleep(1000); + await setTimeout(1000); const aliceNote = await post(alice, { text: 'hi' }); const bobNote = await post(bob, { text: 'hi', replyId: aliceNote.id }); @@ -633,8 +642,8 @@ describe('Timelines', () => { const res = await api('notes/local-timeline', { limit: 100 }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === aliceNote.id), true); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true); + assert.strictEqual(res.body.some(note => note.id === aliceNote.id), true); + assert.strictEqual(res.body.some(note => note.id === bobNote.id), true); }); test.concurrent('[withReplies: true] 他人の他人への返信が含まれる', async () => { @@ -647,7 +656,7 @@ describe('Timelines', () => { const res = await api('notes/local-timeline', { limit: 100, withReplies: true }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true); + assert.strictEqual(res.body.some(note => note.id === bobNote.id), true); }); test.concurrent('[withFiles: true] ファイル付きノートのみ含まれる', async () => { @@ -661,9 +670,9 @@ describe('Timelines', () => { const res = await api('notes/local-timeline', { limit: 100, withFiles: true }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote1.id), false); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote2.id), true); - }, 1000 * 10); + assert.strictEqual(res.body.some(note => note.id === bobNote1.id), false); + assert.strictEqual(res.body.some(note => note.id === bobNote2.id), true); + }); }); describe('Social TL', () => { @@ -676,7 +685,7 @@ describe('Timelines', () => { const res = await api('notes/hybrid-timeline', { limit: 100 }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true); + assert.strictEqual(res.body.some(note => note.id === bobNote.id), true); }); test.concurrent('ローカルユーザーの visibility: home なノートが含まれない', async () => { @@ -688,28 +697,28 @@ describe('Timelines', () => { const res = await api('notes/hybrid-timeline', { limit: 100 }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false); + assert.strictEqual(res.body.some(note => note.id === bobNote.id), false); }); test.concurrent('フォローしているローカルユーザーの visibility: home なノートが含まれる', async () => { const [alice, bob] = await Promise.all([signup(), signup()]); await api('following/create', { userId: bob.id }, alice); - await sleep(1000); + await setTimeout(1000); const bobNote = await post(bob, { text: 'hi', visibility: 'home' }); await waitForPushToTl(); const res = await api('notes/hybrid-timeline', { limit: 100 }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true); + assert.strictEqual(res.body.some(note => note.id === bobNote.id), true); }); test.concurrent('withReplies: false でフォローしているユーザーからの自分への返信が含まれる', async () => { const [alice, bob] = await Promise.all([signup(), signup()]); await api('following/create', { userId: bob.id }, alice); - await sleep(1000); + await setTimeout(1000); const aliceNote = await post(alice, { text: 'hi' }); const bobNote = await post(bob, { text: 'hi', replyId: aliceNote.id }); @@ -717,8 +726,8 @@ describe('Timelines', () => { const res = await api('notes/hybrid-timeline', { limit: 100 }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === aliceNote.id), true); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true); + assert.strictEqual(res.body.some(note => note.id === aliceNote.id), true); + assert.strictEqual(res.body.some(note => note.id === bobNote.id), true); }); test.concurrent('他人の他人への返信が含まれない', async () => { @@ -731,8 +740,8 @@ describe('Timelines', () => { const res = await api('notes/hybrid-timeline', { limit: 100 }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false); - assert.strictEqual(res.body.some((note: any) => note.id === carolNote.id), true); + assert.strictEqual(res.body.some(note => note.id === bobNote.id), false); + assert.strictEqual(res.body.some(note => note.id === carolNote.id), true); }); test.concurrent('リモートユーザーのノートが含まれない', async () => { @@ -744,7 +753,7 @@ describe('Timelines', () => { const res = await api('notes/local-timeline', { limit: 100 }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false); + assert.strictEqual(res.body.some(note => note.id === bobNote.id), false); }); test.concurrent('フォローしているリモートユーザーのノートが含まれる', async () => { @@ -759,7 +768,7 @@ describe('Timelines', () => { const res = await api('notes/hybrid-timeline', { limit: 100 }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true); + assert.strictEqual(res.body.some(note => note.id === bobNote.id), true); }); test.concurrent('フォローしているリモートユーザーの visibility: home なノートが含まれる', async () => { @@ -774,7 +783,7 @@ describe('Timelines', () => { const res = await api('notes/hybrid-timeline', { limit: 100 }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true); + assert.strictEqual(res.body.some(note => note.id === bobNote.id), true); }); test.concurrent('[withReplies: true] 他人の他人への返信が含まれる', async () => { @@ -787,7 +796,7 @@ describe('Timelines', () => { const res = await api('notes/hybrid-timeline', { limit: 100, withReplies: true }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true); + assert.strictEqual(res.body.some(note => note.id === bobNote.id), true); }); test.concurrent('[withFiles: true] ファイル付きノートのみ含まれる', async () => { @@ -801,9 +810,9 @@ describe('Timelines', () => { const res = await api('notes/hybrid-timeline', { limit: 100, withFiles: true }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote1.id), false); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote2.id), true); - }, 1000 * 10); + assert.strictEqual(res.body.some(note => note.id === bobNote1.id), false); + assert.strictEqual(res.body.some(note => note.id === bobNote2.id), true); + }); }); describe('User List TL', () => { @@ -812,14 +821,14 @@ describe('Timelines', () => { const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body); await api('users/lists/push', { listId: list.id, userId: bob.id }, alice); - await sleep(1000); + await setTimeout(1000); const bobNote = await post(bob, { text: 'hi' }); await waitForPushToTl(); const res = await api('notes/user-list-timeline', { listId: list.id }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true); + assert.strictEqual(res.body.some(note => note.id === bobNote.id), true); }); test.concurrent('リスインしているフォローしていないユーザーの visibility: home なノートが含まれる', async () => { @@ -827,14 +836,14 @@ describe('Timelines', () => { const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body); await api('users/lists/push', { listId: list.id, userId: bob.id }, alice); - await sleep(1000); + await setTimeout(1000); const bobNote = await post(bob, { text: 'hi', visibility: 'home' }); await waitForPushToTl(); const res = await api('notes/user-list-timeline', { listId: list.id }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true); + assert.strictEqual(res.body.some(note => note.id === bobNote.id), true); }); test.concurrent('リスインしているフォローしていないユーザーの visibility: followers なノートが含まれない', async () => { @@ -842,14 +851,14 @@ describe('Timelines', () => { const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body); await api('users/lists/push', { listId: list.id, userId: bob.id }, alice); - await sleep(1000); + await setTimeout(1000); const bobNote = await post(bob, { text: 'hi', visibility: 'followers' }); await waitForPushToTl(); const res = await api('notes/user-list-timeline', { listId: list.id }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false); + assert.strictEqual(res.body.some(note => note.id === bobNote.id), false); }); test.concurrent('リスインしているフォローしていないユーザーの他人への返信が含まれない', async () => { @@ -857,7 +866,7 @@ describe('Timelines', () => { const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body); await api('users/lists/push', { listId: list.id, userId: bob.id }, alice); - await sleep(1000); + await setTimeout(1000); const carolNote = await post(carol, { text: 'hi' }); const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id }); @@ -865,7 +874,7 @@ describe('Timelines', () => { const res = await api('notes/user-list-timeline', { listId: list.id }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false); + assert.strictEqual(res.body.some(note => note.id === bobNote.id), false); }); test.concurrent('リスインしているフォローしていないユーザーのユーザー自身への返信が含まれる', async () => { @@ -873,7 +882,7 @@ describe('Timelines', () => { const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body); await api('users/lists/push', { listId: list.id, userId: bob.id }, alice); - await sleep(1000); + await setTimeout(1000); const bobNote1 = await post(bob, { text: 'hi' }); const bobNote2 = await post(bob, { text: 'hi', replyId: bobNote1.id }); @@ -881,8 +890,8 @@ describe('Timelines', () => { const res = await api('notes/user-list-timeline', { listId: list.id }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote1.id), true); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote2.id), true); + assert.strictEqual(res.body.some(note => note.id === bobNote1.id), true); + assert.strictEqual(res.body.some(note => note.id === bobNote2.id), true); }); test.concurrent('withReplies: false でリスインしているフォローしていないユーザーからの自分への返信が含まれる', async () => { @@ -891,7 +900,7 @@ describe('Timelines', () => { const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body); await api('users/lists/push', { listId: list.id, userId: bob.id }, alice); await api('users/lists/update-membership', { listId: list.id, userId: bob.id, withReplies: false }, alice); - await sleep(1000); + await setTimeout(1000); const aliceNote = await post(alice, { text: 'hi' }); const bobNote = await post(bob, { text: 'hi', replyId: aliceNote.id }); @@ -899,7 +908,7 @@ describe('Timelines', () => { const res = await api('notes/user-list-timeline', { listId: list.id }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true); + assert.strictEqual(res.body.some(note => note.id === bobNote.id), true); }); test.concurrent('withReplies: false でリスインしているフォローしていないユーザーの他人への返信が含まれない', async () => { @@ -908,7 +917,7 @@ describe('Timelines', () => { const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body); await api('users/lists/push', { listId: list.id, userId: bob.id }, alice); await api('users/lists/update-membership', { listId: list.id, userId: bob.id, withReplies: false }, alice); - await sleep(1000); + await setTimeout(1000); const carolNote = await post(carol, { text: 'hi' }); const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id }); @@ -916,7 +925,7 @@ describe('Timelines', () => { const res = await api('notes/user-list-timeline', { listId: list.id }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false); + assert.strictEqual(res.body.some(note => note.id === bobNote.id), false); }); test.concurrent('withReplies: true でリスインしているフォローしていないユーザーの他人への返信が含まれる', async () => { @@ -925,7 +934,7 @@ describe('Timelines', () => { const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body); await api('users/lists/push', { listId: list.id, userId: bob.id }, alice); await api('users/lists/update-membership', { listId: list.id, userId: bob.id, withReplies: true }, alice); - await sleep(1000); + await setTimeout(1000); const carolNote = await post(carol, { text: 'hi' }); const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id }); @@ -933,7 +942,7 @@ describe('Timelines', () => { const res = await api('notes/user-list-timeline', { listId: list.id }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true); + assert.strictEqual(res.body.some(note => note.id === bobNote.id), true); }); test.concurrent('リスインしているフォローしているユーザーの visibility: home なノートが含まれる', async () => { @@ -942,14 +951,14 @@ describe('Timelines', () => { await api('following/create', { userId: bob.id }, alice); const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body); await api('users/lists/push', { listId: list.id, userId: bob.id }, alice); - await sleep(1000); + await setTimeout(1000); const bobNote = await post(bob, { text: 'hi', visibility: 'home' }); await waitForPushToTl(); const res = await api('notes/user-list-timeline', { listId: list.id }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true); + assert.strictEqual(res.body.some(note => note.id === bobNote.id), true); }); test.concurrent('リスインしているフォローしているユーザーの visibility: followers なノートが含まれる', async () => { @@ -958,15 +967,15 @@ describe('Timelines', () => { await api('following/create', { userId: bob.id }, alice); const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body); await api('users/lists/push', { listId: list.id, userId: bob.id }, alice); - await sleep(1000); + await setTimeout(1000); const bobNote = await post(bob, { text: 'hi', visibility: 'followers' }); await waitForPushToTl(); const res = await api('notes/user-list-timeline', { listId: list.id }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true); - assert.strictEqual(res.body.find((note: any) => note.id === bobNote.id).text, 'hi'); + assert.strictEqual(res.body.some(note => note.id === bobNote.id), true); + assert.strictEqual(res.body.find(note => note.id === bobNote.id)?.text, 'hi'); }); test.concurrent('リスインしている自分の visibility: followers なノートが含まれる', async () => { @@ -974,15 +983,15 @@ describe('Timelines', () => { const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body); await api('users/lists/push', { listId: list.id, userId: alice.id }, alice); - await sleep(1000); + await setTimeout(1000); const aliceNote = await post(alice, { text: 'hi', visibility: 'followers' }); await waitForPushToTl(); const res = await api('notes/user-list-timeline', { listId: list.id }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === aliceNote.id), true); - assert.strictEqual(res.body.find((note: any) => note.id === aliceNote.id).text, 'hi'); + assert.strictEqual(res.body.some(note => note.id === aliceNote.id), true); + assert.strictEqual(res.body.find(note => note.id === aliceNote.id)?.text, 'hi'); }); test.concurrent('リスインしているユーザーのチャンネルノートが含まれない', async () => { @@ -991,14 +1000,14 @@ describe('Timelines', () => { const channel = await api('channels/create', { name: 'channel' }, bob).then(x => x.body); const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body); await api('users/lists/push', { listId: list.id, userId: bob.id }, alice); - await sleep(1000); + await setTimeout(1000); const bobNote = await post(bob, { text: 'hi', channelId: channel.id }); await waitForPushToTl(); const res = await api('notes/user-list-timeline', { listId: list.id }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false); + assert.strictEqual(res.body.some(note => note.id === bobNote.id), false); }); test.concurrent('[withFiles: true] リスインしているユーザーのファイル付きノートのみ含まれる', async () => { @@ -1014,24 +1023,24 @@ describe('Timelines', () => { const res = await api('notes/user-list-timeline', { listId: list.id, withFiles: true }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote1.id), false); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote2.id), true); - }, 1000 * 10); + assert.strictEqual(res.body.some(note => note.id === bobNote1.id), false); + assert.strictEqual(res.body.some(note => note.id === bobNote2.id), true); + }); test.concurrent('リスインしているユーザーの自身宛ての visibility: specified なノートが含まれる', async () => { const [alice, bob] = await Promise.all([signup(), signup()]); const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body); await api('users/lists/push', { listId: list.id, userId: bob.id }, alice); - await sleep(1000); + await setTimeout(1000); const bobNote = await post(bob, { text: 'hi', visibility: 'specified', visibleUserIds: [alice.id] }); await waitForPushToTl(); const res = await api('notes/user-list-timeline', { listId: list.id }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true); - assert.strictEqual(res.body.find((note: any) => note.id === bobNote.id).text, 'hi'); + assert.strictEqual(res.body.some(note => note.id === bobNote.id), true); + assert.strictEqual(res.body.find(note => note.id === bobNote.id)?.text, 'hi'); }); test.concurrent('リスインしているユーザーの自身宛てではない visibility: specified なノートが含まれない', async () => { @@ -1040,14 +1049,14 @@ describe('Timelines', () => { const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body); await api('users/lists/push', { listId: list.id, userId: bob.id }, alice); await api('users/lists/push', { listId: list.id, userId: carol.id }, alice); - await sleep(1000); + await setTimeout(1000); const bobNote = await post(bob, { text: 'hi', visibility: 'specified', visibleUserIds: [carol.id] }); await waitForPushToTl(); const res = await api('notes/user-list-timeline', { listId: list.id }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false); + assert.strictEqual(res.body.some(note => note.id === bobNote.id), false); }); }); @@ -1061,7 +1070,7 @@ describe('Timelines', () => { const res = await api('users/notes', { userId: bob.id }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true); + assert.strictEqual(res.body.some(note => note.id === bobNote.id), true); }); test.concurrent('フォローしていないユーザーの visibility: followers なノートが含まれない', async () => { @@ -1073,22 +1082,22 @@ describe('Timelines', () => { const res = await api('users/notes', { userId: bob.id }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false); + assert.strictEqual(res.body.some(note => note.id === bobNote.id), false); }); test.concurrent('フォローしているユーザーの visibility: followers なノートが含まれる', async () => { const [alice, bob] = await Promise.all([signup(), signup()]); await api('following/create', { userId: bob.id }, alice); - await sleep(1000); + await setTimeout(1000); const bobNote = await post(bob, { text: 'hi', visibility: 'followers' }); await waitForPushToTl(); const res = await api('users/notes', { userId: bob.id }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true); - assert.strictEqual(res.body.find((note: any) => note.id === bobNote.id).text, 'hi'); + assert.strictEqual(res.body.some(note => note.id === bobNote.id), true); + assert.strictEqual(res.body.find(note => note.id === bobNote.id)?.text, 'hi'); }); test.concurrent('自身の visibility: followers なノートが含まれる', async () => { @@ -1100,8 +1109,8 @@ describe('Timelines', () => { const res = await api('users/notes', { userId: alice.id }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === aliceNote.id), true); - assert.strictEqual(res.body.find((note: any) => note.id === aliceNote.id).text, 'hi'); + assert.strictEqual(res.body.some(note => note.id === aliceNote.id), true); + assert.strictEqual(res.body.find(note => note.id === aliceNote.id)?.text, 'hi'); }); test.concurrent('チャンネル投稿が含まれない', async () => { @@ -1114,7 +1123,7 @@ describe('Timelines', () => { const res = await api('users/notes', { userId: bob.id }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false); + assert.strictEqual(res.body.some(note => note.id === bobNote.id), false); }); test.concurrent('[withReplies: false] 他人への返信が含まれない', async () => { @@ -1128,8 +1137,8 @@ describe('Timelines', () => { const res = await api('users/notes', { userId: bob.id }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote1.id), true); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote2.id), false); + assert.strictEqual(res.body.some(note => note.id === bobNote1.id), true); + assert.strictEqual(res.body.some(note => note.id === bobNote2.id), false); }); test.concurrent('[withReplies: true] 他人への返信が含まれる', async () => { @@ -1143,8 +1152,8 @@ describe('Timelines', () => { const res = await api('users/notes', { userId: bob.id, withReplies: true }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote1.id), true); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote2.id), true); + assert.strictEqual(res.body.some(note => note.id === bobNote1.id), true); + assert.strictEqual(res.body.some(note => note.id === bobNote2.id), true); }); test.concurrent('[withReplies: true] 他人への visibility: specified な返信が含まれない', async () => { @@ -1158,8 +1167,8 @@ describe('Timelines', () => { const res = await api('users/notes', { userId: bob.id, withReplies: true }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote1.id), true); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote2.id), false); + assert.strictEqual(res.body.some(note => note.id === bobNote1.id), true); + assert.strictEqual(res.body.some(note => note.id === bobNote2.id), false); }); test.concurrent('[withFiles: true] ファイル付きノートのみ含まれる', async () => { @@ -1173,9 +1182,9 @@ describe('Timelines', () => { const res = await api('users/notes', { userId: bob.id, withFiles: true }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote1.id), false); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote2.id), true); - }, 1000 * 10); + assert.strictEqual(res.body.some(note => note.id === bobNote1.id), false); + assert.strictEqual(res.body.some(note => note.id === bobNote2.id), true); + }); test.concurrent('[withChannelNotes: true] チャンネル投稿が含まれる', async () => { const [alice, bob] = await Promise.all([signup(), signup()]); @@ -1187,7 +1196,7 @@ describe('Timelines', () => { const res = await api('users/notes', { userId: bob.id, withChannelNotes: true }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true); + assert.strictEqual(res.body.some(note => note.id === bobNote.id), true); }); test.concurrent('[withChannelNotes: true] 他人が取得した場合センシティブチャンネル投稿が含まれない', async () => { @@ -1200,7 +1209,7 @@ describe('Timelines', () => { const res = await api('users/notes', { userId: bob.id, withChannelNotes: true }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false); + assert.strictEqual(res.body.some(note => note.id === bobNote.id), false); }); test.concurrent('[withChannelNotes: true] 自分が取得した場合センシティブチャンネル投稿が含まれる', async () => { @@ -1213,14 +1222,14 @@ describe('Timelines', () => { const res = await api('users/notes', { userId: bob.id, withChannelNotes: true }, bob); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true); + assert.strictEqual(res.body.some(note => note.id === bobNote.id), true); }); test.concurrent('ミュートしているユーザーに関連する投稿が含まれない', async () => { const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]); await api('mute/create', { userId: carol.id }, alice); - await sleep(1000); + await setTimeout(1000); const carolNote = await post(carol, { text: 'hi' }); const bobNote = await post(bob, { text: 'hi', renoteId: carolNote.id }); @@ -1228,14 +1237,14 @@ describe('Timelines', () => { const res = await api('users/notes', { userId: bob.id }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false); + assert.strictEqual(res.body.some(note => note.id === bobNote.id), false); }); test.concurrent('ミュートしていても userId に指定したユーザーの投稿が含まれる', async () => { const [alice, bob] = await Promise.all([signup(), signup()]); await api('mute/create', { userId: bob.id }, alice); - await sleep(1000); + await setTimeout(1000); const bobNote1 = await post(bob, { text: 'hi' }); const bobNote2 = await post(bob, { text: 'hi', replyId: bobNote1.id }); const bobNote3 = await post(bob, { text: 'hi', renoteId: bobNote1.id }); @@ -1244,9 +1253,9 @@ describe('Timelines', () => { const res = await api('users/notes', { userId: bob.id }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote1.id), true); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote2.id), true); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote3.id), true); + assert.strictEqual(res.body.some(note => note.id === bobNote1.id), true); + assert.strictEqual(res.body.some(note => note.id === bobNote2.id), true); + assert.strictEqual(res.body.some(note => note.id === bobNote3.id), true); }); test.concurrent('自身の visibility: specified なノートが含まれる', async () => { @@ -1258,7 +1267,7 @@ describe('Timelines', () => { const res = await api('users/notes', { userId: alice.id, withReplies: true }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === aliceNote.id), true); + assert.strictEqual(res.body.some(note => note.id === aliceNote.id), true); }); test.concurrent('visibleUserIds に指定されてない visibility: specified なノートが含まれない', async () => { @@ -1270,7 +1279,34 @@ describe('Timelines', () => { const res = await api('users/notes', { userId: bob.id, withReplies: true }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false); + assert.strictEqual(res.body.some(note => note.id === bobNote.id), false); + }); + + /** @see https://github.com/misskey-dev/misskey/issues/14000 */ + test.concurrent('FTT: sinceId にキャッシュより古いノートを指定しても、sinceId による絞り込みが正しく動作する', async () => { + const alice = await signup(); + const noteSince = await post(alice, { text: 'Note where id will be `sinceId`.' }); + const note1 = await post(alice, { text: '1' }); + const note2 = await post(alice, { text: '2' }); + await redisForTimelines.del('list:userTimeline:' + alice.id); + const note3 = await post(alice, { text: '3' }); + + const res = await api('users/notes', { userId: alice.id, sinceId: noteSince.id }); + assert.deepStrictEqual(res.body, [note1, note2, note3]); + }); + + test.concurrent('FTT: sinceId にキャッシュより古いノートを指定しても、sinceId と untilId による絞り込みが正しく動作する', async () => { + const alice = await signup(); + const noteSince = await post(alice, { text: 'Note where id will be `sinceId`.' }); + const note1 = await post(alice, { text: '1' }); + const note2 = await post(alice, { text: '2' }); + await redisForTimelines.del('list:userTimeline:' + alice.id); + const note3 = await post(alice, { text: '3' }); + const noteUntil = await post(alice, { text: 'Note where id will be `untilId`.' }); + await post(alice, { text: '4' }); + + const res = await api('users/notes', { userId: alice.id, sinceId: noteSince.id, untilId: noteUntil.id }); + assert.deepStrictEqual(res.body, [note3, note2, note1]); }); }); diff --git a/packages/backend/test/e2e/user-notes.ts b/packages/backend/test/e2e/user-notes.ts index 331e053935..cc07c5ae71 100644 --- a/packages/backend/test/e2e/user-notes.ts +++ b/packages/backend/test/e2e/user-notes.ts @@ -17,8 +17,8 @@ describe('users/notes', () => { beforeAll(async () => { alice = await signup({ username: 'alice' }); - const jpg = await uploadUrl(alice, 'https://raw.githubusercontent.com/misskey-dev/misskey/develop/packages/backend/test/resources/Lenna.jpg'); - const png = await uploadUrl(alice, 'https://raw.githubusercontent.com/misskey-dev/misskey/develop/packages/backend/test/resources/Lenna.png'); + const jpg = await uploadUrl(alice, 'https://raw.githubusercontent.com/misskey-dev/misskey/develop/packages/backend/test/resources/192.jpg'); + const png = await uploadUrl(alice, 'https://raw.githubusercontent.com/misskey-dev/misskey/develop/packages/backend/test/resources/192.png'); jpgNote = await post(alice, { fileIds: [jpg.id], }); diff --git a/packages/backend/test/e2e/users.ts b/packages/backend/test/e2e/users.ts index 3458e06384..61fd759932 100644 --- a/packages/backend/test/e2e/users.ts +++ b/packages/backend/test/e2e/users.ts @@ -231,7 +231,7 @@ describe('ユーザー', () => { rolePublic = await role(root, { isPublic: true, name: 'Public Role' }); await api('admin/roles/assign', { userId: userRolePublic.id, roleId: rolePublic.id }, root); userRoleBadge = await signup({ username: 'userRoleBadge' }); - roleBadge = await role(root, { asBadge: true, name: 'Badge Role' }); + roleBadge = await role(root, { asBadge: true, name: 'Badge Role', isPublic: true }); await api('admin/roles/assign', { userId: userRoleBadge.id, roleId: roleBadge.id }, root); userSilenced = await signup({ username: 'userSilenced' }); await post(userSilenced, { text: 'test' }); @@ -655,7 +655,16 @@ describe('ユーザー', () => { iconUrl: roleBadge.iconUrl, displayOrder: roleBadge.displayOrder, }]); - assert.deepStrictEqual(response.roles, []); // バッヂだからといってrolesが取れるとは限らない + assert.deepStrictEqual(response.roles, [{ + id: roleBadge.id, + name: roleBadge.name, + color: roleBadge.color, + iconUrl: roleBadge.iconUrl, + description: roleBadge.description, + isModerator: roleBadge.isModerator, + isAdministrator: roleBadge.isAdministrator, + displayOrder: roleBadge.displayOrder, + }]); }); test('をID指定のリスト形式で取得することができる(空)', async () => { const parameters = { userIds: [] }; diff --git a/packages/backend/test/eslint.config.js b/packages/backend/test/eslint.config.js new file mode 100644 index 0000000000..a0f43babad --- /dev/null +++ b/packages/backend/test/eslint.config.js @@ -0,0 +1,22 @@ +import globals from 'globals'; +import tsParser from '@typescript-eslint/parser'; +import sharedConfig from '../../shared/eslint.config.js'; + +export default [ + ...sharedConfig, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + globals: { + ...globals.node, + ...globals.jest, + }, + parserOptions: { + parser: tsParser, + project: ['./tsconfig.json'], + sourceType: 'module', + tsconfigRootDir: import.meta.dirname, + }, + }, + }, +]; diff --git a/packages/backend/test/misc/mock-resolver.ts b/packages/backend/test/misc/mock-resolver.ts index 3c7e796700..485506ee64 100644 --- a/packages/backend/test/misc/mock-resolver.ts +++ b/packages/backend/test/misc/mock-resolver.ts @@ -14,6 +14,7 @@ import type { InstanceActorService } from '@/core/InstanceActorService.js'; import type { LoggerService } from '@/core/LoggerService.js'; import type { MetaService } from '@/core/MetaService.js'; import type { UtilityService } from '@/core/UtilityService.js'; +import type { FederatedInstanceService } from '@/core/FederatedInstanceService.js'; import { bindThis } from '@/decorators.js'; import type { FollowRequestsRepository, @@ -47,6 +48,7 @@ export class MockResolver extends Resolver { {} as HttpRequestService, {} as ApRendererService, {} as ApDbResolverService, + {} as FederatedInstanceService, loggerService, ); } diff --git a/packages/backend/test/prelude/maybe.ts b/packages/backend/test/prelude/maybe.ts deleted file mode 100644 index 16e92216d4..0000000000 --- a/packages/backend/test/prelude/maybe.ts +++ /dev/null @@ -1,23 +0,0 @@ -/* - * SPDX-FileCopyrightText: syuilo and misskey-project - * SPDX-License-Identifier: AGPL-3.0-only - */ - -import * as assert from 'assert'; -import { just, nothing } from '../../src/misc/prelude/maybe.js'; - -describe('just', () => { - test('has a value', () => { - assert.deepStrictEqual(just(3).isJust(), true); - }); - - test('has the inverse called get', () => { - assert.deepStrictEqual(just(3).get(), 3); - }); -}); - -describe('nothing', () => { - test('has no value', () => { - assert.deepStrictEqual(nothing().isJust(), false); - }); -}); diff --git a/packages/backend/test/resources/192.jpg b/packages/backend/test/resources/192.jpg new file mode 100644 index 0000000000..76374628e0 Binary files /dev/null and b/packages/backend/test/resources/192.jpg differ diff --git a/packages/backend/test/resources/192.png b/packages/backend/test/resources/192.png new file mode 100644 index 0000000000..15fd1e3731 Binary files /dev/null and b/packages/backend/test/resources/192.png differ diff --git a/packages/backend/test/resources/Lenna.jpg b/packages/backend/test/resources/Lenna.jpg deleted file mode 100644 index 6b5b32281c..0000000000 Binary files a/packages/backend/test/resources/Lenna.jpg and /dev/null differ diff --git a/packages/backend/test/resources/Lenna.png b/packages/backend/test/resources/Lenna.png deleted file mode 100644 index 59ef68aabd..0000000000 Binary files a/packages/backend/test/resources/Lenna.png and /dev/null differ diff --git a/packages/backend/test/unit/AbuseReportNotificationService.ts b/packages/backend/test/unit/AbuseReportNotificationService.ts new file mode 100644 index 0000000000..e971659070 --- /dev/null +++ b/packages/backend/test/unit/AbuseReportNotificationService.ts @@ -0,0 +1,343 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { jest } from '@jest/globals'; +import { Test, TestingModule } from '@nestjs/testing'; +import { AbuseReportNotificationService } from '@/core/AbuseReportNotificationService.js'; +import { + AbuseReportNotificationRecipientRepository, + MiAbuseReportNotificationRecipient, + MiSystemWebhook, + MiUser, + SystemWebhooksRepository, + UserProfilesRepository, + UsersRepository, +} from '@/models/_.js'; +import { DI } from '@/di-symbols.js'; +import { GlobalModule } from '@/GlobalModule.js'; +import { IdService } from '@/core/IdService.js'; +import { EmailService } from '@/core/EmailService.js'; +import { RoleService } from '@/core/RoleService.js'; +import { MetaService } from '@/core/MetaService.js'; +import { ModerationLogService } from '@/core/ModerationLogService.js'; +import { GlobalEventService } from '@/core/GlobalEventService.js'; +import { RecipientMethod } from '@/models/AbuseReportNotificationRecipient.js'; +import { SystemWebhookService } from '@/core/SystemWebhookService.js'; +import { randomString } from '../utils.js'; + +process.env.NODE_ENV = 'test'; + +describe('AbuseReportNotificationService', () => { + let app: TestingModule; + let service: AbuseReportNotificationService; + + // -------------------------------------------------------------------------------------- + + let usersRepository: UsersRepository; + let userProfilesRepository: UserProfilesRepository; + let systemWebhooksRepository: SystemWebhooksRepository; + let abuseReportNotificationRecipientRepository: AbuseReportNotificationRecipientRepository; + let idService: IdService; + let roleService: jest.Mocked; + let emailService: jest.Mocked; + let webhookService: jest.Mocked; + + // -------------------------------------------------------------------------------------- + + let root: MiUser; + let alice: MiUser; + let bob: MiUser; + let systemWebhook1: MiSystemWebhook; + let systemWebhook2: MiSystemWebhook; + + // -------------------------------------------------------------------------------------- + + async function createUser(data: Partial = {}) { + const user = await usersRepository + .insert({ + id: idService.gen(), + ...data, + }) + .then(x => usersRepository.findOneByOrFail(x.identifiers[0])); + + await userProfilesRepository.insert({ + userId: user.id, + }); + + return user; + } + + async function createWebhook(data: Partial = {}) { + return systemWebhooksRepository + .insert({ + id: idService.gen(), + name: randomString(), + on: ['abuseReport'], + url: 'https://example.com', + secret: randomString(), + ...data, + }) + .then(x => systemWebhooksRepository.findOneByOrFail(x.identifiers[0])); + } + + async function createRecipient(data: Partial = {}) { + return abuseReportNotificationRecipientRepository + .insert({ + id: idService.gen(), + isActive: true, + name: randomString(), + ...data, + }) + .then(x => abuseReportNotificationRecipientRepository.findOneByOrFail(x.identifiers[0])); + } + + // -------------------------------------------------------------------------------------- + + beforeAll(async () => { + app = await Test + .createTestingModule({ + imports: [ + GlobalModule, + ], + providers: [ + AbuseReportNotificationService, + IdService, + { + provide: RoleService, useFactory: () => ({ getModeratorIds: jest.fn() }), + }, + { + provide: SystemWebhookService, useFactory: () => ({ enqueueSystemWebhook: jest.fn() }), + }, + { + provide: EmailService, useFactory: () => ({ sendEmail: jest.fn() }), + }, + { + provide: MetaService, useFactory: () => ({ fetch: jest.fn() }), + }, + { + provide: ModerationLogService, useFactory: () => ({ log: () => Promise.resolve() }), + }, + { + provide: GlobalEventService, useFactory: () => ({ publishAdminStream: jest.fn() }), + }, + ], + }) + .compile(); + + usersRepository = app.get(DI.usersRepository); + userProfilesRepository = app.get(DI.userProfilesRepository); + systemWebhooksRepository = app.get(DI.systemWebhooksRepository); + abuseReportNotificationRecipientRepository = app.get(DI.abuseReportNotificationRecipientRepository); + + service = app.get(AbuseReportNotificationService); + idService = app.get(IdService); + roleService = app.get(RoleService) as jest.Mocked; + emailService = app.get(EmailService) as jest.Mocked; + webhookService = app.get(SystemWebhookService) as jest.Mocked; + + app.enableShutdownHooks(); + }); + + beforeEach(async () => { + root = await createUser({ username: 'root', usernameLower: 'root', isRoot: true }); + alice = await createUser({ username: 'alice', usernameLower: 'alice', isRoot: false }); + bob = await createUser({ username: 'bob', usernameLower: 'bob', isRoot: false }); + systemWebhook1 = await createWebhook(); + systemWebhook2 = await createWebhook(); + + roleService.getModeratorIds.mockResolvedValue([root.id, alice.id, bob.id]); + }); + + afterEach(async () => { + emailService.sendEmail.mockClear(); + webhookService.enqueueSystemWebhook.mockClear(); + + await usersRepository.delete({}); + await userProfilesRepository.delete({}); + await systemWebhooksRepository.delete({}); + await abuseReportNotificationRecipientRepository.delete({}); + }); + + afterAll(async () => { + await app.close(); + }); + + // -------------------------------------------------------------------------------------- + + describe('createRecipient', () => { + test('作成成功1', async () => { + const params = { + isActive: true, + name: randomString(), + method: 'email' as RecipientMethod, + userId: alice.id, + systemWebhookId: null, + }; + + const recipient1 = await service.createRecipient(params, root); + expect(recipient1).toMatchObject(params); + }); + + test('作成成功2', async () => { + const params = { + isActive: true, + name: randomString(), + method: 'webhook' as RecipientMethod, + userId: null, + systemWebhookId: systemWebhook1.id, + }; + + const recipient1 = await service.createRecipient(params, root); + expect(recipient1).toMatchObject(params); + }); + }); + + describe('updateRecipient', () => { + test('更新成功1', async () => { + const recipient1 = await createRecipient({ + method: 'email', + userId: alice.id, + }); + + const params = { + id: recipient1.id, + isActive: false, + name: randomString(), + method: 'email' as RecipientMethod, + userId: bob.id, + systemWebhookId: null, + }; + + const recipient2 = await service.updateRecipient(params, root); + expect(recipient2).toMatchObject(params); + }); + + test('更新成功2', async () => { + const recipient1 = await createRecipient({ + method: 'webhook', + systemWebhookId: systemWebhook1.id, + }); + + const params = { + id: recipient1.id, + isActive: false, + name: randomString(), + method: 'webhook' as RecipientMethod, + userId: null, + systemWebhookId: systemWebhook2.id, + }; + + const recipient2 = await service.updateRecipient(params, root); + expect(recipient2).toMatchObject(params); + }); + }); + + describe('deleteRecipient', () => { + test('削除成功1', async () => { + const recipient1 = await createRecipient({ + method: 'email', + userId: alice.id, + }); + + await service.deleteRecipient(recipient1.id, root); + + await expect(abuseReportNotificationRecipientRepository.findOneBy({ id: recipient1.id })).resolves.toBeNull(); + }); + }); + + describe('fetchRecipients', () => { + async function create() { + const recipient1 = await createRecipient({ + method: 'email', + userId: alice.id, + }); + const recipient2 = await createRecipient({ + method: 'email', + userId: bob.id, + }); + + const recipient3 = await createRecipient({ + method: 'webhook', + systemWebhookId: systemWebhook1.id, + }); + const recipient4 = await createRecipient({ + method: 'webhook', + systemWebhookId: systemWebhook2.id, + }); + + return [recipient1, recipient2, recipient3, recipient4]; + } + + test('フィルタなし', async () => { + const [recipient1, recipient2, recipient3, recipient4] = await create(); + + const recipients = await service.fetchRecipients({}); + expect(recipients).toEqual([recipient1, recipient2, recipient3, recipient4]); + }); + + test('フィルタなし(非モデレータは除外される)', async () => { + roleService.getModeratorIds.mockClear(); + roleService.getModeratorIds.mockResolvedValue([root.id, bob.id]); + + const [recipient1, recipient2, recipient3, recipient4] = await create(); + + const recipients = await service.fetchRecipients({}); + // aliceはモデレータではないので除外される + expect(recipients).toEqual([recipient2, recipient3, recipient4]); + }); + + test('フィルタなし(非モデレータでも除外されないオプション設定)', async () => { + roleService.getModeratorIds.mockClear(); + roleService.getModeratorIds.mockResolvedValue([root.id, bob.id]); + + const [recipient1, recipient2, recipient3, recipient4] = await create(); + + const recipients = await service.fetchRecipients({}, { removeUnauthorized: false }); + expect(recipients).toEqual([recipient1, recipient2, recipient3, recipient4]); + }); + + test('emailのみ', async () => { + const [recipient1, recipient2, recipient3, recipient4] = await create(); + + const recipients = await service.fetchRecipients({ method: ['email'] }); + expect(recipients).toEqual([recipient1, recipient2]); + }); + + test('webhookのみ', async () => { + const [recipient1, recipient2, recipient3, recipient4] = await create(); + + const recipients = await service.fetchRecipients({ method: ['webhook'] }); + expect(recipients).toEqual([recipient3, recipient4]); + }); + + test('すべて', async () => { + const [recipient1, recipient2, recipient3, recipient4] = await create(); + + const recipients = await service.fetchRecipients({ method: ['email', 'webhook'] }); + expect(recipients).toEqual([recipient1, recipient2, recipient3, recipient4]); + }); + + test('ID指定', async () => { + const [recipient1, recipient2, recipient3, recipient4] = await create(); + + const recipients = await service.fetchRecipients({ ids: [recipient1.id, recipient3.id] }); + expect(recipients).toEqual([recipient1, recipient3]); + }); + + test('ID指定(method=emailではないIDが混ざりこまない)', async () => { + const [recipient1, recipient2, recipient3, recipient4] = await create(); + + const recipients = await service.fetchRecipients({ ids: [recipient1.id, recipient3.id], method: ['email'] }); + expect(recipients).toEqual([recipient1]); + }); + + test('ID指定(method=webhookではないIDが混ざりこまない)', async () => { + const [recipient1, recipient2, recipient3, recipient4] = await create(); + + const recipients = await service.fetchRecipients({ ids: [recipient1.id, recipient3.id], method: ['webhook'] }); + expect(recipients).toEqual([recipient3]); + }); + }); +}); diff --git a/packages/backend/test/unit/ApMfmService.ts b/packages/backend/test/unit/ApMfmService.ts index 79cb81f5c9..e81a321c9b 100644 --- a/packages/backend/test/unit/ApMfmService.ts +++ b/packages/backend/test/unit/ApMfmService.ts @@ -23,10 +23,10 @@ describe('ApMfmService', () => { describe('getNoteHtml', () => { test('Do not provide _misskey_content for simple text', () => { - const note: MiNote = { + const note = { text: 'テキスト #タグ @mention 🍊 :emoji: https://example.com', mentionedRemoteUsers: '[]', - } as any; + }; const { content, noMisskeyContent } = apMfmService.getNoteHtml(note); @@ -35,10 +35,10 @@ describe('ApMfmService', () => { }); test('Provide _misskey_content for MFM', () => { - const note: MiNote = { + const note = { text: '$[tada foo]', mentionedRemoteUsers: '[]', - } as any; + }; const { content, noMisskeyContent } = apMfmService.getNoteHtml(note); diff --git a/packages/backend/test/unit/FetchInstanceMetadataService.ts b/packages/backend/test/unit/FetchInstanceMetadataService.ts index bf8f3ab0e3..2e66b81fcd 100644 --- a/packages/backend/test/unit/FetchInstanceMetadataService.ts +++ b/packages/backend/test/unit/FetchInstanceMetadataService.ts @@ -75,62 +75,61 @@ describe('FetchInstanceMetadataService', () => { test('Lock and update', async () => { redisClient.set = mockRedis(); const now = Date.now(); - federatedInstanceService.fetch.mockResolvedValue({ infoUpdatedAt: { getTime: () => { return now - 10 * 1000 * 60 * 60 * 24; } } } as any); + federatedInstanceService.fetch.mockResolvedValue({ infoUpdatedAt: new Date(now - 10 * 1000 * 60 * 60 * 24) } as any); httpRequestService.getJson.mockImplementation(() => { throw Error(); }); const tryLockSpy = jest.spyOn(fetchInstanceMetadataService, 'tryLock'); const unlockSpy = jest.spyOn(fetchInstanceMetadataService, 'unlock'); await fetchInstanceMetadataService.fetchInstanceMetadata({ host: 'example.com' } as any); + expect(federatedInstanceService.fetch).toHaveBeenCalledTimes(1); expect(tryLockSpy).toHaveBeenCalledTimes(1); expect(unlockSpy).toHaveBeenCalledTimes(1); - expect(federatedInstanceService.fetch).toHaveBeenCalledTimes(1); expect(httpRequestService.getJson).toHaveBeenCalled(); }); - test('Lock and don\'t update', async () => { + test('Don\'t lock and update if recently updated', async () => { redisClient.set = mockRedis(); - const now = Date.now(); - federatedInstanceService.fetch.mockResolvedValue({ infoUpdatedAt: { getTime: () => now } } as any); + federatedInstanceService.fetch.mockResolvedValue({ infoUpdatedAt: new Date() } as any); httpRequestService.getJson.mockImplementation(() => { throw Error(); }); const tryLockSpy = jest.spyOn(fetchInstanceMetadataService, 'tryLock'); const unlockSpy = jest.spyOn(fetchInstanceMetadataService, 'unlock'); await fetchInstanceMetadataService.fetchInstanceMetadata({ host: 'example.com' } as any); - expect(tryLockSpy).toHaveBeenCalledTimes(1); - expect(unlockSpy).toHaveBeenCalledTimes(1); expect(federatedInstanceService.fetch).toHaveBeenCalledTimes(1); + expect(tryLockSpy).toHaveBeenCalledTimes(0); + expect(unlockSpy).toHaveBeenCalledTimes(0); expect(httpRequestService.getJson).toHaveBeenCalledTimes(0); }); test('Do nothing when lock not acquired', async () => { redisClient.set = mockRedis(); const now = Date.now(); - federatedInstanceService.fetch.mockResolvedValue({ infoUpdatedAt: { getTime: () => now - 10 * 1000 * 60 * 60 * 24 } } as any); + federatedInstanceService.fetch.mockResolvedValue({ infoUpdatedAt: new Date(now - 10 * 1000 * 60 * 60 * 24) } as any); httpRequestService.getJson.mockImplementation(() => { throw Error(); }); await fetchInstanceMetadataService.tryLock('example.com'); const tryLockSpy = jest.spyOn(fetchInstanceMetadataService, 'tryLock'); const unlockSpy = jest.spyOn(fetchInstanceMetadataService, 'unlock'); await fetchInstanceMetadataService.fetchInstanceMetadata({ host: 'example.com' } as any); + expect(federatedInstanceService.fetch).toHaveBeenCalledTimes(1); expect(tryLockSpy).toHaveBeenCalledTimes(1); expect(unlockSpy).toHaveBeenCalledTimes(0); - expect(federatedInstanceService.fetch).toHaveBeenCalledTimes(0); expect(httpRequestService.getJson).toHaveBeenCalledTimes(0); }); - test('Do when lock not acquired but forced', async () => { + test('Do when forced', async () => { redisClient.set = mockRedis(); const now = Date.now(); - federatedInstanceService.fetch.mockResolvedValue({ infoUpdatedAt: { getTime: () => now - 10 * 1000 * 60 * 60 * 24 } } as any); + federatedInstanceService.fetch.mockResolvedValue({ infoUpdatedAt: new Date(now - 10 * 1000 * 60 * 60 * 24) } as any); httpRequestService.getJson.mockImplementation(() => { throw Error(); }); await fetchInstanceMetadataService.tryLock('example.com'); const tryLockSpy = jest.spyOn(fetchInstanceMetadataService, 'tryLock'); const unlockSpy = jest.spyOn(fetchInstanceMetadataService, 'unlock'); await fetchInstanceMetadataService.fetchInstanceMetadata({ host: 'example.com' } as any, true); + expect(federatedInstanceService.fetch).toHaveBeenCalledTimes(0); expect(tryLockSpy).toHaveBeenCalledTimes(0); expect(unlockSpy).toHaveBeenCalledTimes(1); - expect(federatedInstanceService.fetch).toHaveBeenCalledTimes(0); expect(httpRequestService.getJson).toHaveBeenCalled(); }); }); diff --git a/packages/backend/test/unit/FileInfoService.ts b/packages/backend/test/unit/FileInfoService.ts index 40d187f5a8..29bd03a201 100644 --- a/packages/backend/test/unit/FileInfoService.ts +++ b/packages/backend/test/unit/FileInfoService.ts @@ -12,7 +12,7 @@ import { ModuleMocker } from 'jest-mock'; import { Test } from '@nestjs/testing'; import { afterAll, beforeAll, describe, test } from '@jest/globals'; import { GlobalModule } from '@/GlobalModule.js'; -import { FileInfoService } from '@/core/FileInfoService.js'; +import { FileInfo, FileInfoService } from '@/core/FileInfoService.js'; //import { DI } from '@/di-symbols.js'; import { AiService } from '@/core/AiService.js'; import { LoggerService } from '@/core/LoggerService.js'; @@ -28,6 +28,15 @@ const moduleMocker = new ModuleMocker(global); describe('FileInfoService', () => { let app: TestingModule; let fileInfoService: FileInfoService; + const strip = (fileInfo: FileInfo): Omit, 'warnings' | 'blurhash' | 'sensitive' | 'porn'> => { + const fi: Partial = fileInfo; + delete fi.warnings; + delete fi.sensitive; + delete fi.blurhash; + delete fi.porn; + + return fi; + } beforeAll(async () => { app = await Test.createTestingModule({ @@ -63,11 +72,7 @@ describe('FileInfoService', () => { test('Empty file', async () => { const path = `${resources}/emptyfile`; - const info = await fileInfoService.getFileInfo(path, { skipSensitiveDetection: true }) as any; - delete info.warnings; - delete info.blurhash; - delete info.sensitive; - delete info.porn; + const info = strip(await fileInfoService.getFileInfo(path, { skipSensitiveDetection: true })); assert.deepStrictEqual(info, { size: 0, md5: 'd41d8cd98f00b204e9800998ecf8427e', @@ -83,32 +88,24 @@ describe('FileInfoService', () => { describe('IMAGE', () => { test('Generic JPEG', async () => { - const path = `${resources}/Lenna.jpg`; - const info = await fileInfoService.getFileInfo(path, { skipSensitiveDetection: true }) as any; - delete info.warnings; - delete info.blurhash; - delete info.sensitive; - delete info.porn; + const path = `${resources}/192.jpg`; + const info = strip(await fileInfoService.getFileInfo(path, { skipSensitiveDetection: true })); assert.deepStrictEqual(info, { - size: 25360, - md5: '091b3f259662aa31e2ffef4519951168', + size: 5131, + md5: '8c9ed0677dd2b8f9f7472c3af247e5e3', type: { mime: 'image/jpeg', ext: 'jpg', }, - width: 512, - height: 512, + width: 192, + height: 192, orientation: undefined, }); }); test('Generic APNG', async () => { const path = `${resources}/anime.png`; - const info = await fileInfoService.getFileInfo(path, { skipSensitiveDetection: true }) as any; - delete info.warnings; - delete info.blurhash; - delete info.sensitive; - delete info.porn; + const info = strip(await fileInfoService.getFileInfo(path, { skipSensitiveDetection: true })); assert.deepStrictEqual(info, { size: 1868, md5: '08189c607bea3b952704676bb3c979e0', @@ -124,11 +121,7 @@ describe('FileInfoService', () => { test('Generic AGIF', async () => { const path = `${resources}/anime.gif`; - const info = await fileInfoService.getFileInfo(path, { skipSensitiveDetection: true }) as any; - delete info.warnings; - delete info.blurhash; - delete info.sensitive; - delete info.porn; + const info = strip(await fileInfoService.getFileInfo(path, { skipSensitiveDetection: true })); assert.deepStrictEqual(info, { size: 2248, md5: '32c47a11555675d9267aee1a86571e7e', @@ -144,11 +137,7 @@ describe('FileInfoService', () => { test('PNG with alpha', async () => { const path = `${resources}/with-alpha.png`; - const info = await fileInfoService.getFileInfo(path, { skipSensitiveDetection: true }) as any; - delete info.warnings; - delete info.blurhash; - delete info.sensitive; - delete info.porn; + const info = strip(await fileInfoService.getFileInfo(path, { skipSensitiveDetection: true })); assert.deepStrictEqual(info, { size: 3772, md5: 'f73535c3e1e27508885b69b10cf6e991', @@ -164,11 +153,7 @@ describe('FileInfoService', () => { test('Generic SVG', async () => { const path = `${resources}/image.svg`; - const info = await fileInfoService.getFileInfo(path, { skipSensitiveDetection: true }) as any; - delete info.warnings; - delete info.blurhash; - delete info.sensitive; - delete info.porn; + const info = strip(await fileInfoService.getFileInfo(path, { skipSensitiveDetection: true })); assert.deepStrictEqual(info, { size: 505, md5: 'b6f52b4b021e7b92cdd04509c7267965', @@ -185,11 +170,7 @@ describe('FileInfoService', () => { test('SVG with XML definition', async () => { // https://github.com/misskey-dev/misskey/issues/4413 const path = `${resources}/with-xml-def.svg`; - const info = await fileInfoService.getFileInfo(path, { skipSensitiveDetection: true }) as any; - delete info.warnings; - delete info.blurhash; - delete info.sensitive; - delete info.porn; + const info = strip(await fileInfoService.getFileInfo(path, { skipSensitiveDetection: true })); assert.deepStrictEqual(info, { size: 544, md5: '4b7a346cde9ccbeb267e812567e33397', @@ -205,11 +186,7 @@ describe('FileInfoService', () => { test('Dimension limit', async () => { const path = `${resources}/25000x25000.png`; - const info = await fileInfoService.getFileInfo(path, { skipSensitiveDetection: true }) as any; - delete info.warnings; - delete info.blurhash; - delete info.sensitive; - delete info.porn; + const info = strip(await fileInfoService.getFileInfo(path, { skipSensitiveDetection: true })); assert.deepStrictEqual(info, { size: 75933, md5: '268c5dde99e17cf8fe09f1ab3f97df56', @@ -225,11 +202,7 @@ describe('FileInfoService', () => { test('Rotate JPEG', async () => { const path = `${resources}/rotate.jpg`; - const info = await fileInfoService.getFileInfo(path, { skipSensitiveDetection: true }) as any; - delete info.warnings; - delete info.blurhash; - delete info.sensitive; - delete info.porn; + const info = strip(await fileInfoService.getFileInfo(path, { skipSensitiveDetection: true })); assert.deepStrictEqual(info, { size: 12624, md5: '68d5b2d8d1d1acbbce99203e3ec3857e', @@ -247,11 +220,7 @@ describe('FileInfoService', () => { describe('AUDIO', () => { test('MP3', async () => { const path = `${resources}/kick_gaba7.mp3`; - const info = await fileInfoService.getFileInfo(path, { skipSensitiveDetection: true }) as any; - delete info.warnings; - delete info.blurhash; - delete info.sensitive; - delete info.porn; + const info = strip(await fileInfoService.getFileInfo(path, { skipSensitiveDetection: true })); delete info.width; delete info.height; delete info.orientation; @@ -267,11 +236,7 @@ describe('FileInfoService', () => { test('WAV', async () => { const path = `${resources}/kick_gaba7.wav`; - const info = await fileInfoService.getFileInfo(path, { skipSensitiveDetection: true }) as any; - delete info.warnings; - delete info.blurhash; - delete info.sensitive; - delete info.porn; + const info = strip(await fileInfoService.getFileInfo(path, { skipSensitiveDetection: true })); delete info.width; delete info.height; delete info.orientation; @@ -287,11 +252,7 @@ describe('FileInfoService', () => { test('AAC', async () => { const path = `${resources}/kick_gaba7.aac`; - const info = await fileInfoService.getFileInfo(path, { skipSensitiveDetection: true }) as any; - delete info.warnings; - delete info.blurhash; - delete info.sensitive; - delete info.porn; + const info = strip(await fileInfoService.getFileInfo(path, { skipSensitiveDetection: true })); delete info.width; delete info.height; delete info.orientation; @@ -307,11 +268,7 @@ describe('FileInfoService', () => { test('FLAC', async () => { const path = `${resources}/kick_gaba7.flac`; - const info = await fileInfoService.getFileInfo(path, { skipSensitiveDetection: true }) as any; - delete info.warnings; - delete info.blurhash; - delete info.sensitive; - delete info.porn; + const info = strip(await fileInfoService.getFileInfo(path, { skipSensitiveDetection: true })); delete info.width; delete info.height; delete info.orientation; @@ -327,11 +284,7 @@ describe('FileInfoService', () => { test('MPEG-4 AUDIO (M4A)', async () => { const path = `${resources}/kick_gaba7.m4a`; - const info = await fileInfoService.getFileInfo(path, { skipSensitiveDetection: true }) as any; - delete info.warnings; - delete info.blurhash; - delete info.sensitive; - delete info.porn; + const info = strip(await fileInfoService.getFileInfo(path, { skipSensitiveDetection: true })); delete info.width; delete info.height; delete info.orientation; @@ -347,11 +300,7 @@ describe('FileInfoService', () => { test('WEBM AUDIO', async () => { const path = `${resources}/kick_gaba7.webm`; - const info = await fileInfoService.getFileInfo(path, { skipSensitiveDetection: true }) as any; - delete info.warnings; - delete info.blurhash; - delete info.sensitive; - delete info.porn; + const info = strip(await fileInfoService.getFileInfo(path, { skipSensitiveDetection: true })); delete info.width; delete info.height; delete info.orientation; diff --git a/packages/backend/test/unit/RoleService.ts b/packages/backend/test/unit/RoleService.ts index ec441735d7..b6cbe4c520 100644 --- a/packages/backend/test/unit/RoleService.ts +++ b/packages/backend/test/unit/RoleService.ts @@ -3,17 +3,23 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import { UserEntityService } from '@/core/entities/UserEntityService.js'; - process.env.NODE_ENV = 'test'; +import { setTimeout } from 'node:timers/promises'; import { jest } from '@jest/globals'; import { ModuleMocker } from 'jest-mock'; import { Test } from '@nestjs/testing'; import * as lolex from '@sinonjs/fake-timers'; import { GlobalModule } from '@/GlobalModule.js'; import { RoleService } from '@/core/RoleService.js'; -import type { MiRole, MiUser, RoleAssignmentsRepository, RolesRepository, UsersRepository } from '@/models/_.js'; +import { + MiRole, + MiRoleAssignment, + MiUser, + RoleAssignmentsRepository, + RolesRepository, + UsersRepository, +} from '@/models/_.js'; import { DI } from '@/di-symbols.js'; import { MetaService } from '@/core/MetaService.js'; import { genAidx } from '@/misc/id/aidx.js'; @@ -23,7 +29,7 @@ import { GlobalEventService } from '@/core/GlobalEventService.js'; import { secureRndstr } from '@/misc/secure-rndstr.js'; import { NotificationService } from '@/core/NotificationService.js'; import { RoleCondFormulaValue } from '@/models/Role.js'; -import { sleep } from '../utils.js'; +import { UserEntityService } from '@/core/entities/UserEntityService.js'; import type { TestingModule } from '@nestjs/testing'; import type { MockFunctionMetadata } from 'jest-mock'; @@ -39,27 +45,27 @@ describe('RoleService', () => { let notificationService: jest.Mocked; let clock: lolex.InstalledClock; - function createUser(data: Partial = {}) { + async function createUser(data: Partial = {}) { const un = secureRndstr(16); - return usersRepository.insert({ + const x = await usersRepository.insert({ id: genAidx(Date.now()), username: un, usernameLower: un, ...data, - }) - .then(x => usersRepository.findOneByOrFail(x.identifiers[0])); + }); + return await usersRepository.findOneByOrFail(x.identifiers[0]); } - function createRole(data: Partial = {}) { - return rolesRepository.insert({ + async function createRole(data: Partial = {}) { + const x = await rolesRepository.insert({ id: genAidx(Date.now()), updatedAt: new Date(), lastUsedAt: new Date(), name: '', description: '', ...data, - }) - .then(x => rolesRepository.findOneByOrFail(x.identifiers[0])); + }); + return await rolesRepository.findOneByOrFail(x.identifiers[0]); } function createConditionalRole(condFormula: RoleCondFormulaValue, data: Partial = {}) { @@ -71,6 +77,20 @@ describe('RoleService', () => { }); } + async function assignRole(args: Partial) { + const id = genAidx(Date.now()); + const expiresAt = new Date(); + expiresAt.setDate(expiresAt.getDate() + 1); + + await roleAssignmentsRepository.insert({ + id, + expiresAt, + ...args, + }); + + return await roleAssignmentsRepository.findOneByOrFail({ id }); + } + function aidx() { return genAidx(Date.now()); } @@ -258,13 +278,103 @@ describe('RoleService', () => { // ストリーミング経由で反映されるまでちょっと待つ clock.uninstall(); - await sleep(100); + await setTimeout(100); const resultAfter25hAgain = await roleService.getUserPolicies(user.id); expect(resultAfter25hAgain.canManageCustomEmojis).toBe(true); }); }); + describe('getModeratorIds', () => { + test('includeAdmins = false, excludeExpire = false', async () => { + const [adminUser1, adminUser2, modeUser1, modeUser2, normalUser1, normalUser2] = await Promise.all([ + createUser(), createUser(), createUser(), createUser(), createUser(), createUser(), + ]); + + const role1 = await createRole({ name: 'admin', isAdministrator: true }); + const role2 = await createRole({ name: 'moderator', isModerator: true }); + const role3 = await createRole({ name: 'normal' }); + + await Promise.all([ + assignRole({ userId: adminUser1.id, roleId: role1.id }), + assignRole({ userId: adminUser2.id, roleId: role1.id, expiresAt: new Date(Date.now() - 1000) }), + assignRole({ userId: modeUser1.id, roleId: role2.id }), + assignRole({ userId: modeUser2.id, roleId: role2.id, expiresAt: new Date(Date.now() - 1000) }), + assignRole({ userId: normalUser1.id, roleId: role3.id }), + assignRole({ userId: normalUser2.id, roleId: role3.id, expiresAt: new Date(Date.now() - 1000) }), + ]); + + const result = await roleService.getModeratorIds(false, false); + expect(result).toEqual([modeUser1.id, modeUser2.id]); + }); + + test('includeAdmins = false, excludeExpire = true', async () => { + const [adminUser1, adminUser2, modeUser1, modeUser2, normalUser1, normalUser2] = await Promise.all([ + createUser(), createUser(), createUser(), createUser(), createUser(), createUser(), + ]); + + const role1 = await createRole({ name: 'admin', isAdministrator: true }); + const role2 = await createRole({ name: 'moderator', isModerator: true }); + const role3 = await createRole({ name: 'normal' }); + + await Promise.all([ + assignRole({ userId: adminUser1.id, roleId: role1.id }), + assignRole({ userId: adminUser2.id, roleId: role1.id, expiresAt: new Date(Date.now() - 1000) }), + assignRole({ userId: modeUser1.id, roleId: role2.id }), + assignRole({ userId: modeUser2.id, roleId: role2.id, expiresAt: new Date(Date.now() - 1000) }), + assignRole({ userId: normalUser1.id, roleId: role3.id }), + assignRole({ userId: normalUser2.id, roleId: role3.id, expiresAt: new Date(Date.now() - 1000) }), + ]); + + const result = await roleService.getModeratorIds(false, true); + expect(result).toEqual([modeUser1.id]); + }); + + test('includeAdmins = true, excludeExpire = false', async () => { + const [adminUser1, adminUser2, modeUser1, modeUser2, normalUser1, normalUser2] = await Promise.all([ + createUser(), createUser(), createUser(), createUser(), createUser(), createUser(), + ]); + + const role1 = await createRole({ name: 'admin', isAdministrator: true }); + const role2 = await createRole({ name: 'moderator', isModerator: true }); + const role3 = await createRole({ name: 'normal' }); + + await Promise.all([ + assignRole({ userId: adminUser1.id, roleId: role1.id }), + assignRole({ userId: adminUser2.id, roleId: role1.id, expiresAt: new Date(Date.now() - 1000) }), + assignRole({ userId: modeUser1.id, roleId: role2.id }), + assignRole({ userId: modeUser2.id, roleId: role2.id, expiresAt: new Date(Date.now() - 1000) }), + assignRole({ userId: normalUser1.id, roleId: role3.id }), + assignRole({ userId: normalUser2.id, roleId: role3.id, expiresAt: new Date(Date.now() - 1000) }), + ]); + + const result = await roleService.getModeratorIds(true, false); + expect(result).toEqual([adminUser1.id, adminUser2.id, modeUser1.id, modeUser2.id]); + }); + + test('includeAdmins = true, excludeExpire = true', async () => { + const [adminUser1, adminUser2, modeUser1, modeUser2, normalUser1, normalUser2] = await Promise.all([ + createUser(), createUser(), createUser(), createUser(), createUser(), createUser(), + ]); + + const role1 = await createRole({ name: 'admin', isAdministrator: true }); + const role2 = await createRole({ name: 'moderator', isModerator: true }); + const role3 = await createRole({ name: 'normal' }); + + await Promise.all([ + assignRole({ userId: adminUser1.id, roleId: role1.id }), + assignRole({ userId: adminUser2.id, roleId: role1.id, expiresAt: new Date(Date.now() - 1000) }), + assignRole({ userId: modeUser1.id, roleId: role2.id }), + assignRole({ userId: modeUser2.id, roleId: role2.id, expiresAt: new Date(Date.now() - 1000) }), + assignRole({ userId: normalUser1.id, roleId: role3.id }), + assignRole({ userId: normalUser2.id, roleId: role3.id, expiresAt: new Date(Date.now() - 1000) }), + ]); + + const result = await roleService.getModeratorIds(true, true); + expect(result).toEqual([adminUser1.id, modeUser1.id]); + }); + }); + describe('conditional role', () => { test('~かつ~', async () => { const [user1, user2, user3, user4] = await Promise.all([ @@ -697,7 +807,7 @@ describe('RoleService', () => { await roleService.assign(user.id, role.id); clock.uninstall(); - await sleep(100); + await setTimeout(100); const assignments = await roleAssignmentsRepository.find({ where: { @@ -725,7 +835,7 @@ describe('RoleService', () => { await roleService.assign(user.id, role.id); clock.uninstall(); - await sleep(100); + await setTimeout(100); const assignments = await roleAssignmentsRepository.find({ where: { diff --git a/packages/backend/test/unit/SystemWebhookService.ts b/packages/backend/test/unit/SystemWebhookService.ts new file mode 100644 index 0000000000..790cd1490e --- /dev/null +++ b/packages/backend/test/unit/SystemWebhookService.ts @@ -0,0 +1,516 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { setTimeout } from 'node:timers/promises'; +import { afterEach, beforeEach, describe, expect, jest } from '@jest/globals'; +import { Test, TestingModule } from '@nestjs/testing'; +import { MiUser } from '@/models/User.js'; +import { MiSystemWebhook, SystemWebhookEventType } from '@/models/SystemWebhook.js'; +import { SystemWebhooksRepository, UsersRepository } from '@/models/_.js'; +import { IdService } from '@/core/IdService.js'; +import { GlobalModule } from '@/GlobalModule.js'; +import { ModerationLogService } from '@/core/ModerationLogService.js'; +import { GlobalEventService } from '@/core/GlobalEventService.js'; +import { DI } from '@/di-symbols.js'; +import { QueueService } from '@/core/QueueService.js'; +import { LoggerService } from '@/core/LoggerService.js'; +import { SystemWebhookService } from '@/core/SystemWebhookService.js'; +import { randomString } from '../utils.js'; + +describe('SystemWebhookService', () => { + let app: TestingModule; + let service: SystemWebhookService; + + // -------------------------------------------------------------------------------------- + + let usersRepository: UsersRepository; + let systemWebhooksRepository: SystemWebhooksRepository; + let idService: IdService; + let queueService: jest.Mocked; + + // -------------------------------------------------------------------------------------- + + let root: MiUser; + + // -------------------------------------------------------------------------------------- + + async function createUser(data: Partial = {}) { + return await usersRepository + .insert({ + id: idService.gen(), + ...data, + }) + .then(x => usersRepository.findOneByOrFail(x.identifiers[0])); + } + + async function createWebhook(data: Partial = {}) { + return systemWebhooksRepository + .insert({ + id: idService.gen(), + name: randomString(), + on: ['abuseReport'], + url: 'https://example.com', + secret: randomString(), + ...data, + }) + .then(x => systemWebhooksRepository.findOneByOrFail(x.identifiers[0])); + } + + // -------------------------------------------------------------------------------------- + + async function beforeAllImpl() { + app = await Test + .createTestingModule({ + imports: [ + GlobalModule, + ], + providers: [ + SystemWebhookService, + IdService, + LoggerService, + GlobalEventService, + { + provide: QueueService, useFactory: () => ({ systemWebhookDeliver: jest.fn() }), + }, + { + provide: ModerationLogService, useFactory: () => ({ log: () => Promise.resolve() }), + }, + ], + }) + .compile(); + + usersRepository = app.get(DI.usersRepository); + systemWebhooksRepository = app.get(DI.systemWebhooksRepository); + + service = app.get(SystemWebhookService); + idService = app.get(IdService); + queueService = app.get(QueueService) as jest.Mocked; + + app.enableShutdownHooks(); + } + + async function afterAllImpl() { + await app.close(); + } + + async function beforeEachImpl() { + root = await createUser({ isRoot: true, username: 'root', usernameLower: 'root' }); + } + + async function afterEachImpl() { + await usersRepository.delete({}); + await systemWebhooksRepository.delete({}); + } + + // -------------------------------------------------------------------------------------- + + describe('アプリを毎回作り直す必要のないグループ', () => { + beforeAll(beforeAllImpl); + afterAll(afterAllImpl); + beforeEach(beforeEachImpl); + afterEach(afterEachImpl); + + describe('fetchSystemWebhooks', () => { + test('フィルタなし', async () => { + const webhook1 = await createWebhook({ + isActive: true, + on: ['abuseReport'], + }); + const webhook2 = await createWebhook({ + isActive: false, + on: ['abuseReport'], + }); + const webhook3 = await createWebhook({ + isActive: true, + on: ['abuseReportResolved'], + }); + const webhook4 = await createWebhook({ + isActive: false, + on: [], + }); + + const fetchedWebhooks = await service.fetchSystemWebhooks(); + expect(fetchedWebhooks).toEqual([webhook1, webhook2, webhook3, webhook4]); + }); + + test('activeのみ', async () => { + const webhook1 = await createWebhook({ + isActive: true, + on: ['abuseReport'], + }); + const webhook2 = await createWebhook({ + isActive: false, + on: ['abuseReport'], + }); + const webhook3 = await createWebhook({ + isActive: true, + on: ['abuseReportResolved'], + }); + const webhook4 = await createWebhook({ + isActive: false, + on: [], + }); + + const fetchedWebhooks = await service.fetchSystemWebhooks({ isActive: true }); + expect(fetchedWebhooks).toEqual([webhook1, webhook3]); + }); + + test('特定のイベントのみ', async () => { + const webhook1 = await createWebhook({ + isActive: true, + on: ['abuseReport'], + }); + const webhook2 = await createWebhook({ + isActive: false, + on: ['abuseReport'], + }); + const webhook3 = await createWebhook({ + isActive: true, + on: ['abuseReportResolved'], + }); + const webhook4 = await createWebhook({ + isActive: false, + on: [], + }); + + const fetchedWebhooks = await service.fetchSystemWebhooks({ on: ['abuseReport'] }); + expect(fetchedWebhooks).toEqual([webhook1, webhook2]); + }); + + test('activeな特定のイベントのみ', async () => { + const webhook1 = await createWebhook({ + isActive: true, + on: ['abuseReport'], + }); + const webhook2 = await createWebhook({ + isActive: false, + on: ['abuseReport'], + }); + const webhook3 = await createWebhook({ + isActive: true, + on: ['abuseReportResolved'], + }); + const webhook4 = await createWebhook({ + isActive: false, + on: [], + }); + + const fetchedWebhooks = await service.fetchSystemWebhooks({ on: ['abuseReport'], isActive: true }); + expect(fetchedWebhooks).toEqual([webhook1]); + }); + + test('ID指定', async () => { + const webhook1 = await createWebhook({ + isActive: true, + on: ['abuseReport'], + }); + const webhook2 = await createWebhook({ + isActive: false, + on: ['abuseReport'], + }); + const webhook3 = await createWebhook({ + isActive: true, + on: ['abuseReportResolved'], + }); + const webhook4 = await createWebhook({ + isActive: false, + on: [], + }); + + const fetchedWebhooks = await service.fetchSystemWebhooks({ ids: [webhook1.id, webhook4.id] }); + expect(fetchedWebhooks).toEqual([webhook1, webhook4]); + }); + + test('ID指定(他条件とANDになるか見たい)', async () => { + const webhook1 = await createWebhook({ + isActive: true, + on: ['abuseReport'], + }); + const webhook2 = await createWebhook({ + isActive: false, + on: ['abuseReport'], + }); + const webhook3 = await createWebhook({ + isActive: true, + on: ['abuseReportResolved'], + }); + const webhook4 = await createWebhook({ + isActive: false, + on: [], + }); + + const fetchedWebhooks = await service.fetchSystemWebhooks({ ids: [webhook1.id, webhook4.id], isActive: false }); + expect(fetchedWebhooks).toEqual([webhook4]); + }); + }); + + describe('createSystemWebhook', () => { + test('作成成功 ', async () => { + const params = { + isActive: true, + name: randomString(), + on: ['abuseReport'] as SystemWebhookEventType[], + url: 'https://example.com', + secret: randomString(), + }; + + const webhook = await service.createSystemWebhook(params, root); + expect(webhook).toMatchObject(params); + }); + }); + + describe('updateSystemWebhook', () => { + test('更新成功', async () => { + const webhook = await createWebhook({ + isActive: true, + on: ['abuseReport'], + }); + + const params = { + id: webhook.id, + isActive: false, + name: randomString(), + on: ['abuseReport'] as SystemWebhookEventType[], + url: randomString(), + secret: randomString(), + }; + + const updatedWebhook = await service.updateSystemWebhook(params, root); + expect(updatedWebhook).toMatchObject(params); + }); + }); + + describe('deleteSystemWebhook', () => { + test('削除成功', async () => { + const webhook = await createWebhook({ + isActive: true, + on: ['abuseReport'], + }); + + await service.deleteSystemWebhook(webhook.id, root); + + await expect(systemWebhooksRepository.findOneBy({ id: webhook.id })).resolves.toBeNull(); + }); + }); + }); + + describe('アプリを毎回作り直す必要があるグループ', () => { + beforeEach(async () => { + await beforeAllImpl(); + await beforeEachImpl(); + }); + + afterEach(async () => { + await afterEachImpl(); + await afterAllImpl(); + }); + + describe('enqueueSystemWebhook', () => { + test('キューに追加成功', async () => { + const webhook = await createWebhook({ + isActive: true, + on: ['abuseReport'], + }); + await service.enqueueSystemWebhook(webhook.id, 'abuseReport', { foo: 'bar' }); + + expect(queueService.systemWebhookDeliver).toHaveBeenCalled(); + }); + + test('非アクティブなWebhookはキューに追加されない', async () => { + const webhook = await createWebhook({ + isActive: false, + on: ['abuseReport'], + }); + await service.enqueueSystemWebhook(webhook.id, 'abuseReport', { foo: 'bar' }); + + expect(queueService.systemWebhookDeliver).not.toHaveBeenCalled(); + }); + + test('未許可のイベント種別が渡された場合はWebhookはキューに追加されない', async () => { + const webhook1 = await createWebhook({ + isActive: true, + on: [], + }); + const webhook2 = await createWebhook({ + isActive: true, + on: ['abuseReportResolved'], + }); + await service.enqueueSystemWebhook(webhook1.id, 'abuseReport', { foo: 'bar' }); + await service.enqueueSystemWebhook(webhook2.id, 'abuseReport', { foo: 'bar' }); + + expect(queueService.systemWebhookDeliver).not.toHaveBeenCalled(); + }); + }); + + describe('fetchActiveSystemWebhooks', () => { + describe('systemWebhookCreated', () => { + test('ActiveなWebhookが追加された時、キャッシュに追加されている', async () => { + const webhook = await service.createSystemWebhook( + { + isActive: true, + name: randomString(), + on: ['abuseReport'], + url: 'https://example.com', + secret: randomString(), + }, + root, + ); + + // redisでの配信経由で更新されるのでちょっと待つ + await setTimeout(500); + + const fetchedWebhooks = await service.fetchActiveSystemWebhooks(); + expect(fetchedWebhooks).toEqual([webhook]); + }); + + test('NotActiveなWebhookが追加された時、キャッシュに追加されていない', async () => { + const webhook = await service.createSystemWebhook( + { + isActive: false, + name: randomString(), + on: ['abuseReport'], + url: 'https://example.com', + secret: randomString(), + }, + root, + ); + + // redisでの配信経由で更新されるのでちょっと待つ + await setTimeout(500); + + const fetchedWebhooks = await service.fetchActiveSystemWebhooks(); + expect(fetchedWebhooks).toEqual([]); + }); + }); + + describe('systemWebhookUpdated', () => { + test('ActiveなWebhookが編集された時、キャッシュに反映されている', async () => { + const id = idService.gen(); + await createWebhook({ id }); + // キャッシュ作成 + const webhook1 = await service.fetchActiveSystemWebhooks(); + // 読み込まれていることをチェック + expect(webhook1.length).toEqual(1); + expect(webhook1[0].id).toEqual(id); + + const webhook2 = await service.updateSystemWebhook( + { + id, + isActive: true, + name: randomString(), + on: ['abuseReport'], + url: 'https://example.com', + secret: randomString(), + }, + root, + ); + + // redisでの配信経由で更新されるのでちょっと待つ + await setTimeout(500); + + const fetchedWebhooks = await service.fetchActiveSystemWebhooks(); + expect(fetchedWebhooks).toEqual([webhook2]); + }); + + test('NotActiveなWebhookが編集された時、キャッシュに追加されない', async () => { + const id = idService.gen(); + await createWebhook({ id, isActive: false }); + // キャッシュ作成 + const webhook1 = await service.fetchActiveSystemWebhooks(); + // 読み込まれていないことをチェック + expect(webhook1.length).toEqual(0); + + const webhook2 = await service.updateSystemWebhook( + { + id, + isActive: false, + name: randomString(), + on: ['abuseReport'], + url: 'https://example.com', + secret: randomString(), + }, + root, + ); + + // redisでの配信経由で更新されるのでちょっと待つ + await setTimeout(500); + + const fetchedWebhooks = await service.fetchActiveSystemWebhooks(); + expect(fetchedWebhooks.length).toEqual(0); + }); + + test('NotActiveなWebhookがActiveにされた時、キャッシュに追加されている', async () => { + const id = idService.gen(); + const baseWebhook = await createWebhook({ id, isActive: false }); + // キャッシュ作成 + const webhook1 = await service.fetchActiveSystemWebhooks(); + // 読み込まれていないことをチェック + expect(webhook1.length).toEqual(0); + + const webhook2 = await service.updateSystemWebhook( + { + ...baseWebhook, + isActive: true, + }, + root, + ); + + // redisでの配信経由で更新されるのでちょっと待つ + await setTimeout(500); + + const fetchedWebhooks = await service.fetchActiveSystemWebhooks(); + expect(fetchedWebhooks).toEqual([webhook2]); + }); + + test('ActiveなWebhookがNotActiveにされた時、キャッシュから削除されている', async () => { + const id = idService.gen(); + const baseWebhook = await createWebhook({ id, isActive: true }); + // キャッシュ作成 + const webhook1 = await service.fetchActiveSystemWebhooks(); + // 読み込まれていることをチェック + expect(webhook1.length).toEqual(1); + expect(webhook1[0].id).toEqual(id); + + const webhook2 = await service.updateSystemWebhook( + { + ...baseWebhook, + isActive: false, + }, + root, + ); + + // redisでの配信経由で更新されるのでちょっと待つ + await setTimeout(500); + + const fetchedWebhooks = await service.fetchActiveSystemWebhooks(); + expect(fetchedWebhooks.length).toEqual(0); + }); + }); + + describe('systemWebhookDeleted', () => { + test('キャッシュから削除されている', async () => { + const id = idService.gen(); + const baseWebhook = await createWebhook({ id, isActive: true }); + // キャッシュ作成 + const webhook1 = await service.fetchActiveSystemWebhooks(); + // 読み込まれていることをチェック + expect(webhook1.length).toEqual(1); + expect(webhook1[0].id).toEqual(id); + + const webhook2 = await service.deleteSystemWebhook( + id, + root, + ); + + // redisでの配信経由で更新されるのでちょっと待つ + await setTimeout(500); + + const fetchedWebhooks = await service.fetchActiveSystemWebhooks(); + expect(fetchedWebhooks.length).toEqual(0); + }); + }); + }); + }); +}); diff --git a/packages/backend/test/unit/UserSearchService.ts b/packages/backend/test/unit/UserSearchService.ts new file mode 100644 index 0000000000..7ea325d420 --- /dev/null +++ b/packages/backend/test/unit/UserSearchService.ts @@ -0,0 +1,265 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { Test, TestingModule } from '@nestjs/testing'; +import { describe, jest, test } from '@jest/globals'; +import { In } from 'typeorm'; +import { UserSearchService } from '@/core/UserSearchService.js'; +import { FollowingsRepository, MiUser, UserProfilesRepository, UsersRepository } from '@/models/_.js'; +import { IdService } from '@/core/IdService.js'; +import { GlobalModule } from '@/GlobalModule.js'; +import { DI } from '@/di-symbols.js'; +import { UserEntityService } from '@/core/entities/UserEntityService.js'; + +describe('UserSearchService', () => { + let app: TestingModule; + let service: UserSearchService; + + let usersRepository: UsersRepository; + let followingsRepository: FollowingsRepository; + let idService: IdService; + let userProfilesRepository: UserProfilesRepository; + + let root: MiUser; + let alice: MiUser; + let alyce: MiUser; + let alycia: MiUser; + let alysha: MiUser; + let alyson: MiUser; + let alyssa: MiUser; + let bob: MiUser; + let bobbi: MiUser; + let bobbie: MiUser; + let bobby: MiUser; + + async function createUser(data: Partial = {}) { + const user = await usersRepository + .insert({ + id: idService.gen(), + ...data, + }) + .then(x => usersRepository.findOneByOrFail(x.identifiers[0])); + + await userProfilesRepository.insert({ + userId: user.id, + }); + + return user; + } + + async function createFollowings(follower: MiUser, followees: MiUser[]) { + for (const followee of followees) { + await followingsRepository.insert({ + id: idService.gen(), + followerId: follower.id, + followeeId: followee.id, + }); + } + } + + async function setActive(users: MiUser[]) { + for (const user of users) { + await usersRepository.update(user.id, { + updatedAt: new Date(), + }); + } + } + + async function setInactive(users: MiUser[]) { + for (const user of users) { + await usersRepository.update(user.id, { + updatedAt: new Date(0), + }); + } + } + + async function setSuspended(users: MiUser[]) { + for (const user of users) { + await usersRepository.update(user.id, { + isSuspended: true, + }); + } + } + + beforeAll(async () => { + app = await Test + .createTestingModule({ + imports: [ + GlobalModule, + ], + providers: [ + UserSearchService, + { + provide: UserEntityService, useFactory: jest.fn(() => ({ + // とりあえずIDが返れば確認が出来るので + packMany: (value: any) => value, + })), + }, + IdService, + ], + }) + .compile(); + + await app.init(); + + usersRepository = app.get(DI.usersRepository); + userProfilesRepository = app.get(DI.userProfilesRepository); + followingsRepository = app.get(DI.followingsRepository); + + service = app.get(UserSearchService); + idService = app.get(IdService); + }); + + beforeEach(async () => { + root = await createUser({ username: 'root', usernameLower: 'root', isRoot: true }); + alice = await createUser({ username: 'Alice', usernameLower: 'alice' }); + alyce = await createUser({ username: 'Alyce', usernameLower: 'alyce' }); + alycia = await createUser({ username: 'Alycia', usernameLower: 'alycia' }); + alysha = await createUser({ username: 'Alysha', usernameLower: 'alysha' }); + alyson = await createUser({ username: 'Alyson', usernameLower: 'alyson', host: 'example.com' }); + alyssa = await createUser({ username: 'Alyssa', usernameLower: 'alyssa', host: 'example.com' }); + bob = await createUser({ username: 'Bob', usernameLower: 'bob' }); + bobbi = await createUser({ username: 'Bobbi', usernameLower: 'bobbi' }); + bobbie = await createUser({ username: 'Bobbie', usernameLower: 'bobbie', host: 'example.com' }); + bobby = await createUser({ username: 'Bobby', usernameLower: 'bobby', host: 'example.com' }); + }); + + afterEach(async () => { + await usersRepository.delete({}); + }); + + afterAll(async () => { + await app.close(); + }); + + describe('search', () => { + test('フォロー中のアクティブユーザのうち、"al"から始まる人が全員ヒットする', async () => { + await createFollowings(root, [alice, alyce, alycia, alysha, alyson, alyssa, bob, bobbi, bobbie, bobby]); + await setActive([alice, alyce, alyssa, bob, bobbi, bobbie, bobby]); + await setInactive([alycia, alysha, alyson]); + + const result = await service.search( + { username: 'al' }, + { limit: 100 }, + root, + ); + + // alycia, alysha, alysonは非アクティブなので後ろに行く + expect(result).toEqual([alice, alyce, alyssa, alycia, alysha, alyson].map(x => x.id)); + }); + + test('フォロー中の非アクティブユーザのうち、"al"から始まる人が全員ヒットする', async () => { + await createFollowings(root, [alycia, alysha, alyson, alyssa, bob, bobbi, bobbie, bobby]); + await setInactive([alice, alyce, alycia, alysha, alyson, alyssa, bob, bobbi, bobbie, bobby]); + + const result = await service.search( + { username: 'al' }, + { limit: 100 }, + root, + ); + + // alice, alyceはフォローしていないので後ろに行く + expect(result).toEqual([alycia, alysha, alyson, alyssa, alice, alyce].map(x => x.id)); + }); + + test('フォローしていないアクティブユーザのうち、"al"から始まる人が全員ヒットする', async () => { + await setActive([alysha, alyson, alyssa, bob, bobbi, bobbie, bobby]); + await setInactive([alice, alyce, alycia]); + + const result = await service.search( + { username: 'al' }, + { limit: 100 }, + root, + ); + + // alice, alyce, alyciaは非アクティブなので後ろに行く + expect(result).toEqual([alysha, alyson, alyssa, alice, alyce, alycia].map(x => x.id)); + }); + + test('フォローしていない非アクティブユーザのうち、"al"から始まる人が全員ヒットする', async () => { + await setInactive([alice, alyce, alycia, alysha, alyson, alyssa, bob, bobbi, bobbie, bobby]); + + const result = await service.search( + { username: 'al' }, + { limit: 100 }, + root, + ); + + expect(result).toEqual([alice, alyce, alycia, alysha, alyson, alyssa].map(x => x.id)); + }); + + test('フォロー(アクティブ)、フォロー(非アクティブ)、非フォロー(アクティブ)、非フォロー(非アクティブ)混在時の優先順位度確認', async () => { + await createFollowings(root, [alyson, alyssa, bob, bobbi, bobbie]); + await setActive([root, alyssa, bob, bobbi, alyce, alycia]); + await setInactive([alyson, alice, alysha, bobbie, bobby]); + + const result = await service.search( + { }, + { limit: 100 }, + root, + ); + + // 見る用 + // const users = await usersRepository.findBy({ id: In(result) }).then(it => new Map(it.map(x => [x.id, x]))); + // console.log(result.map(x => users.get(x as any)).map(it => it?.username)); + + // フォローしててアクティブなので先頭: alyssa, bob, bobbi + // フォローしてて非アクティブなので次: alyson, bobbie + // フォローしてないけどアクティブなので次: alyce, alycia, root(アルファベット順的にここになる) + // フォローしてないし非アクティブなので最後: alice, alysha, bobby + expect(result).toEqual([alyssa, bob, bobbi, alyson, bobbie, alyce, alycia, root, alice, alysha, bobby].map(x => x.id)); + }); + + test('[非ログイン] アクティブユーザのうち、"al"から始まる人が全員ヒットする', async () => { + await setActive([alysha, alyson, alyssa, bob, bobbi, bobbie, bobby]); + await setInactive([alice, alyce, alycia]); + + const result = await service.search( + { username: 'al' }, + { limit: 100 }, + ); + + // alice, alyce, alyciaは非アクティブなので後ろに行く + expect(result).toEqual([alysha, alyson, alyssa, alice, alyce, alycia].map(x => x.id)); + }); + + test('[非ログイン] 非アクティブユーザのうち、"al"から始まる人が全員ヒットする', async () => { + await setInactive([alice, alyce, alycia, alysha, alyson, alyssa, bob, bobbi, bobbie, bobby]); + + const result = await service.search( + { username: 'al' }, + { limit: 100 }, + ); + + expect(result).toEqual([alice, alyce, alycia, alysha, alyson, alyssa].map(x => x.id)); + }); + + test('フォロー中のアクティブユーザのうち、"al"から始まり"example.com"にいる人が全員ヒットする', async () => { + await createFollowings(root, [alice, alyce, alycia, alysha, alyson, alyssa, bob, bobbi, bobbie, bobby]); + await setActive([alice, alyce, alycia, alysha, alyson, alyssa, bob, bobbi, bobbie, bobby]); + + const result = await service.search( + { username: 'al', host: 'exam' }, + { limit: 100 }, + root, + ); + + expect(result).toEqual([alyson, alyssa].map(x => x.id)); + }); + + test('サスペンド済みユーザは出ない', async () => { + await setActive([alice, alyce, alycia, alysha, alyson, alyssa, bob, bobbi, bobbie, bobby]); + await setSuspended([alice, alyce, alycia]); + + const result = await service.search( + { username: 'al' }, + { limit: 100 }, + root, + ); + + expect(result).toEqual([alysha, alyson, alyssa].map(x => x.id)); + }); + }); +}); diff --git a/packages/backend/test/unit/ap-request.ts b/packages/backend/test/unit/ap-request.ts index d3d39240dc..50894c8b81 100644 --- a/packages/backend/test/unit/ap-request.ts +++ b/packages/backend/test/unit/ap-request.ts @@ -4,10 +4,8 @@ */ import * as assert from 'assert'; -import httpSignature from '@peertube/http-signature'; - -import { genRsaKeyPair } from '@/misc/gen-key-pair.js'; -import { ApRequestCreator } from '@/core/activitypub/ApRequestService.js'; +import { verifyDraftSignature, parseRequestSignature, genEd25519KeyPair, genRsaKeyPair, importPrivateKey } from '@misskey-dev/node-http-message-signatures'; +import { createSignedGet, createSignedPost } from '@/core/activitypub/ApRequestService.js'; export const buildParsedSignature = (signingString: string, signature: string, algorithm: string) => { return { @@ -24,38 +22,68 @@ export const buildParsedSignature = (signingString: string, signature: string, a }; }; -describe('ap-request', () => { - test('createSignedPost with verify', async () => { - const keypair = await genRsaKeyPair(); - const key = { keyId: 'x', 'privateKeyPem': keypair.privateKey }; - const url = 'https://example.com/inbox'; - const activity = { a: 1 }; - const body = JSON.stringify(activity); - const headers = { - 'User-Agent': 'UA', - }; +async function getKeyPair(level: string) { + if (level === '00') { + return await genRsaKeyPair(); + } else if (level === '01') { + return await genEd25519KeyPair(); + } + throw new Error('Invalid level'); +} - const req = ApRequestCreator.createSignedPost({ key, url, body, additionalHeaders: headers }); +describe('ap-request post', () => { + const url = 'https://example.com/inbox'; + const activity = { a: 1 }; + const body = JSON.stringify(activity); + const headers = { + 'User-Agent': 'UA', + }; - const parsed = buildParsedSignature(req.signingString, req.signature, 'rsa-sha256'); + describe.each(['00', '01'])('createSignedPost with verify', (level) => { + test('pem', async () => { + const keypair = await getKeyPair(level); + const key = { keyId: 'x', 'privateKeyPem': keypair.privateKey }; - const result = httpSignature.verifySignature(parsed, keypair.publicKey); - assert.deepStrictEqual(result, true); - }); + const req = await createSignedPost({ level, key, url, body, additionalHeaders: headers }); - test('createSignedGet with verify', async () => { - const keypair = await genRsaKeyPair(); - const key = { keyId: 'x', 'privateKeyPem': keypair.privateKey }; - const url = 'https://example.com/outbox'; - const headers = { - 'User-Agent': 'UA', - }; + const parsed = parseRequestSignature(req.request); + expect(parsed.version).toBe('draft'); + expect(Array.isArray(parsed.value)).toBe(false); + const verify = await verifyDraftSignature(parsed.value as any, keypair.publicKey); + assert.deepStrictEqual(verify, true); + }); + test('imported', async () => { + const keypair = await getKeyPair(level); + const key = { keyId: 'x', 'privateKey': await importPrivateKey(keypair.privateKey) }; - const req = ApRequestCreator.createSignedGet({ key, url, additionalHeaders: headers }); + const req = await createSignedPost({ level, key, url, body, additionalHeaders: headers }); - const parsed = buildParsedSignature(req.signingString, req.signature, 'rsa-sha256'); - - const result = httpSignature.verifySignature(parsed, keypair.publicKey); - assert.deepStrictEqual(result, true); + const parsed = parseRequestSignature(req.request); + expect(parsed.version).toBe('draft'); + expect(Array.isArray(parsed.value)).toBe(false); + const verify = await verifyDraftSignature(parsed.value as any, keypair.publicKey); + assert.deepStrictEqual(verify, true); + }); + }); +}); + +describe('ap-request get', () => { + describe.each(['00', '01'])('createSignedGet with verify', (level) => { + test('pass', async () => { + const keypair = await getKeyPair(level); + const key = { keyId: 'x', 'privateKeyPem': keypair.privateKey }; + const url = 'https://example.com/outbox'; + const headers = { + 'User-Agent': 'UA', + }; + + const req = await createSignedGet({ level, key, url, additionalHeaders: headers }); + + const parsed = parseRequestSignature(req.request); + expect(parsed.version).toBe('draft'); + expect(Array.isArray(parsed.value)).toBe(false); + const verify = await verifyDraftSignature(parsed.value as any, keypair.publicKey); + assert.deepStrictEqual(verify, true); + }); }); }); diff --git a/packages/backend/test/utils.ts b/packages/backend/test/utils.ts index 86814fffe0..e70befeebe 100644 --- a/packages/backend/test/utils.ts +++ b/packages/backend/test/utils.ts @@ -17,6 +17,8 @@ import { validateContentTypeSetAsActivityPub } from '@/core/activitypub/misc/val import { entities } from '../src/postgres.js'; import { loadConfig } from '../src/config.js'; import type * as misskey from 'misskey-js'; +import { type Response } from 'node-fetch'; +import { ApiError } from "@/server/api/error.js"; export { server as startServer, jobQueue as startJobQueue } from '@/boot/common.js'; @@ -47,27 +49,28 @@ export const successfulApiCall = async ; }; -export const failedApiCall = async (request: ApiRequest, assertion: { +export const failedApiCall = async (request: ApiRequest, assertion: { status: number, code: string, id: string -}): Promise => { +}): Promise => { const { endpoint, parameters, user } = request; const { status, code, id } = assertion; const res = await api(endpoint, parameters, user); assert.strictEqual(res.status, status, inspect(res.body)); - assert.strictEqual(res.body.error.code, code, inspect(res.body)); - assert.strictEqual(res.body.error.id, id, inspect(res.body)); - return res.body; + assert.ok(res.body); + assert.strictEqual(castAsError(res.body as any).error.code, code, inspect(res.body)); + assert.strictEqual(castAsError(res.body as any).error.id, id, inspect(res.body)); }; -export const api = async (path: E, params: misskey.Endpoints[E]['req'], me?: UserToken): Promise<{ +export const api = async (path: E, params: P, me?: UserToken): Promise<{ status: number, headers: Headers, - body: any + body: misskey.api.SwitchCaseResponseType }> => { const bodyAuth: Record = {}; const headers: Record = { @@ -88,13 +91,14 @@ export const api = async (path: E, params: mi }); const body = res.headers.get('content-type') === 'application/json; charset=utf-8' - ? await res.json() + ? await res.json() as misskey.api.SwitchCaseResponseType : null; return { status: res.status, headers: res.headers, - body, + // FIXME: removing this non-null assertion: requires better typing around empty response. + body: body!, }; }; @@ -140,7 +144,8 @@ export const post = async (user: UserToken, params: misskey.Endpoints['notes/cre const res = await api('notes/create', q, user); - return res.body ? res.body.createdNote : null; + // FIXME: the return type should reflect this fact. + return (res.body ? res.body.createdNote : null)!; }; export const createAppToken = async (user: UserToken, permissions: (typeof misskey.permissions)[number][]) => { @@ -296,7 +301,7 @@ export const uploadFile = async (user?: UserToken, { path, name, blob }: UploadO body: misskey.entities.DriveFile | null }> => { const absPath = path == null - ? new URL('resources/Lenna.jpg', import.meta.url) + ? new URL('resources/192.jpg', import.meta.url) : isAbsolute(path.toString()) ? new URL(path) : new URL(path, new URL('resources/', import.meta.url)); @@ -454,7 +459,7 @@ export type SimpleGetResponse = { type: string | null, location: string | null }; -export const simpleGet = async (path: string, accept = '*/*', cookie: any = undefined): Promise => { +export const simpleGet = async (path: string, accept = '*/*', cookie: any = undefined, bodyExtractor: (res: Response) => Promise = _ => Promise.resolve(null)): Promise => { const res = await relativeFetch(path, { headers: { Accept: accept, @@ -482,7 +487,7 @@ export const simpleGet = async (path: string, accept = '*/*', cookie: any = unde const body = jsonTypes.includes(res.headers.get('content-type') ?? '') ? await res.json() : htmlTypes.includes(res.headers.get('content-type') ?? '') ? new JSDOM(await res.text()) : - null; + await bodyExtractor(res); return { status: res.status, @@ -604,14 +609,6 @@ export async function initTestDb(justBorrow = false, initEntities?: any[]) { return db; } -export function sleep(msec: number) { - return new Promise(res => { - setTimeout(() => { - res(); - }, msec); - }); -} - export async function sendEnvUpdateRequest(params: { key: string, value?: string }) { const res = await fetch( `http://localhost:${port + 1000}/env`, @@ -642,3 +639,9 @@ export async function sendEnvResetRequest() { throw new Error('server env update failed.'); } } + +// 与えられた値を強制的にエラーとみなす。この関数は型安全性を破壊するため、異常系のアサーション以外で用いられるべきではない。 +// FIXME(misskey-js): misskey-jsがエラー情報を公開するようになったらこの関数を廃止する +export function castAsError(obj: Record): { error: ApiError } { + return obj as { error: ApiError }; +} diff --git a/packages/frontend/.eslintrc.cjs b/packages/frontend/.eslintrc.cjs deleted file mode 100644 index 20f88dc078..0000000000 --- a/packages/frontend/.eslintrc.cjs +++ /dev/null @@ -1,82 +0,0 @@ -module.exports = { - root: true, - env: { - 'node': false, - }, - parser: 'vue-eslint-parser', - parserOptions: { - 'parser': '@typescript-eslint/parser', - tsconfigRootDir: __dirname, - project: ['./tsconfig.json'], - extraFileExtensions: ['.vue'], - }, - extends: [ - '../shared/.eslintrc.js', - 'plugin:vue/vue3-recommended', - ], - rules: { - '@typescript-eslint/no-empty-interface': [ - 'error', - { - 'allowSingleExtends': true, - }, - ], - // window の禁止理由: グローバルスコープと衝突し、予期せぬ結果を招くため - // e の禁止理由: error や event など、複数のキーワードの頭文字であり分かりにくいため - 'id-denylist': ['error', 'window', 'e'], - 'no-shadow': ['warn'], - 'vue/attributes-order': ['error', { - 'alphabetical': false, - }], - 'vue/no-use-v-if-with-v-for': ['error', { - 'allowUsingIterationVar': false, - }], - 'vue/no-ref-as-operand': 'error', - 'vue/no-multi-spaces': ['error', { - 'ignoreProperties': false, - }], - 'vue/no-v-html': 'warn', - 'vue/order-in-components': 'error', - 'vue/html-indent': ['warn', 'tab', { - 'attribute': 1, - 'baseIndent': 0, - 'closeBracket': 0, - 'alignAttributesVertically': true, - 'ignores': [], - }], - 'vue/html-closing-bracket-spacing': ['warn', { - 'startTag': 'never', - 'endTag': 'never', - 'selfClosingTag': 'never', - }], - 'vue/multi-word-component-names': 'warn', - 'vue/require-v-for-key': 'warn', - 'vue/no-unused-components': 'warn', - 'vue/no-unused-vars': 'warn', - 'vue/no-dupe-keys': 'warn', - 'vue/valid-v-for': 'warn', - 'vue/return-in-computed-property': 'warn', - 'vue/no-setup-props-destructure': 'warn', - 'vue/max-attributes-per-line': 'off', - 'vue/html-self-closing': 'off', - 'vue/singleline-html-element-content-newline': 'off', - 'vue/v-on-event-hyphenation': ['error', 'never', { autofix: true }], - 'vue/attribute-hyphenation': ['error', 'never'], - }, - globals: { - // Node.js - 'module': false, - 'require': false, - '__dirname': false, - - // Misskey - '_DEV_': false, - '_LANGS_': false, - '_VERSION_': false, - '_ENV_': false, - '_PERF_PREFIX_': false, - '_DATA_TRANSFER_DRIVE_FILE_': false, - '_DATA_TRANSFER_DRIVE_FOLDER_': false, - '_DATA_TRANSFER_DECK_COLUMN_': false, - }, -}; diff --git a/packages/frontend/.storybook/changes.ts b/packages/frontend/.storybook/changes.ts index 7c70972e1e..1299910499 100644 --- a/packages/frontend/.storybook/changes.ts +++ b/packages/frontend/.storybook/changes.ts @@ -47,14 +47,12 @@ await fs.readFile( ) ) .map((path) => path.replace(/(?:(?<=\.stories)\.(?:impl|meta)|\.msw)(?=\.ts$)/g, '')) - .map((path) => (path.startsWith('.') ? path : `./${path}`)) ); if ( micromatch(Array.from(modules), [ '../../assets/**', '../../fluent-emojis/**', '../../locales/ja-JP.yml', - '../../misskey-assets/**', 'assets/**', 'public/**', '../../pnpm-lock.yaml', diff --git a/packages/frontend/.storybook/charts.ts b/packages/frontend/.storybook/charts.ts new file mode 100644 index 0000000000..5015012a82 --- /dev/null +++ b/packages/frontend/.storybook/charts.ts @@ -0,0 +1,48 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { DefaultBodyType, HttpResponse, HttpResponseResolver, JsonBodyType, PathParams, http } from 'msw'; +import seedrandom from 'seedrandom'; +import { action } from '@storybook/addon-actions'; + +function getChartArray(seed: string, limit: number, option?: { accumulate?: boolean, mul?: number }): number[] { + const rng = seedrandom(seed); + const max = Math.floor(option?.mul ?? 250 * rng()); + let accumulation = 0; + const array: number[] = []; + for (let i = 0; i < limit; i++) { + const num = Math.floor((max + 1) * rng()); + if (option?.accumulate) { + accumulation += num; + array.unshift(accumulation); + } else { + array.push(num); + } + } + return array; +} + +export function getChartResolver(fields: string[], option?: { accumulate?: boolean, mulMap?: Record }): HttpResponseResolver { + return ({ request }) => { + action(`GET ${request.url}`)(); + const limitParam = new URL(request.url).searchParams.get('limit'); + const limit = limitParam ? parseInt(limitParam) : 30; + const res = {}; + for (const field of fields) { + const layers = field.split('.'); + let current = res; + while (layers.length > 1) { + const currentKey = layers.shift()!; + if (current[currentKey] == null) current[currentKey] = {}; + current = current[currentKey]; + } + current[layers[0]] = getChartArray(field, limit, { + accumulate: option?.accumulate, + mul: option?.mulMap != null && field in option.mulMap ? option.mulMap[field] : undefined, + }); + } + return HttpResponse.json(res); + }; +} diff --git a/packages/frontend/.storybook/fakes.ts b/packages/frontend/.storybook/fakes.ts index 3a24ccb248..9d789a34ff 100644 --- a/packages/frontend/.storybook/fakes.ts +++ b/packages/frontend/.storybook/fakes.ts @@ -22,6 +22,66 @@ export function abuseUserReport() { }; } +export function channel(id = 'somechannelid', name = 'Some Channel', bannerUrl: string | null = 'https://github.com/misskey-dev/misskey/blob/master/packages/frontend/assets/fedi.jpg?raw=true'): entities.Channel { + return { + id, + createdAt: '2016-12-28T22:49:51.000Z', + lastNotedAt: '2016-12-28T22:49:51.000Z', + name, + description: null, + userId: null, + bannerUrl, + pinnedNoteIds: [], + color: '#000', + isArchived: false, + usersCount: 1, + notesCount: 1, + isSensitive: false, + allowRenoteToExternal: false, + }; +} + +export function clip(id = 'someclipid', name = 'Some Clip'): entities.Clip { + return { + id, + createdAt: '2016-12-28T22:49:51.000Z', + lastClippedAt: null, + userId: 'someuserid', + user: { + id: 'someuserid', + name: 'Misskey User', + username: 'miskist', + host: 'misskey-hub.net', + avatarUrl: 'https://github.com/misskey-dev/misskey/blob/master/packages/frontend/assets/about-icon.png?raw=true', + avatarBlurhash: 'eQFRshof5NWBRi},juayfPju53WB?0ofs;s*a{ofjuay^SoMEJR%ay', + avatarDecorations: [], + emojis: {}, + badgeRoles: [], + onlineStatus: 'unknown', + }, + notesCount: undefined, + name, + description: 'Some clip description', + isPublic: false, + favoritedCount: 0, + }; +} + +export function emojiDetailed(id = 'someemojiid', name = 'some_emoji'): entities.EmojiDetailed { + return { + id, + aliases: ['alias1', 'alias2'], + name, + category: 'emojiCategory', + host: null, + url: '/client-assets/about-icon.png', + license: null, + isSensitive: false, + localOnly: false, + roleIdsThatCanBeUsedThisEmojiAsReaction: ['roleId1', 'roleId2'], + }; +} + export function galleryPost(isSensitive = false) { return { id: 'somepostid', @@ -65,6 +125,35 @@ export function file(isSensitive = false) { }; } +export function federationInstance(): entities.FederationInstance { + return { + id: 'someinstanceid', + firstRetrievedAt: '2021-01-01T00:00:00.000Z', + host: 'misskey-hub.net', + usersCount: 10, + notesCount: 20, + followingCount: 5, + followersCount: 15, + isNotResponding: false, + isSuspended: false, + suspensionState: 'none', + isBlocked: false, + softwareName: 'misskey', + softwareVersion: '2024.5.0', + openRegistrations: false, + name: 'Misskey Hub', + description: '', + maintainerName: '', + maintainerEmail: '', + isSilenced: false, + iconUrl: 'https://github.com/misskey-dev/misskey/blob/master/packages/frontend/assets/about-icon.png?raw=true', + faviconUrl: '', + themeColor: '', + infoUpdatedAt: '', + latestRequestReceivedAt: '', + }; +} + export function userDetailed(id = 'someuserid', username = 'miskist', host = 'misskey-hub.net', name = 'Misskey User'): entities.UserDetailed { return { id, diff --git a/packages/frontend/.storybook/generate.tsx b/packages/frontend/.storybook/generate.tsx index d74c83a500..7b6c86447e 100644 --- a/packages/frontend/.storybook/generate.tsx +++ b/packages/frontend/.storybook/generate.tsx @@ -397,12 +397,13 @@ function toStories(component: string): Promise { const globs = await Promise.all([ glob('src/components/global/Mk*.vue'), glob('src/components/global/RouterView.vue'), - glob('src/components/Mk{A,B}*.vue'), + glob('src/components/Mk[A-C]*.vue'), glob('src/components/MkDigitalClock.vue'), glob('src/components/MkGalleryPostPreview.vue'), glob('src/components/MkSignupServerRules.vue'), glob('src/components/MkUserSetupDialog.vue'), glob('src/components/MkUserSetupDialog.*.vue'), + glob('src/components/MkInstanceCardMini.vue'), glob('src/components/MkInviteCode.vue'), glob('src/pages/user/home.vue'), ]); diff --git a/packages/frontend/.storybook/main.ts b/packages/frontend/.storybook/main.ts index d3822942cd..9f318cf449 100644 --- a/packages/frontend/.storybook/main.ts +++ b/packages/frontend/.storybook/main.ts @@ -15,6 +15,7 @@ const _dirname = fileURLToPath(new URL('.', import.meta.url)); const config = { stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'], + staticDirs: [{ from: '../assets', to: '/client-assets' }], addons: [ getAbsolutePath('@storybook/addon-essentials'), getAbsolutePath('@storybook/addon-interactions'), diff --git a/packages/frontend/.storybook/preview.ts b/packages/frontend/.storybook/preview.ts index 982a2979ac..d000a28232 100644 --- a/packages/frontend/.storybook/preview.ts +++ b/packages/frontend/.storybook/preview.ts @@ -3,11 +3,11 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import { FORCE_REMOUNT } from '@storybook/core-events'; +import { FORCE_RE_RENDER, FORCE_REMOUNT } from '@storybook/core-events'; import { addons } from '@storybook/preview-api'; import { type Preview, setup } from '@storybook/vue3'; import isChromatic from 'chromatic/isChromatic'; -import { initialize, mswDecorator } from 'msw-storybook-addon'; +import { initialize, mswLoader } from 'msw-storybook-addon'; import { userDetailed } from './fakes.js'; import locale from './locale.js'; import { commonHandlers, onUnhandledRequest } from './mocks.js'; @@ -16,7 +16,7 @@ import '../src/style.scss'; const appInitialized = Symbol(); -let lastStory = null; +let lastStory: string | null = null; let moduleInitialized = false; let unobserve = () => {}; let misskeyOS = null; @@ -110,7 +110,7 @@ const preview = { }).catch(() => {}); Promise.all([resetIndexedDBPromise, resetDefaultStorePromise]).then(() => { initLocalStorage(); - channel.emit(FORCE_REMOUNT, { storyId: context.id }); + channel.emit(FORCE_RE_RENDER, { storyId: context.id }); }); } const story = Story(); @@ -122,7 +122,6 @@ const preview = { } return story; }, - mswDecorator, (Story, context) => { return { setup() { @@ -137,6 +136,7 @@ const preview = { }; }, ], + loaders: [mswLoader], parameters: { controls: { exclude: /^__/, diff --git a/packages/frontend/eslint.config.js b/packages/frontend/eslint.config.js new file mode 100644 index 0000000000..dd8f03dac5 --- /dev/null +++ b/packages/frontend/eslint.config.js @@ -0,0 +1,95 @@ +import globals from 'globals'; +import tsParser from '@typescript-eslint/parser'; +import parser from 'vue-eslint-parser'; +import pluginVue from 'eslint-plugin-vue'; +import pluginMisskey from '@misskey-dev/eslint-plugin'; +import sharedConfig from '../shared/eslint.config.js'; + +export default [ + ...sharedConfig, + { + files: ['src/**/*.vue'], + ...pluginMisskey.configs.typescript, + }, + ...pluginVue.configs['flat/recommended'], + { + files: ['src/**/*.{ts,vue}'], + languageOptions: { + globals: { + ...Object.fromEntries(Object.entries(globals.node).map(([key]) => [key, 'off'])), + ...globals.browser, + + // Node.js + module: false, + require: false, + __dirname: false, + + // Misskey + _DEV_: false, + _LANGS_: false, + _VERSION_: false, + _ENV_: false, + _PERF_PREFIX_: false, + _DATA_TRANSFER_DRIVE_FILE_: false, + _DATA_TRANSFER_DRIVE_FOLDER_: false, + _DATA_TRANSFER_DECK_COLUMN_: false, + }, + parser, + parserOptions: { + extraFileExtensions: ['.vue'], + parser: tsParser, + project: ['./tsconfig.json'], + sourceType: 'module', + tsconfigRootDir: import.meta.dirname, + }, + }, + rules: { + '@typescript-eslint/no-empty-interface': ['error', { + allowSingleExtends: true, + }], + // window の禁止理由: グローバルスコープと衝突し、予期せぬ結果を招くため + // e の禁止理由: error や event など、複数のキーワードの頭文字であり分かりにくいため + 'id-denylist': ['error', 'window', 'e'], + 'no-shadow': ['warn'], + 'vue/attributes-order': ['error', { + alphabetical: false, + }], + 'vue/no-use-v-if-with-v-for': ['error', { + allowUsingIterationVar: false, + }], + 'vue/no-ref-as-operand': 'error', + 'vue/no-multi-spaces': ['error', { + ignoreProperties: false, + }], + 'vue/no-v-html': 'warn', + 'vue/order-in-components': 'error', + 'vue/html-indent': ['warn', 'tab', { + attribute: 1, + baseIndent: 0, + closeBracket: 0, + alignAttributesVertically: true, + ignores: [], + }], + 'vue/html-closing-bracket-spacing': ['warn', { + startTag: 'never', + endTag: 'never', + selfClosingTag: 'never', + }], + 'vue/multi-word-component-names': 'warn', + 'vue/require-v-for-key': 'warn', + 'vue/no-unused-components': 'warn', + 'vue/no-unused-vars': 'warn', + 'vue/no-dupe-keys': 'warn', + 'vue/valid-v-for': 'warn', + 'vue/return-in-computed-property': 'warn', + 'vue/no-setup-props-reactivity-loss': 'warn', + 'vue/max-attributes-per-line': 'off', + 'vue/html-self-closing': 'off', + 'vue/singleline-html-element-content-newline': 'off', + 'vue/v-on-event-hyphenation': ['error', 'never', { + autofix: true, + }], + 'vue/attribute-hyphenation': ['error', 'never'], + }, + }, +]; diff --git a/packages/frontend/package.json b/packages/frontend/package.json index 56b824c0c5..fbeae08aa0 100644 --- a/packages/frontend/package.json +++ b/packages/frontend/package.json @@ -22,24 +22,24 @@ "@mcaptcha/vanilla-glue": "0.1.0-alpha-3", "@misskey-dev/browser-image-resizer": "2024.1.0", "@rollup/plugin-json": "6.1.0", - "@rollup/plugin-replace": "5.0.5", + "@rollup/plugin-replace": "5.0.7", "@rollup/pluginutils": "5.1.0", - "@syuilo/aiscript": "0.18.0", + "@syuilo/aiscript": "0.19.0", "@tabler/icons-webfont": "3.3.0", "@twemoji/parser": "15.1.1", - "@vitejs/plugin-vue": "5.0.4", - "@vue/compiler-sfc": "3.4.26", - "aiscript-vscode": "github:aiscript-dev/aiscript-vscode#v0.1.9", + "@vitejs/plugin-vue": "5.0.5", + "@vue/compiler-sfc": "3.4.31", + "aiscript-vscode": "github:aiscript-dev/aiscript-vscode#v0.1.11", "astring": "1.8.6", "broadcast-channel": "7.0.0", "buraha": "0.0.1", "canvas-confetti": "1.9.3", - "chart.js": "4.4.2", + "chart.js": "4.4.3", "chartjs-adapter-date-fns": "3.0.0", "chartjs-chart-matrix": "2.0.1", "chartjs-plugin-gradient": "0.6.1", "chartjs-plugin-zoom": "2.0.1", - "chromatic": "11.3.0", + "chromatic": "11.5.4", "compare-versions": "6.1.0", "cropperjs": "2.0.0-beta.5", "date-fns": "2.30.0", @@ -55,87 +55,87 @@ "misskey-bubble-game": "workspace:*", "misskey-js": "workspace:*", "misskey-reversi": "workspace:*", - "photoswipe": "5.4.3", + "photoswipe": "5.4.4", "punycode": "2.3.1", - "rollup": "4.17.2", + "rollup": "4.18.0", "sanitize-html": "2.13.0", - "sass": "1.76.0", - "shiki": "1.4.0", + "sass": "1.77.6", + "shiki": "1.10.0", "strict-event-emitter-types": "2.0.0", "textarea-caret": "3.1.0", - "three": "0.164.1", - "throttle-debounce": "5.0.0", + "three": "0.165.0", + "throttle-debounce": "5.0.2", "tinycolor2": "1.6.0", - "tsc-alias": "1.8.8", + "tsc-alias": "1.8.10", "tsconfig-paths": "4.2.0", - "typescript": "5.4.5", - "uuid": "9.0.1", - "v-code-diff": "1.11.0", - "vite": "5.2.11", - "vue": "3.4.26", + "typescript": "5.5.3", + "uuid": "10.0.0", + "v-code-diff": "1.12.0", + "vite": "5.3.2", + "vue": "3.4.31", "vuedraggable": "next" }, "devDependencies": { - "@misskey-dev/eslint-plugin": "1.0.0", "@misskey-dev/summaly": "5.1.0", - "@storybook/addon-actions": "8.0.9", - "@storybook/addon-essentials": "8.0.9", - "@storybook/addon-interactions": "8.0.9", - "@storybook/addon-links": "8.0.9", - "@storybook/addon-mdx-gfm": "8.0.9", - "@storybook/addon-storysource": "8.0.9", - "@storybook/blocks": "8.0.9", - "@storybook/components": "8.0.9", - "@storybook/core-events": "8.0.9", - "@storybook/manager-api": "8.0.9", - "@storybook/preview-api": "8.0.9", - "@storybook/react": "8.0.9", - "@storybook/react-vite": "8.0.9", - "@storybook/test": "8.0.9", - "@storybook/theming": "8.0.9", - "@storybook/types": "8.0.9", - "@storybook/vue3": "8.0.9", - "@storybook/vue3-vite": "8.0.9", - "@testing-library/vue": "8.0.3", + "@storybook/addon-actions": "8.1.11", + "@storybook/addon-essentials": "8.1.11", + "@storybook/addon-interactions": "8.1.11", + "@storybook/addon-links": "8.1.11", + "@storybook/addon-mdx-gfm": "8.1.11", + "@storybook/addon-storysource": "8.1.11", + "@storybook/blocks": "8.1.11", + "@storybook/components": "8.1.11", + "@storybook/core-events": "8.1.11", + "@storybook/manager-api": "8.1.11", + "@storybook/preview-api": "8.1.11", + "@storybook/react": "8.1.11", + "@storybook/react-vite": "8.1.11", + "@storybook/test": "8.1.11", + "@storybook/theming": "8.1.11", + "@storybook/types": "8.1.11", + "@storybook/vue3": "8.1.11", + "@storybook/vue3-vite": "8.1.11", + "@testing-library/vue": "8.1.0", "@types/escape-regexp": "0.0.3", "@types/estree": "1.0.5", "@types/matter-js": "0.19.6", - "@types/micromatch": "4.0.7", - "@types/node": "20.12.7", + "@types/micromatch": "4.0.9", + "@types/node": "20.14.9", "@types/punycode": "2.1.4", "@types/sanitize-html": "2.11.0", + "@types/seedrandom": "3.0.8", "@types/throttle-debounce": "5.0.2", "@types/tinycolor2": "1.4.6", - "@types/uuid": "9.0.8", + "@types/uuid": "10.0.0", "@types/ws": "8.5.10", - "@typescript-eslint/eslint-plugin": "7.7.1", - "@typescript-eslint/parser": "7.7.1", - "@vitest/coverage-v8": "0.34.6", - "@vue/runtime-core": "3.4.26", - "acorn": "8.11.3", + "@typescript-eslint/eslint-plugin": "7.15.0", + "@typescript-eslint/parser": "7.15.0", + "@vitest/coverage-v8": "1.6.0", + "@vue/runtime-core": "3.4.31", + "acorn": "8.12.0", "cross-env": "7.0.3", - "cypress": "13.8.1", - "eslint": "8.57.0", + "cypress": "13.13.0", "eslint-plugin-import": "2.29.1", - "eslint-plugin-vue": "9.25.0", + "eslint-plugin-vue": "9.26.0", "fast-glob": "3.3.2", "happy-dom": "10.0.3", "intersection-observer": "0.12.2", - "micromatch": "4.0.5", - "msw": "2.2.14", - "msw-storybook-addon": "2.0.1", - "nodemon": "3.1.0", - "prettier": "3.2.5", + "micromatch": "4.0.7", + "msw": "2.3.1", + "msw-storybook-addon": "2.0.2", + "nodemon": "3.1.4", + "prettier": "3.3.2", "react": "18.3.1", "react-dom": "18.3.1", - "start-server-and-test": "2.0.3", - "storybook": "8.0.9", + "seedrandom": "3.0.5", + "start-server-and-test": "2.0.4", + "storybook": "8.1.11", "storybook-addon-misskey-theme": "github:misskey-dev/storybook-addon-misskey-theme", "vite-plugin-turbosnap": "1.0.3", - "vitest": "0.34.6", + "vitest": "1.6.0", "vitest-fetch-mock": "0.2.2", - "vue-component-type-helpers": "2.0.16", - "vue-eslint-parser": "9.4.2", - "vue-tsc": "2.0.16" + "vue-component-type-helpers": "2.0.24", + "vue-eslint-parser": "9.4.3", + "vue-tsc": "2.0.24" } } diff --git a/packages/frontend/src/account.ts b/packages/frontend/src/account.ts index 7f20e0b1a2..4172016f89 100644 --- a/packages/frontend/src/account.ts +++ b/packages/frontend/src/account.ts @@ -120,7 +120,7 @@ function fetchAccount(token: string, id?: string, forceShowDialog?: boolean): Pr res.json().then(done2, fail2); })) .then(async res => { - if (res.error) { + if ('error' in res) { if (res.error.id === 'a8c724b3-6e9c-4b46-b1a8-bc3ed6258370') { // SUSPENDED if (forceShowDialog || $i && (token === $i.token || id === $i.id)) { @@ -184,10 +184,12 @@ export async function refreshAccount() { export async function login(token: Account['token'], redirect?: string) { const showing = ref(true); - popup(defineAsyncComponent(() => import('@/components/MkWaitingDialog.vue')), { + const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkWaitingDialog.vue')), { success: false, showing: showing, - }, {}, 'closed'); + }, { + closed: () => dispose(), + }); if (_DEV_) console.log('logging as token ', token); const me = await fetchAccount(token, undefined, true) .catch(reason => { @@ -223,21 +225,23 @@ export async function openAccountMenu(opts: { if (!$i) return; function showSigninDialog() { - popup(defineAsyncComponent(() => import('@/components/MkSigninDialog.vue')), {}, { + const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkSigninDialog.vue')), {}, { done: res => { addAccount(res.id, res.i); success(); }, - }, 'closed'); + closed: () => dispose(), + }); } function createAccount() { - popup(defineAsyncComponent(() => import('@/components/MkSignupDialog.vue')), {}, { + const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkSignupDialog.vue')), {}, { done: res => { addAccount(res.id, res.i); switchAccountWithToken(res.i); }, - }, 'closed'); + closed: () => dispose(), + }); } async function switchAccount(account: Misskey.entities.UserDetailed) { diff --git a/packages/frontend/src/boot/main-boot.ts b/packages/frontend/src/boot/main-boot.ts index 5cb19f388a..2a549d1e8b 100644 --- a/packages/frontend/src/boot/main-boot.ts +++ b/packages/frontend/src/boot/main-boot.ts @@ -5,6 +5,7 @@ import { createApp, defineAsyncComponent, markRaw } from 'vue'; import { common } from './common.js'; +import type * as Misskey from 'misskey-js'; import { ui } from '@/config.js'; import { i18n } from '@/i18n.js'; import { alert, confirm, popup, post, toast } from '@/os.js'; @@ -13,7 +14,6 @@ import * as sound from '@/scripts/sound.js'; import { $i, signout, updateAccount } from '@/account.js'; import { instance } from '@/instance.js'; import { ColdDeviceStorage, defaultStore } from '@/store.js'; -import { makeHotkey } from '@/scripts/hotkey.js'; import { reactionPicker } from '@/scripts/reaction-picker.js'; import { miLocalStorage } from '@/local-storage.js'; import { claimAchievement, claimedAchievements } from '@/scripts/achievements.js'; @@ -21,6 +21,7 @@ import { initializeSw } from '@/scripts/initialize-sw.js'; import { deckStore } from '@/ui/deck/deck-store.js'; import { emojiPicker } from '@/scripts/emoji-picker.js'; import { mainRouter } from '@/router/main.js'; +import { type Keymap, makeHotkey } from '@/scripts/hotkey.js'; export async function mainBoot() { const { isClientUpdated } = await common(() => createApp( @@ -35,7 +36,9 @@ export async function mainBoot() { emojiPicker.init(); if (isClientUpdated && $i) { - popup(defineAsyncComponent(() => import('@/components/MkUpdated.vue')), {}, {}, 'closed'); + const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkUpdated.vue')), {}, { + closed: () => dispose(), + }); } const stream = useStream(); @@ -67,14 +70,6 @@ export async function mainBoot() { }); } - const hotkeys = { - 'd': (): void => { - defaultStore.set('darkMode', !defaultStore.state.darkMode); - }, - 's': (): void => { - mainRouter.push('/search'); - }, - }; try { if (defaultStore.state.enableSeasonalScreenEffect) { const month = new Date().getMonth() + 1; @@ -96,36 +91,41 @@ export async function mainBoot() { }).render(); } } - } + } } catch (error) { // console.error(error); console.error('Failed to initialise the seasonal screen effect canvas context:', error); } if ($i) { - // only add post shortcuts if logged in - hotkeys['p|n'] = post; - defaultStore.loaded.then(() => { if (defaultStore.state.accountSetupWizard !== -1) { - popup(defineAsyncComponent(() => import('@/components/MkUserSetupDialog.vue')), {}, {}, 'closed'); + const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkUserSetupDialog.vue')), {}, { + closed: () => dispose(), + }); } }); for (const announcement of ($i.unreadAnnouncements ?? []).filter(x => x.display === 'dialog')) { - popup(defineAsyncComponent(() => import('@/components/MkAnnouncementDialog.vue')), { + const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkAnnouncementDialog.vue')), { announcement, - }, {}, 'closed'); + }, { + closed: () => dispose(), + }); } - stream.on('announcementCreated', (ev) => { + function onAnnouncementCreated (ev: { announcement: Misskey.entities.Announcement }) { const announcement = ev.announcement; if (announcement.display === 'dialog') { - popup(defineAsyncComponent(() => import('@/components/MkAnnouncementDialog.vue')), { + const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkAnnouncementDialog.vue')), { announcement, - }, {}, 'closed'); + }, { + closed: () => dispose(), + }); } - }); + } + + stream.on('announcementCreated', onAnnouncementCreated); if ($i.isDeleted) { alert({ @@ -247,13 +247,17 @@ export async function mainBoot() { const neverShowDonationInfo = miLocalStorage.getItem('neverShowDonationInfo'); if (neverShowDonationInfo !== 'true' && (createdAt.getTime() < (Date.now() - (1000 * 60 * 60 * 24 * 3))) && !location.pathname.startsWith('/miauth')) { if (latestDonationInfoShownAt == null || (new Date(latestDonationInfoShownAt).getTime() < (Date.now() - (1000 * 60 * 60 * 24 * 30)))) { - popup(defineAsyncComponent(() => import('@/components/MkDonation.vue')), {}, {}, 'closed'); + const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkDonation.vue')), {}, { + closed: () => dispose(), + }); } } const modifiedVersionMustProminentlyOfferInAgplV3Section13Read = miLocalStorage.getItem('modifiedVersionMustProminentlyOfferInAgplV3Section13Read'); if (modifiedVersionMustProminentlyOfferInAgplV3Section13Read !== 'true' && instance.repositoryUrl !== 'https://github.com/misskey-dev/misskey') { - popup(defineAsyncComponent(() => import('@/components/MkSourceCodeAvailablePopup.vue')), {}, {}, 'closed'); + const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkSourceCodeAvailablePopup.vue')), {}, { + closed: () => dispose(), + }); } if ('Notification' in window) { @@ -314,6 +318,9 @@ export async function mainBoot() { updateAccount({ hasUnreadAnnouncement: false }); }); + // 個人宛てお知らせが発行されたとき + main.on('announcementCreated', onAnnouncementCreated); + // トークンが再生成されたとき // このままではMisskeyが利用できないので強制的にサインアウトさせる main.on('myTokenRegenerated', () => { @@ -322,7 +329,19 @@ export async function mainBoot() { } // shortcut - document.addEventListener('keydown', makeHotkey(hotkeys)); + const keymap = { + 'p|n': () => { + if ($i == null) return; + post(); + }, + 'd': () => { + defaultStore.set('darkMode', !defaultStore.state.darkMode); + }, + 's': () => { + mainRouter.push('/search'); + }, + } as const satisfies Keymap; + document.addEventListener('keydown', makeHotkey(keymap), { passive: false }); initializeSw(); } diff --git a/packages/frontend/src/components/MkAchievements.vue b/packages/frontend/src/components/MkAchievements.vue index 5d103fa789..c8134416b5 100644 --- a/packages/frontend/src/components/MkAchievements.vue +++ b/packages/frontend/src/components/MkAchievements.vue @@ -153,7 +153,7 @@ onMounted(() => { background: linear-gradient(0deg, #ffee20, #eb7018); } - &:before { + &::before { content: ""; display: block; position: absolute; @@ -173,7 +173,7 @@ onMounted(() => { background: linear-gradient(0deg, #e1e1e1, #7c7c7c); } - &:before { + &::before { content: ""; display: block; position: absolute; diff --git a/packages/frontend/src/components/MkButton.vue b/packages/frontend/src/components/MkButton.vue index 3489255b91..9560efb7d9 100644 --- a/packages/frontend/src/components/MkButton.vue +++ b/packages/frontend/src/components/MkButton.vue @@ -11,6 +11,7 @@ SPDX-License-Identifier: AGPL-3.0-only :type="type" :name="name" :value="value" + :disabled="disabled" @click="emit('click', $event)" @mousedown="onMousedown" > @@ -55,6 +56,7 @@ const props = defineProps<{ asLike?: boolean; name?: string; value?: string; + disabled?: boolean; }>(); const emit = defineEmits<{ @@ -248,7 +250,6 @@ function onMousedown(evt: MouseEvent): void { } &:focus-visible { - outline: solid 2px var(--focus); outline-offset: 2px; } diff --git a/packages/frontend/src/components/MkCaptcha.vue b/packages/frontend/src/components/MkCaptcha.vue index c64bb47e77..c5b6e0caed 100644 --- a/packages/frontend/src/components/MkCaptcha.vue +++ b/packages/frontend/src/components/MkCaptcha.vue @@ -104,7 +104,6 @@ async function requestRender() { }); } else if (props.provider === 'mcaptcha' && props.instanceUrl && props.sitekey) { const { default: Widget } = await import('@mcaptcha/vanilla-glue'); - // @ts-expect-error avoid typecheck error new Widget({ siteKey: { instanceUrl: new URL(props.instanceUrl), diff --git a/packages/frontend/src/components/MkChannelFollowButton.stories.impl.ts b/packages/frontend/src/components/MkChannelFollowButton.stories.impl.ts new file mode 100644 index 0000000000..b9770670dc --- /dev/null +++ b/packages/frontend/src/components/MkChannelFollowButton.stories.impl.ts @@ -0,0 +1,71 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +/* eslint-disable @typescript-eslint/explicit-function-return-type */ +/* eslint-disable import/no-default-export */ +import { StoryObj } from '@storybook/vue3'; +import { HttpResponse, http } from 'msw'; +import { action } from '@storybook/addon-actions'; +import { expect, userEvent, within } from '@storybook/test'; +import { channel } from '../../.storybook/fakes.js'; +import { commonHandlers } from '../../.storybook/mocks.js'; +import MkChannelFollowButton from './MkChannelFollowButton.vue'; +import { i18n } from '@/i18n.js'; + +function sleep(ms: number) { + return new Promise(resolve => setTimeout(resolve, ms)); +} + +export const Default = { + render(args) { + return { + components: { + MkChannelFollowButton, + }, + setup() { + return { + args, + }; + }, + computed: { + props() { + return { + ...this.args, + }; + }, + }, + template: '', + }; + }, + args: { + channel: channel(), + full: true, + }, + async play({ canvasElement }) { + const canvas = within(canvasElement); + const buttonElement = canvas.getByRole('button'); + await expect(buttonElement).toHaveTextContent(i18n.ts.follow); + await userEvent.click(buttonElement); + await sleep(1000); + await expect(buttonElement).toHaveTextContent(i18n.ts.unfollow); + await userEvent.click(buttonElement); + }, + parameters: { + layout: 'centered', + msw: { + handlers: [ + ...commonHandlers, + http.post('/api/channels/follow', async ({ request }) => { + action('POST /api/channels/follow')(await request.json()); + return HttpResponse.json({}); + }), + http.post('/api/channels/unfollow', async ({ request }) => { + action('POST /api/channels/unfollow')(await request.json()); + return HttpResponse.json({}); + }), + ], + }, + }, +} satisfies StoryObj; diff --git a/packages/frontend/src/components/MkChannelFollowButton.vue b/packages/frontend/src/components/MkChannelFollowButton.vue index 6b1b380e41..35dc3ad4bf 100644 --- a/packages/frontend/src/components/MkChannelFollowButton.vue +++ b/packages/frontend/src/components/MkChannelFollowButton.vue @@ -26,17 +26,18 @@ SPDX-License-Identifier: AGPL-3.0-only diff --git a/packages/frontend/src/components/MkDrive.file.vue b/packages/frontend/src/components/MkDrive.file.vue index 4106b0a436..90284890a5 100644 --- a/packages/frontend/src/components/MkDrive.file.vue +++ b/packages/frontend/src/components/MkDrive.file.vue @@ -115,14 +115,14 @@ function onDragend() { background: rgba(#000, 0.05); > .label { - &:before, - &:after { + &::before, + &::after { background: #0b65a5; } &.red { - &:before, - &:after { + &::before, + &::after { background: #c12113; } } @@ -133,14 +133,14 @@ function onDragend() { background: rgba(#000, 0.1); > .label { - &:before, - &:after { + &::before, + &::after { background: #0b588c; } &.red { - &:before, - &:after { + &::before, + &::after { background: #ce2212; } } @@ -159,8 +159,8 @@ function onDragend() { } > .label { - &:before, - &:after { + &::before, + &::after { display: none; } } @@ -181,8 +181,8 @@ function onDragend() { left: 0; pointer-events: none; - &:before, - &:after { + &::before, + &::after { content: ""; display: block; position: absolute; @@ -190,14 +190,14 @@ function onDragend() { background: #0c7ac9; } - &:before { + &::before { top: 0; left: 57px; width: 28px; height: 8px; } - &:after { + &::after { top: 57px; left: 0; width: 8px; @@ -205,8 +205,8 @@ function onDragend() { } &.red { - &:before, - &:after { + &::before, + &::after { background: #c12113; } } diff --git a/packages/frontend/src/components/MkDrive.folder.vue b/packages/frontend/src/components/MkDrive.folder.vue index 8da0d78f35..c940596cde 100644 --- a/packages/frontend/src/components/MkDrive.folder.vue +++ b/packages/frontend/src/components/MkDrive.folder.vue @@ -39,7 +39,7 @@ import { misskeyApi } from '@/scripts/misskey-api.js'; import { i18n } from '@/i18n.js'; import { defaultStore } from '@/store.js'; import { claimAchievement } from '@/scripts/achievements.js'; -import copyToClipboard from '@/scripts/copy-to-clipboard.js'; +import { copyToClipboard } from '@/scripts/copy-to-clipboard.js'; import { MenuItem } from '@/types/menu.js'; const props = withDefaults(defineProps<{ @@ -257,10 +257,11 @@ function onContextmenu(ev: MouseEvent) { text: i18n.ts.openInWindow, icon: 'ti ti-app-window', action: () => { - os.popup(defineAsyncComponent(() => import('@/components/MkDriveWindow.vue')), { + const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkDriveWindow.vue')), { initialFolder: props.folder, }, { - }, 'closed'); + closed: () => dispose(), + }); }, }, { type: 'divider' }, { text: i18n.ts.rename, @@ -295,7 +296,7 @@ function onContextmenu(ev: MouseEvent) { cursor: pointer; &.draghover { - &:after { + &::after { content: ""; pointer-events: none; position: absolute; diff --git a/packages/frontend/src/components/MkEmojiPicker.vue b/packages/frontend/src/components/MkEmojiPicker.vue index 8a6bef54d8..4a3ed69f47 100644 --- a/packages/frontend/src/components/MkEmojiPicker.vue +++ b/packages/frontend/src/components/MkEmojiPicker.vue @@ -5,7 +5,19 @@ SPDX-License-Identifier: AGPL-3.0-only diff --git a/packages/frontend/src/components/MkFlashPreview.vue b/packages/frontend/src/components/MkFlashPreview.vue index c5dd877971..6783804cc5 100644 --- a/packages/frontend/src/components/MkFlashPreview.vue +++ b/packages/frontend/src/components/MkFlashPreview.vue @@ -4,7 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only --> @@ -151,22 +151,26 @@ function drawImage(bitmap: CanvasImageSource) { } function drawAvg() { - if (!canvas.value || !props.hash) return; + if (!canvas.value) return; + + const color = (props.hash != null && extractAvgColorFromBlurhash(props.hash)) || '#888'; const ctx = canvas.value.getContext('2d'); if (!ctx) return; // avgColorでお茶をにごす ctx.beginPath(); - ctx.fillStyle = extractAvgColorFromBlurhash(props.hash) ?? '#888'; + ctx.fillStyle = color; ctx.fillRect(0, 0, canvasWidth.value, canvasHeight.value); } async function draw() { - if (props.hash == null) return; + if (import.meta.env.MODE === 'test' && props.hash == null) return; drawAvg(); + if (props.hash == null) return; + if (props.onlyAvgColor) return; const work = await canvasPromise; diff --git a/packages/frontend/src/components/MkInstanceCardMini.stories.impl.ts b/packages/frontend/src/components/MkInstanceCardMini.stories.impl.ts new file mode 100644 index 0000000000..9e8de9d878 --- /dev/null +++ b/packages/frontend/src/components/MkInstanceCardMini.stories.impl.ts @@ -0,0 +1,65 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +/* eslint-disable @typescript-eslint/explicit-function-return-type */ +import { StoryObj } from '@storybook/vue3'; +import { HttpResponse, http } from 'msw'; +import { federationInstance } from '../../.storybook/fakes.js'; +import { commonHandlers } from '../../.storybook/mocks.js'; +import { getChartResolver } from '../../.storybook/charts.js'; +import MkInstanceCardMini from './MkInstanceCardMini.vue'; + +export const Default = { + render(args) { + return { + components: { + MkInstanceCardMini, + }, + setup() { + return { + args, + }; + }, + computed: { + props() { + return { + ...this.args, + }; + }, + }, + template: '', + }; + }, + args: { + instance: federationInstance(), + }, + parameters: { + layout: 'centered', + msw: { + handlers: [ + ...commonHandlers, + http.get('/undefined/preview.webp', async ({ request }) => { + const urlStr = new URL(request.url).searchParams.get('url'); + if (urlStr == null) { + return new HttpResponse(null, { status: 404 }); + } + const url = new URL(urlStr); + + if (url.href.startsWith('https://github.com/misskey-dev/misskey/blob/master/packages/frontend/assets/')) { + const image = await (await fetch(`client-assets/${url.pathname.split('/').pop()}`)).blob(); + return new HttpResponse(image, { + headers: { + 'Content-Type': 'image/jpeg', + }, + }); + } else { + return new HttpResponse(null, { status: 404 }); + } + }), + http.get('/api/charts/instance', getChartResolver(['requests.received'])), + ], + }, + }, +} satisfies StoryObj; diff --git a/packages/frontend/src/components/MkInstanceCardMini.vue b/packages/frontend/src/components/MkInstanceCardMini.vue index e26aef0f69..17c974dd04 100644 --- a/packages/frontend/src/components/MkInstanceCardMini.vue +++ b/packages/frontend/src/components/MkInstanceCardMini.vue @@ -29,8 +29,8 @@ const chartValues = ref(null); misskeyApiGet('charts/instance', { host: props.instance.host, limit: 16 + 1, span: 'day' }).then(res => { // 今日のぶんの値はまだ途中の値であり、それも含めると大抵の場合前日よりも下降しているようなグラフになってしまうため今日は弾く - res['requests.received'].splice(0, 1); - chartValues.value = res['requests.received']; + res.requests.received.splice(0, 1); + chartValues.value = res.requests.received; }); function getInstanceIcon(instance): string { diff --git a/packages/frontend/src/components/MkInviteCode.vue b/packages/frontend/src/components/MkInviteCode.vue index 1c6f412dc1..de51a98789 100644 --- a/packages/frontend/src/components/MkInviteCode.vue +++ b/packages/frontend/src/components/MkInviteCode.vue @@ -62,7 +62,7 @@ import { computed } from 'vue'; import * as Misskey from 'misskey-js'; import MkFolder from '@/components/MkFolder.vue'; import MkButton from '@/components/MkButton.vue'; -import copyToClipboard from '@/scripts/copy-to-clipboard.js'; +import { copyToClipboard } from '@/scripts/copy-to-clipboard.js'; import { i18n } from '@/i18n.js'; import * as os from '@/os.js'; diff --git a/packages/frontend/src/components/MkKeyValue.vue b/packages/frontend/src/components/MkKeyValue.vue index 20b1ef2be2..50c9e16e5e 100644 --- a/packages/frontend/src/components/MkKeyValue.vue +++ b/packages/frontend/src/components/MkKeyValue.vue @@ -17,7 +17,7 @@ SPDX-License-Identifier: AGPL-3.0-only diff --git a/packages/frontend/src/components/MkMediaAudio.vue b/packages/frontend/src/components/MkMediaAudio.vue index 5d2edf467e..a080550ddf 100644 --- a/packages/frontend/src/components/MkMediaAudio.vue +++ b/packages/frontend/src/components/MkMediaAudio.vue @@ -15,7 +15,7 @@ SPDX-License-Identifier: AGPL-3.0-only @contextmenu.stop @keydown.stop > -
-
{{ hms(elapsedTimeMs) }}
- @@ -80,6 +94,7 @@ import type { MenuItem } from '@/types/menu.js'; import { defaultStore } from '@/store.js'; import { i18n } from '@/i18n.js'; import * as os from '@/os.js'; +import { type Keymap } from '@/scripts/hotkey.js'; import bytes from '@/filters/bytes.js'; import { hms } from '@/filters/hms.js'; import MkMediaRange from '@/components/MkMediaRange.vue'; @@ -90,32 +105,44 @@ const props = defineProps<{ }>(); const keymap = { - 'up': () => { - if (hasFocus() && audioEl.value) { - volume.value = Math.min(volume.value + 0.1, 1); - } + 'up': { + allowRepeat: true, + callback: () => { + if (hasFocus() && audioEl.value) { + volume.value = Math.min(volume.value + 0.1, 1); + } + }, }, - 'down': () => { - if (hasFocus() && audioEl.value) { - volume.value = Math.max(volume.value - 0.1, 0); - } + 'down': { + allowRepeat: true, + callback: () => { + if (hasFocus() && audioEl.value) { + volume.value = Math.max(volume.value - 0.1, 0); + } + }, }, - 'left': () => { - if (hasFocus() && audioEl.value) { - audioEl.value.currentTime = Math.max(audioEl.value.currentTime - 5, 0); - } + 'left': { + allowRepeat: true, + callback: () => { + if (hasFocus() && audioEl.value) { + audioEl.value.currentTime = Math.max(audioEl.value.currentTime - 5, 0); + } + }, }, - 'right': () => { - if (hasFocus() && audioEl.value) { - audioEl.value.currentTime = Math.min(audioEl.value.currentTime + 5, audioEl.value.duration); - } + 'right': { + allowRepeat: true, + callback: () => { + if (hasFocus() && audioEl.value) { + audioEl.value.currentTime = Math.min(audioEl.value.currentTime + 5, audioEl.value.duration); + } + }, }, 'space': () => { if (hasFocus()) { togglePlayPause(); } }, -}; +} as const satisfies Keymap; // PlayerElもしくはその子要素にフォーカスがあるかどうか function hasFocus() { @@ -126,9 +153,21 @@ function hasFocus() { const playerEl = shallowRef(); const audioEl = shallowRef(); -// eslint-disable-next-line vue/no-setup-props-destructure +// eslint-disable-next-line vue/no-setup-props-reactivity-loss const hide = ref((defaultStore.state.nsfw === 'force' || defaultStore.state.dataSaver.media) ? true : (props.audio.isSensitive && defaultStore.state.nsfw !== 'ignore')); +async function show() { + if (props.audio.isSensitive && defaultStore.state.confirmWhenRevealingSensitiveMedia) { + const { canceled } = await os.confirm({ + type: 'question', + text: i18n.ts.sensitiveMediaRevealConfirm, + }); + if (canceled) return; + } + + hide.value = false; +} + // Menu const menuShowing = ref(false); @@ -358,7 +397,7 @@ onDeactivated(() => { border-radius: var(--radius); overflow: clip; - &:focus { + &:focus-visible { outline: none; } } @@ -424,6 +463,10 @@ onDeactivated(() => { color: var(--accent); background-color: var(--accentedBg); } + + &:focus-visible { + outline: none; + } } } diff --git a/packages/frontend/src/components/MkMediaBanner.vue b/packages/frontend/src/components/MkMediaBanner.vue index a219848b7f..11995e1f3b 100644 --- a/packages/frontend/src/components/MkMediaBanner.vue +++ b/packages/frontend/src/components/MkMediaBanner.vue @@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only diff --git a/packages/frontend/src/components/MkRadio.vue b/packages/frontend/src/components/MkRadio.vue index 6676e3bf5b..22fc86723e 100644 --- a/packages/frontend/src/components/MkRadio.vue +++ b/packages/frontend/src/components/MkRadio.vue @@ -9,6 +9,7 @@ SPDX-License-Identifier: AGPL-3.0-only :class="[$style.root, { [$style.disabled]: disabled, [$style.checked]: checked }]" :aria-checked="checked" :aria-disabled="disabled" + role="checkbox" @click="toggle" > .button { border-color: var(--accent); - &:after { + &::after { background-color: var(--accent); transform: scale(1); opacity: 1; @@ -104,7 +110,7 @@ function toggle(): void { border-radius: 100%; transition: inherit; - &:after { + &::after { content: ''; display: block; position: absolute; diff --git a/packages/frontend/src/components/MkRange.vue b/packages/frontend/src/components/MkRange.vue index 15f8128e98..1eae642937 100644 --- a/packages/frontend/src/components/MkRange.vue +++ b/packages/frontend/src/components/MkRange.vue @@ -101,17 +101,19 @@ const steps = computed(() => { } }); -const onMousedown = (ev: MouseEvent | TouchEvent) => { +function onMousedown(ev: MouseEvent | TouchEvent) { ev.preventDefault(); const tooltipShowing = ref(true); - os.popup(defineAsyncComponent(() => import('@/components/MkTooltip.vue')), { + const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkTooltip.vue')), { showing: tooltipShowing, text: computed(() => { return props.textConverter(finalValue.value); }), targetElement: thumbEl, - }, {}, 'closed'); + }, { + closed: () => dispose(), + }); const style = document.createElement('style'); style.appendChild(document.createTextNode('* { cursor: grabbing !important; } body * { pointer-events: none !important; }')); @@ -152,7 +154,7 @@ const onMousedown = (ev: MouseEvent | TouchEvent) => { window.addEventListener('touchmove', onDrag); window.addEventListener('mouseup', onMouseup, { once: true }); window.addEventListener('touchend', onMouseup, { once: true }); -}; +} diff --git a/packages/frontend/src/components/MkSigninDialog.vue b/packages/frontend/src/components/MkSigninDialog.vue index 33355bb99e..524c62b4d3 100644 --- a/packages/frontend/src/components/MkSigninDialog.vue +++ b/packages/frontend/src/components/MkSigninDialog.vue @@ -6,21 +6,22 @@ SPDX-License-Identifier: AGPL-3.0-only @@ -72,7 +75,13 @@ const toggle = () => { height: 0; opacity: 0; margin: 0; + + &:focus-visible ~ .toggle { + outline: 2px solid var(--focus); + outline-offset: 2px; + } } + .body { margin-left: 12px; margin-top: 2px; diff --git a/packages/frontend/src/components/MkSystemWebhookEditor.impl.ts b/packages/frontend/src/components/MkSystemWebhookEditor.impl.ts new file mode 100644 index 0000000000..76f54e8d37 --- /dev/null +++ b/packages/frontend/src/components/MkSystemWebhookEditor.impl.ts @@ -0,0 +1,45 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { defineAsyncComponent } from 'vue'; +import * as os from '@/os.js'; + +export type SystemWebhookEventType = 'abuseReport' | 'abuseReportResolved'; + +export type MkSystemWebhookEditorProps = { + mode: 'create' | 'edit'; + id?: string; + requiredEvents?: SystemWebhookEventType[]; +}; + +export type MkSystemWebhookResult = { + id?: string; + isActive: boolean; + name: string; + on: SystemWebhookEventType[]; + url: string; + secret: string; +}; + +export async function showSystemWebhookEditorDialog(props: MkSystemWebhookEditorProps): Promise { + const { dispose, result } = await new Promise<{ dispose: () => void, result: MkSystemWebhookResult | null }>(async resolve => { + const { dispose: _dispose } = os.popup( + defineAsyncComponent(() => import('@/components/MkSystemWebhookEditor.vue')), + props, + { + submitted: (ev: MkSystemWebhookResult) => { + resolve({ dispose: _dispose, result: ev }); + }, + closed: () => { + resolve({ dispose: _dispose, result: null }); + }, + }, + ); + }); + + dispose(); + + return result; +} diff --git a/packages/frontend/src/components/MkSystemWebhookEditor.vue b/packages/frontend/src/components/MkSystemWebhookEditor.vue new file mode 100644 index 0000000000..007d841f00 --- /dev/null +++ b/packages/frontend/src/components/MkSystemWebhookEditor.vue @@ -0,0 +1,217 @@ + + + + + + + diff --git a/packages/frontend/src/components/MkTutorialDialog.PostNote.vue b/packages/frontend/src/components/MkTutorialDialog.PostNote.vue index e1d88b5e5c..27483cc7c2 100644 --- a/packages/frontend/src/components/MkTutorialDialog.PostNote.vue +++ b/packages/frontend/src/components/MkTutorialDialog.PostNote.vue @@ -105,7 +105,7 @@ const exampleCWNote = reactive({ font-weight: bold; text-align: left; - &:before { + &::before { content: ""; display: block; width: calc(100% - 38px); diff --git a/packages/frontend/src/components/MkTutorialDialog.Sensitive.vue b/packages/frontend/src/components/MkTutorialDialog.Sensitive.vue index 7ae48dcd15..d8d4b5aab7 100644 --- a/packages/frontend/src/components/MkTutorialDialog.Sensitive.vue +++ b/packages/frontend/src/components/MkTutorialDialog.Sensitive.vue @@ -115,7 +115,7 @@ const exampleNote = reactive({ font-weight: bold; text-align: left; - &:before { + &::before { content: ""; display: block; width: calc(100% - 38px); diff --git a/packages/frontend/src/components/MkTutorialDialog.Timeline.vue b/packages/frontend/src/components/MkTutorialDialog.Timeline.vue index 57f26e86a7..6f2930ebc9 100644 --- a/packages/frontend/src/components/MkTutorialDialog.Timeline.vue +++ b/packages/frontend/src/components/MkTutorialDialog.Timeline.vue @@ -56,7 +56,7 @@ import { i18n } from '@/i18n.js'; font-weight: bold; text-align: left; - &:before { + &::before { content: ""; display: block; width: calc(100% - 38px); diff --git a/packages/frontend/src/components/MkTutorialDialog.vue b/packages/frontend/src/components/MkTutorialDialog.vue index d2711e4ec5..9adc8d466c 100644 --- a/packages/frontend/src/components/MkTutorialDialog.vue +++ b/packages/frontend/src/components/MkTutorialDialog.vue @@ -172,7 +172,7 @@ const emit = defineEmits<{ const dialog = shallowRef>(); -// eslint-disable-next-line vue/no-setup-props-destructure +// eslint-disable-next-line vue/no-setup-props-reactivity-loss const page = ref(props.initialPage ?? 0); watch(page, (to) => { diff --git a/packages/frontend/src/components/MkUrlPreview.vue b/packages/frontend/src/components/MkUrlPreview.vue index 6954f1f6ff..c868a22045 100644 --- a/packages/frontend/src/components/MkUrlPreview.vue +++ b/packages/frontend/src/components/MkUrlPreview.vue @@ -15,7 +15,7 @@ SPDX-License-Identifier: AGPL-3.0-only scrolling="no" :allow="player.allow == null ? 'autoplay;encrypted-media;fullscreen' : player.allow.filter(x => ['autoplay', 'clipboard-write', 'fullscreen', 'encrypted-media', 'picture-in-picture', 'web-share'].includes(x)).join(';')" :class="$style.playerIframe" - :src="player.url + (player.url.match(/\?/) ? '&autoplay=1&auto_play=1' : '?autoplay=1&auto_play=1')" + :src="transformPlayerUrl(player.url)" :style="{ border: 0 }" > invalid url @@ -91,6 +91,7 @@ import * as os from '@/os.js'; import { deviceKind } from '@/scripts/device-kind.js'; import MkButton from '@/components/MkButton.vue'; import { versatileLang } from '@/scripts/intl-const.js'; +import { transformPlayerUrl } from '@/scripts/player-url-transform.js'; import { defaultStore } from '@/store.js'; type SummalyResult = Awaited>; @@ -188,11 +189,13 @@ function adjustTweetHeight(message: any) { if (height) tweetHeight.value = height; } -const openPlayer = (): void => { - os.popup(defineAsyncComponent(() => import('@/components/MkYouTubePlayer.vue')), { +function openPlayer(): void { + const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkYouTubePlayer.vue')), { url: requestUrl.href, + }, { + // TODO }); -}; +} (window as any).addEventListener('message', adjustTweetHeight); diff --git a/packages/frontend/src/components/MkUserInfo.vue b/packages/frontend/src/components/MkUserInfo.vue index f247ba8fdd..f0b9606590 100644 --- a/packages/frontend/src/components/MkUserInfo.vue +++ b/packages/frontend/src/components/MkUserInfo.vue @@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only @@ -41,6 +41,8 @@ import { userPage } from '@/filters/user.js'; import { i18n } from '@/i18n.js'; import { $i } from '@/account.js'; import { isFollowingVisibleForMe, isFollowersVisibleForMe } from '@/scripts/isFfVisibleForMe.js'; +import { getStaticImageUrl } from '@/scripts/media-proxy.js'; +import { defaultStore } from '@/store.js'; defineProps<{ user: Misskey.entities.UserDetailed; diff --git a/packages/frontend/src/components/MkUserPopup.vue b/packages/frontend/src/components/MkUserPopup.vue index 41b27a1afb..ea1241002e 100644 --- a/packages/frontend/src/components/MkUserPopup.vue +++ b/packages/frontend/src/components/MkUserPopup.vue @@ -13,7 +13,7 @@ SPDX-License-Identifier: AGPL-3.0-only >
-
+
{{ i18n.ts.followsYou }}
@@ -67,6 +67,7 @@ import { i18n } from '@/i18n.js'; import { defaultStore } from '@/store.js'; import { $i } from '@/account.js'; import { isFollowingVisibleForMe, isFollowersVisibleForMe } from '@/scripts/isFfVisibleForMe.js'; +import { getStaticImageUrl } from '@/scripts/media-proxy.js'; const props = defineProps<{ showing: boolean; diff --git a/packages/frontend/src/components/MkUserSetupDialog.vue b/packages/frontend/src/components/MkUserSetupDialog.vue index 1d376382ca..514350c930 100644 --- a/packages/frontend/src/components/MkUserSetupDialog.vue +++ b/packages/frontend/src/components/MkUserSetupDialog.vue @@ -148,7 +148,7 @@ const emit = defineEmits<{ const dialog = shallowRef>(); -// eslint-disable-next-line vue/no-setup-props-destructure +// eslint-disable-next-line vue/no-setup-props-reactivity-loss const page = ref(defaultStore.state.accountSetupWizard); watch(page, () => { @@ -176,9 +176,11 @@ function setupComplete() { function launchTutorial() { setupComplete(); nextTick(() => { - os.popup(defineAsyncComponent(() => import('@/components/MkTutorialDialog.vue')), { + const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkTutorialDialog.vue')), { initialPage: 1, - }, {}, 'closed'); + }, { + closed: () => dispose(), + }); }); } diff --git a/packages/frontend/src/components/MkVisibilityPicker.vue b/packages/frontend/src/components/MkVisibilityPicker.vue index 5ecd41bfdf..75066bbc32 100644 --- a/packages/frontend/src/components/MkVisibilityPicker.vue +++ b/packages/frontend/src/components/MkVisibilityPicker.vue @@ -4,7 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only -->
{{ i18n.ts.visibility }} diff --git a/packages/frontend/src/components/MkVisitorDashboard.vue b/packages/frontend/src/components/MkVisitorDashboard.vue index f7963f9938..445780eca7 100644 --- a/packages/frontend/src/components/MkVisitorDashboard.vue +++ b/packages/frontend/src/components/MkVisitorDashboard.vue @@ -23,7 +23,7 @@ SPDX-License-Identifier: AGPL-3.0-only
{{ i18n.ts.joinThisServer }} - {{ i18n.ts.exploreOtherServers }} + {{ i18n.ts.exploreOtherServers }} {{ i18n.ts.login }}
@@ -65,7 +65,8 @@ import { i18n } from '@/i18n.js'; import { instance } from '@/instance.js'; import MkNumber from '@/components/MkNumber.vue'; import XActiveUsersChart from '@/components/MkVisitorDashboard.ActiveUsersChart.vue'; -import { openInstanceMenu } from '@/ui/_common_/common'; +import { openInstanceMenu } from '@/ui/_common_/common.js'; +import type { MenuItem } from '@/types/menu.js'; const stats = ref(null); @@ -74,24 +75,24 @@ misskeyApi('stats', {}).then((res) => { }); function signin() { - os.popup(XSigninDialog, { + const { dispose } = os.popup(XSigninDialog, { autoSet: true, - }, {}, 'closed'); + }, { + closed: () => dispose(), + }); } function signup() { - os.popup(XSignupDialog, { + const { dispose } = os.popup(XSignupDialog, { autoSet: true, - }, {}, 'closed'); + }, { + closed: () => dispose(), + }); } -function showMenu(ev) { +function showMenu(ev: MouseEvent) { openInstanceMenu(ev); } - -function exploreOtherServers() { - window.open('https://misskey-hub.net/servers/', '_blank', 'noopener'); -} diff --git a/packages/frontend/src/pages/about.vue b/packages/frontend/src/pages/about.vue index 324d1c11de..8dfeb6d2a7 100644 --- a/packages/frontend/src/pages/about.vue +++ b/packages/frontend/src/pages/about.vue @@ -8,113 +8,7 @@ SPDX-License-Identifier: AGPL-3.0-only -
-
-
- -
- {{ instance.name ?? host }} -
-
-
- - - - - - - -
- - - - -
-
- - - {{ i18n.ts.aboutMisskey }} - - - - {{ i18n.ts.sourceCode }} - - - {{ i18n.ts.sourceCodeIsNotYetProvided }} - -
-
- - -
- - - - - - - - - - - - - {{ i18n.ts.impressum }} - -
- - - -
    -
  1. -
-
- - - {{ i18n.ts.termsOfService }} - - - - {{ i18n.ts.privacyPolicy }} - - - - {{ i18n.ts.feedback }} - -
-
-
- - - - - - - - - - - - - - - - - - - -
- host-meta - host-meta.json - nodeinfo - robots.txt - manifest.json -
-
-
+
@@ -130,26 +24,16 @@ SPDX-License-Identifier: AGPL-3.0-only - - diff --git a/packages/frontend/src/pages/admin-user.vue b/packages/frontend/src/pages/admin-user.vue index f57aa51b5b..1459997dcb 100644 --- a/packages/frontend/src/pages/admin-user.vue +++ b/packages/frontend/src/pages/admin-user.vue @@ -464,16 +464,20 @@ function toggleRoleItem(role) { } function createAnnouncement() { - os.popup(defineAsyncComponent(() => import('@/components/MkUserAnnouncementEditDialog.vue')), { + const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkUserAnnouncementEditDialog.vue')), { user: user.value, - }, {}, 'closed'); + }, { + closed: () => dispose(), + }); } function editAnnouncement(announcement) { - os.popup(defineAsyncComponent(() => import('@/components/MkUserAnnouncementEditDialog.vue')), { + const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkUserAnnouncementEditDialog.vue')), { user: user.value, announcement, - }, {}, 'closed'); + }, { + closed: () => dispose(), + }); } watch(() => props.userId, () => { diff --git a/packages/frontend/src/pages/admin/abuse-report/notification-recipient.editor.vue b/packages/frontend/src/pages/admin/abuse-report/notification-recipient.editor.vue new file mode 100644 index 0000000000..ffe9c620d6 --- /dev/null +++ b/packages/frontend/src/pages/admin/abuse-report/notification-recipient.editor.vue @@ -0,0 +1,307 @@ + + + + + + + diff --git a/packages/frontend/src/pages/admin/abuse-report/notification-recipient.item.vue b/packages/frontend/src/pages/admin/abuse-report/notification-recipient.item.vue new file mode 100644 index 0000000000..0b86808faf --- /dev/null +++ b/packages/frontend/src/pages/admin/abuse-report/notification-recipient.item.vue @@ -0,0 +1,114 @@ + + + + + + + diff --git a/packages/frontend/src/pages/admin/abuse-report/notification-recipient.vue b/packages/frontend/src/pages/admin/abuse-report/notification-recipient.vue new file mode 100644 index 0000000000..93800873f9 --- /dev/null +++ b/packages/frontend/src/pages/admin/abuse-report/notification-recipient.vue @@ -0,0 +1,176 @@ + + + + + + + diff --git a/packages/frontend/src/pages/admin/abuses.vue b/packages/frontend/src/pages/admin/abuses.vue index d2f4a4b531..9a9fa472a5 100644 --- a/packages/frontend/src/pages/admin/abuses.vue +++ b/packages/frontend/src/pages/admin/abuses.vue @@ -7,30 +7,33 @@ SPDX-License-Identifier: AGPL-3.0-only -
-
-
-
- - - - - - - - - - - - - - - - - - -
- - - - -
-
+ + +
@@ -60,6 +61,7 @@ import MkPagination from '@/components/MkPagination.vue'; import XAbuseReport from '@/components/MkAbuseReport.vue'; import { i18n } from '@/i18n.js'; import { definePageMetadata } from '@/scripts/page-metadata.js'; +import MkButton from '@/components/MkButton.vue'; const reports = shallowRef>(); @@ -80,7 +82,7 @@ const pagination = { }; function resolved(reportId) { - reports.value.removeItem(reportId); + reports.value?.removeItem(reportId); } const headerActions = computed(() => []); @@ -92,3 +94,26 @@ definePageMetadata(() => ({ icon: 'ti ti-exclamation-circle', })); + + diff --git a/packages/frontend/src/pages/admin/index.vue b/packages/frontend/src/pages/admin/index.vue index 794feae202..292f10da1a 100644 --- a/packages/frontend/src/pages/admin/index.vue +++ b/packages/frontend/src/pages/admin/index.vue @@ -214,6 +214,11 @@ const menuDef = computed(() => [{ text: i18n.ts.externalServices, to: '/admin/external-services', active: currentPage.value?.route.name === 'external-services', + }, { + icon: 'ti ti-webhook', + text: 'Webhook', + to: '/admin/system-webhook', + active: currentPage.value?.route.name === 'system-webhook', }, { icon: 'ti ti-adjustments', text: i18n.ts.other, diff --git a/packages/frontend/src/pages/admin/modlog.ModLog.vue b/packages/frontend/src/pages/admin/modlog.ModLog.vue index e33c882721..91f1c7c5e6 100644 --- a/packages/frontend/src/pages/admin/modlog.ModLog.vue +++ b/packages/frontend/src/pages/admin/modlog.ModLog.vue @@ -8,9 +8,35 @@ SPDX-License-Identifier: AGPL-3.0-only + +
raw diff --git a/packages/frontend/src/pages/admin/roles.editor.vue b/packages/frontend/src/pages/admin/roles.editor.vue index eb8a59b34f..3e948abdf1 100644 --- a/packages/frontend/src/pages/admin/roles.editor.vue +++ b/packages/frontend/src/pages/admin/roles.editor.vue @@ -378,6 +378,26 @@ SPDX-License-Identifier: AGPL-3.0-only
+ + + +
+ + + + + + + + + +
+
+ + + diff --git a/packages/frontend/src/pages/welcome.timeline.vue b/packages/frontend/src/pages/welcome.timeline.vue index 139b2e0a07..db326f9e6c 100644 --- a/packages/frontend/src/pages/welcome.timeline.vue +++ b/packages/frontend/src/pages/welcome.timeline.vue @@ -4,24 +4,17 @@ SPDX-License-Identifier: AGPL-3.0-only --> @@ -29,43 +22,54 @@ SPDX-License-Identifier: AGPL-3.0-only diff --git a/packages/frontend/src/router/definition.ts b/packages/frontend/src/router/definition.ts index c12ae0fa57..f7a219c57e 100644 --- a/packages/frontend/src/router/definition.ts +++ b/packages/frontend/src/router/definition.ts @@ -237,8 +237,18 @@ const routes: RouteDef[] = [{ origin: 'origin', }, }, { + // Legacy Compatibility path: '/authorize-follow', - component: page(() => import('@/pages/follow.vue')), + redirect: '/lookup', + loginRequired: true, +}, { + // Mastodon Compatibility + path: '/authorize_interaction', + redirect: '/lookup', + loginRequired: true, +}, { + path: '/lookup', + component: page(() => import('@/pages/lookup.vue')), loginRequired: true, }, { path: '/share', @@ -251,6 +261,9 @@ const routes: RouteDef[] = [{ }, { path: '/scratchpad', component: page(() => import('@/pages/scratchpad.vue')), +}, { + path: '/preview', + component: page(() => import('@/pages/preview.vue')), }, { path: '/auth/:token', component: page(() => import('@/pages/auth.vue')), @@ -471,6 +484,14 @@ const routes: RouteDef[] = [{ path: '/invites', name: 'invites', component: page(() => import('@/pages/admin/invites.vue')), + }, { + path: '/abuse-report-notification-recipient', + name: 'abuse-report-notification-recipient', + component: page(() => import('@/pages/admin/abuse-report/notification-recipient.vue')), + }, { + path: '/system-webhook', + name: 'system-webhook', + component: page(() => import('@/pages/admin/system-webhook.vue')), }, { path: '/', component: page(() => import('@/pages/_empty_.vue')), diff --git a/packages/frontend/src/scripts/array.ts b/packages/frontend/src/scripts/array.ts index b3d76e149f..f2feb29dfc 100644 --- a/packages/frontend/src/scripts/array.ts +++ b/packages/frontend/src/scripts/array.ts @@ -77,44 +77,6 @@ export function maximum(xs: number[]): number { return Math.max(...xs); } -/** - * Splits an array based on the equivalence relation. - * The concatenation of the result is equal to the argument. - */ -export function groupBy(f: EndoRelation, xs: T[]): T[][] { - const groups = [] as T[][]; - for (const x of xs) { - const lastGroup = groups.at(-1); - if (lastGroup !== undefined && f(lastGroup[0], x)) { - lastGroup.push(x); - } else { - groups.push([x]); - } - } - return groups; -} - -/** - * Splits an array based on the equivalence relation induced by the function. - * The concatenation of the result is equal to the argument. - */ -export function groupOn(f: (x: T) => S, xs: T[]): T[][] { - return groupBy((a, b) => f(a) === f(b), xs); -} - -export function groupByX(collections: T[], keySelector: (x: T) => string) { - return collections.reduce((obj: Record, item: T) => { - const key = keySelector(item); - if (typeof obj[key] === 'undefined') { - obj[key] = []; - } - - obj[key].push(item); - - return obj; - }, {}); -} - /** * Compare two arrays by lexicographical order */ diff --git a/packages/frontend/src/scripts/copy-to-clipboard.ts b/packages/frontend/src/scripts/copy-to-clipboard.ts index 216c0464b3..7e0bb25606 100644 --- a/packages/frontend/src/scripts/copy-to-clipboard.ts +++ b/packages/frontend/src/scripts/copy-to-clipboard.ts @@ -6,33 +6,6 @@ /** * Clipboardに値をコピー(TODO: 文字列以外も対応) */ -export default val => { - // 空div 生成 - const tmp = document.createElement('div'); - // 選択用のタグ生成 - const pre = document.createElement('pre'); - - // 親要素のCSSで user-select: none だとコピーできないので書き換える - pre.style.webkitUserSelect = 'auto'; - pre.style.userSelect = 'auto'; - - tmp.appendChild(pre).textContent = val; - - // 要素を画面外へ - const s = tmp.style; - s.position = 'fixed'; - s.right = '200%'; - - // body に追加 - document.body.appendChild(tmp); - // 要素を選択 - document.getSelection().selectAllChildren(tmp); - - // クリップボードにコピー - const result = document.execCommand('copy'); - - // 要素削除 - document.body.removeChild(tmp); - - return result; +export function copyToClipboard(input: string | null) { + if (input) navigator.clipboard.writeText(input); }; diff --git a/packages/frontend/src/scripts/focus-trap.ts b/packages/frontend/src/scripts/focus-trap.ts new file mode 100644 index 0000000000..a5df36f520 --- /dev/null +++ b/packages/frontend/src/scripts/focus-trap.ts @@ -0,0 +1,78 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ +import { getHTMLElementOrNull } from '@/scripts/get-dom-node-or-null.js'; + +const focusTrapElements = new Set(); +const ignoreElements = [ + 'script', + 'style', +]; + +function containsFocusTrappedElements(el: HTMLElement): boolean { + return Array.from(focusTrapElements).some((focusTrapElement) => { + return el.contains(focusTrapElement); + }); +} + +function releaseFocusTrap(el: HTMLElement): void { + focusTrapElements.delete(el); + if (el.inert === true) { + el.inert = false; + } + if (el.parentElement != null && el !== document.body) { + el.parentElement.childNodes.forEach((siblingNode) => { + const siblingEl = getHTMLElementOrNull(siblingNode); + if (!siblingEl) return; + if (siblingEl !== el && (focusTrapElements.has(siblingEl) || containsFocusTrappedElements(siblingEl) || focusTrapElements.size === 0)) { + siblingEl.inert = false; + } else if ( + focusTrapElements.size > 0 && + !containsFocusTrappedElements(siblingEl) && + !focusTrapElements.has(siblingEl) && + !ignoreElements.includes(siblingEl.tagName.toLowerCase()) + ) { + siblingEl.inert = true; + } else { + siblingEl.inert = false; + } + }); + releaseFocusTrap(el.parentElement); + } +} + +export function focusTrap(el: HTMLElement, hasInteractionWithOtherFocusTrappedEls: boolean, parent: true): void; +export function focusTrap(el: HTMLElement, hasInteractionWithOtherFocusTrappedEls?: boolean, parent?: false): { release: () => void; }; +export function focusTrap(el: HTMLElement, hasInteractionWithOtherFocusTrappedEls = false, parent = false): { release: () => void; } | void { + if (el.inert === true) { + el.inert = false; + } + if (el.parentElement != null && el !== document.body) { + el.parentElement.childNodes.forEach((siblingNode) => { + const siblingEl = getHTMLElementOrNull(siblingNode); + if (!siblingEl) return; + if ( + siblingEl !== el && + ( + hasInteractionWithOtherFocusTrappedEls === false || + (!focusTrapElements.has(siblingEl) && !containsFocusTrappedElements(siblingEl)) + ) && + !ignoreElements.includes(siblingEl.tagName.toLowerCase()) + ) { + siblingEl.inert = true; + } + }); + focusTrap(el.parentElement, hasInteractionWithOtherFocusTrappedEls, true); + } + + if (!parent) { + focusTrapElements.add(el); + + return { + release: () => { + releaseFocusTrap(el); + }, + }; + } +} diff --git a/packages/frontend/src/scripts/focus.ts b/packages/frontend/src/scripts/focus.ts index ea6ee61c88..eb2da5ad86 100644 --- a/packages/frontend/src/scripts/focus.ts +++ b/packages/frontend/src/scripts/focus.ts @@ -3,30 +3,78 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -export function focusPrev(el: Element | null, self = false, scroll = true) { - if (el == null) return; - if (!self) el = el.previousElementSibling; - if (el) { - if (el.hasAttribute('tabindex')) { - (el as HTMLElement).focus({ - preventScroll: !scroll, - }); - } else { - focusPrev(el.previousElementSibling, true); - } - } -} +import { getScrollPosition, getScrollContainer, getStickyBottom, getStickyTop } from '@/scripts/scroll.js'; +import { getElementOrNull, getNodeOrNull } from '@/scripts/get-dom-node-or-null.js'; -export function focusNext(el: Element | null, self = false, scroll = true) { - if (el == null) return; - if (!self) el = el.nextElementSibling; - if (el) { - if (el.hasAttribute('tabindex')) { - (el as HTMLElement).focus({ - preventScroll: !scroll, - }); - } else { - focusPrev(el.nextElementSibling, true); - } +type MaybeHTMLElement = EventTarget | Node | Element | HTMLElement; + +export const isFocusable = (input: MaybeHTMLElement | null | undefined): input is HTMLElement => { + if (input == null || !(input instanceof HTMLElement)) return false; + + if (input.tabIndex < 0) return false; + if ('disabled' in input && input.disabled === true) return false; + if ('readonly' in input && input.readonly === true) return false; + + if (!input.ownerDocument.contains(input)) return false; + + const style = window.getComputedStyle(input); + if (style.display === 'none') return false; + if (style.visibility === 'hidden') return false; + if (style.opacity === '0') return false; + if (style.pointerEvents === 'none') return false; + + return true; +}; + +export const focusPrev = (input: MaybeHTMLElement | null | undefined, self = false, scroll = true) => { + const element = self ? input : getElementOrNull(input)?.previousElementSibling; + if (element == null) return; + if (isFocusable(element)) { + focusOrScroll(element, scroll); + } else { + focusPrev(element, false, scroll); } -} +}; + +export const focusNext = (input: MaybeHTMLElement | null | undefined, self = false, scroll = true) => { + const element = self ? input : getElementOrNull(input)?.nextElementSibling; + if (element == null) return; + if (isFocusable(element)) { + focusOrScroll(element, scroll); + } else { + focusNext(element, false, scroll); + } +}; + +export const focusParent = (input: MaybeHTMLElement | null | undefined, self = false, scroll = true) => { + const element = self ? input : getNodeOrNull(input)?.parentElement; + if (element == null) return; + if (isFocusable(element)) { + focusOrScroll(element, scroll); + } else { + focusParent(element, false, scroll); + } +}; + +const focusOrScroll = (element: HTMLElement, scroll: boolean) => { + if (scroll) { + const scrollContainer = getScrollContainer(element) ?? document.documentElement; + const scrollContainerTop = getScrollPosition(scrollContainer); + const stickyTop = getStickyTop(element, scrollContainer); + const stickyBottom = getStickyBottom(element, scrollContainer); + const top = element.getBoundingClientRect().top; + const bottom = element.getBoundingClientRect().bottom; + + let scrollTo = scrollContainerTop; + if (top < stickyTop) { + scrollTo += top - stickyTop; + } else if (bottom > window.innerHeight - stickyBottom) { + scrollTo += bottom - window.innerHeight + stickyBottom; + } + scrollContainer.scrollTo({ top: scrollTo, behavior: 'instant' }); + } + + if (document.activeElement !== element) { + element.focus({ preventScroll: true }); + } +}; diff --git a/packages/frontend/src/scripts/get-dom-node-or-null.ts b/packages/frontend/src/scripts/get-dom-node-or-null.ts new file mode 100644 index 0000000000..fbf54675fd --- /dev/null +++ b/packages/frontend/src/scripts/get-dom-node-or-null.ts @@ -0,0 +1,19 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +export const getNodeOrNull = (input: unknown): Node | null => { + if (input instanceof Node) return input; + return null; +}; + +export const getElementOrNull = (input: unknown): Element | null => { + if (input instanceof Element) return input; + return null; +}; + +export const getHTMLElementOrNull = (input: unknown): HTMLElement | null => { + if (input instanceof HTMLElement) return input; + return null; +}; diff --git a/packages/frontend/src/scripts/get-drive-file-menu.ts b/packages/frontend/src/scripts/get-drive-file-menu.ts index 7aca5f83b2..7c6c4b4db4 100644 --- a/packages/frontend/src/scripts/get-drive-file-menu.ts +++ b/packages/frontend/src/scripts/get-drive-file-menu.ts @@ -6,7 +6,7 @@ import * as Misskey from 'misskey-js'; import { defineAsyncComponent } from 'vue'; import { i18n } from '@/i18n.js'; -import copyToClipboard from '@/scripts/copy-to-clipboard.js'; +import { copyToClipboard } from '@/scripts/copy-to-clipboard.js'; import * as os from '@/os.js'; import { misskeyApi } from '@/scripts/misskey-api.js'; import { MenuItem } from '@/types/menu.js'; @@ -27,7 +27,7 @@ function rename(file: Misskey.entities.DriveFile) { } function describe(file: Misskey.entities.DriveFile) { - os.popup(defineAsyncComponent(() => import('@/components/MkFileCaptionEditWindow.vue')), { + const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkFileCaptionEditWindow.vue')), { default: file.comment ?? '', file: file, }, { @@ -37,7 +37,8 @@ function describe(file: Misskey.entities.DriveFile) { comment: caption.length === 0 ? null : caption, }); }, - }, 'closed'); + closed: () => dispose(), + }); } function toggleSensitive(file: Misskey.entities.DriveFile) { diff --git a/packages/frontend/src/scripts/get-note-menu.ts b/packages/frontend/src/scripts/get-note-menu.ts index 71ad299f50..ebb96d1746 100644 --- a/packages/frontend/src/scripts/get-note-menu.ts +++ b/packages/frontend/src/scripts/get-note-menu.ts @@ -11,7 +11,7 @@ import { i18n } from '@/i18n.js'; import { instance } from '@/instance.js'; import * as os from '@/os.js'; import { misskeyApi } from '@/scripts/misskey-api.js'; -import copyToClipboard from '@/scripts/copy-to-clipboard.js'; +import { copyToClipboard } from '@/scripts/copy-to-clipboard.js'; import { url } from '@/config.js'; import { defaultStore, noteActions } from '@/store.js'; import { miLocalStorage } from '@/local-storage.js'; @@ -136,10 +136,12 @@ export function getAbuseNoteMenu(note: Misskey.entities.Note, text: string): Men let noteInfo = ''; if (note.url ?? note.uri != null) noteInfo = `Note: ${note.url ?? note.uri}\n`; noteInfo += `Local Note: ${localUrl}\n`; - os.popup(defineAsyncComponent(() => import('@/components/MkAbuseReportWindow.vue')), { + const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkAbuseReportWindow.vue')), { user: note.user, initialComment: `${noteInfo}-----\n`, - }, {}, 'closed'); + }, { + closed: () => dispose(), + }); }, }; } @@ -530,7 +532,9 @@ export function getRenoteMenu(props: { const rect = el.getBoundingClientRect(); const x = rect.left + (el.offsetWidth / 2); const y = rect.top + (el.offsetHeight / 2); - os.popup(MkRippleEffect, { x, y }, {}, 'end'); + const { dispose } = os.popup(MkRippleEffect, { x, y }, { + end: () => dispose(), + }); } if (!props.mock) { @@ -566,7 +570,9 @@ export function getRenoteMenu(props: { const rect = el.getBoundingClientRect(); const x = rect.left + (el.offsetWidth / 2); const y = rect.top + (el.offsetHeight / 2); - os.popup(MkRippleEffect, { x, y }, {}, 'end'); + const { dispose } = os.popup(MkRippleEffect, { x, y }, { + end: () => dispose(), + }); } const configuredVisibility = defaultStore.state.rememberNoteVisibility ? defaultStore.state.visibility : defaultStore.state.defaultNoteVisibility; @@ -615,7 +621,9 @@ export function getRenoteMenu(props: { const rect = el.getBoundingClientRect(); const x = rect.left + (el.offsetWidth / 2); const y = rect.top + (el.offsetHeight / 2); - os.popup(MkRippleEffect, { x, y }, {}, 'end'); + const { dispose } = os.popup(MkRippleEffect, { x, y }, { + end: () => dispose(), + }); } if (!props.mock) { diff --git a/packages/frontend/src/scripts/get-user-menu.ts b/packages/frontend/src/scripts/get-user-menu.ts index 3e031d232f..dacafb859f 100644 --- a/packages/frontend/src/scripts/get-user-menu.ts +++ b/packages/frontend/src/scripts/get-user-menu.ts @@ -7,7 +7,7 @@ import { toUnicode } from 'punycode'; import { defineAsyncComponent, ref, watch } from 'vue'; import * as Misskey from 'misskey-js'; import { i18n } from '@/i18n.js'; -import copyToClipboard from '@/scripts/copy-to-clipboard.js'; +import { copyToClipboard } from '@/scripts/copy-to-clipboard.js'; import { host, url } from '@/config.js'; import * as os from '@/os.js'; import { misskeyApi } from '@/scripts/misskey-api.js'; @@ -100,9 +100,11 @@ export function getUserMenu(user: Misskey.entities.UserDetailed, router: IRouter } function reportAbuse() { - os.popup(defineAsyncComponent(() => import('@/components/MkAbuseReportWindow.vue')), { + const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkAbuseReportWindow.vue')), { user: user, - }, {}, 'closed'); + }, { + closed: () => dispose(), + }); } async function getConfirmed(text: string): Promise { @@ -184,7 +186,7 @@ export function getUserMenu(user: Misskey.entities.UserDetailed, router: IRouter const canonical = user.host === null ? `@${user.username}` : `@${user.username}@${toUnicode(user.host)}`; copyToClipboard(`${url}/${canonical}`); }, - }, { + }, ...($i ? [{ icon: 'ti ti-mail', text: i18n.ts.sendMessage, action: () => { @@ -257,7 +259,7 @@ export function getUserMenu(user: Misskey.entities.UserDetailed, router: IRouter }, })); }, - }] as any; + }] : [])] as any; if ($i && meId !== user.id) { if (iAmModerator) { diff --git a/packages/frontend/src/scripts/hotkey.ts b/packages/frontend/src/scripts/hotkey.ts index 0600bff893..04fb235694 100644 --- a/packages/frontend/src/scripts/hotkey.ts +++ b/packages/frontend/src/scripts/hotkey.ts @@ -2,94 +2,171 @@ * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ +import { getHTMLElementOrNull } from "@/scripts/get-dom-node-or-null.js"; -import keyCode from './keycode.js'; +//#region types +export type Keymap = Record; -type Callback = (ev: KeyboardEvent) => void; +type CallbackFunction = (ev: KeyboardEvent) => unknown; -type Keymap = Record; +type CallbackObject = { + callback: CallbackFunction; + allowRepeat?: boolean; +}; type Pattern = { which: string[]; - ctrl?: boolean; - shift?: boolean; - alt?: boolean; + ctrl: boolean; + alt: boolean; + shift: boolean; }; type Action = { patterns: Pattern[]; - callback: Callback; - allowRepeat: boolean; + callback: CallbackFunction; + options: Required>; +}; +//#endregion + +//#region consts +const KEY_ALIASES = { + 'esc': 'Escape', + 'enter': 'Enter', + 'space': ' ', + 'up': 'ArrowUp', + 'down': 'ArrowDown', + 'left': 'ArrowLeft', + 'right': 'ArrowRight', + 'plus': ['+', ';'], }; -const parseKeymap = (keymap: Keymap) => Object.entries(keymap).map(([patterns, callback]): Action => { - const result = { - patterns: [], - callback, - allowRepeat: true, - } as Action; +const MODIFIER_KEYS = ['ctrl', 'alt', 'shift']; - if (patterns.match(/^\(.*\)$/) !== null) { - result.allowRepeat = false; - patterns = patterns.slice(1, -1); - } +const IGNORE_ELEMENTS = ['input', 'textarea']; +//#endregion - result.patterns = patterns.split('|').map(part => { - const pattern = { - which: [], - ctrl: false, - alt: false, - shift: false, - } as Pattern; - - const keys = part.trim().split('+').map(x => x.trim().toLowerCase()); - for (const key of keys) { - switch (key) { - case 'ctrl': pattern.ctrl = true; break; - case 'alt': pattern.alt = true; break; - case 'shift': pattern.shift = true; break; - default: pattern.which = keyCode(key).map(k => k.toLowerCase()); - } - } - - return pattern; - }); - - return result; -}); - -const ignoreElements = ['input', 'textarea']; - -function match(ev: KeyboardEvent, patterns: Action['patterns']): boolean { - const key = ev.key.toLowerCase(); - return patterns.some(pattern => pattern.which.includes(key) && - pattern.ctrl === ev.ctrlKey && - pattern.shift === ev.shiftKey && - pattern.alt === ev.altKey && - !ev.metaKey, - ); -} +//#region store +let latestHotkey: Pattern & { callback: CallbackFunction } | null = null; +//#endregion +//#region impl export const makeHotkey = (keymap: Keymap) => { const actions = parseKeymap(keymap); - return (ev: KeyboardEvent) => { - if (document.activeElement) { - if (ignoreElements.some(el => document.activeElement!.matches(el))) return; - if (document.activeElement.attributes['contenteditable']) return; + if ('pswp' in window && window.pswp != null) return; + if (document.activeElement != null) { + if (IGNORE_ELEMENTS.includes(document.activeElement.tagName.toLowerCase())) return; + if (getHTMLElementOrNull(document.activeElement)?.isContentEditable) return; } - for (const action of actions) { - const matched = match(ev, action.patterns); - - if (matched) { - if (!action.allowRepeat && ev.repeat) return; - + if (matchPatterns(ev, action)) { ev.preventDefault(); ev.stopPropagation(); action.callback(ev); - break; + storePattern(ev, action.callback); } } }; }; + +const parseKeymap = (keymap: Keymap) => { + return Object.entries(keymap).map(([rawPatterns, rawCallback]) => { + const patterns = parsePatterns(rawPatterns); + const callback = parseCallback(rawCallback); + const options = parseOptions(rawCallback); + return { patterns, callback, options } as const satisfies Action; + }); +}; + +const parsePatterns = (rawPatterns: keyof Keymap) => { + return rawPatterns.split('|').map(part => { + const keys = part.split('+').map(trimLower); + const which = parseKeyCode(keys.findLast(x => !MODIFIER_KEYS.includes(x))); + const ctrl = keys.includes('ctrl'); + const alt = keys.includes('alt'); + const shift = keys.includes('shift'); + return { which, ctrl, alt, shift } as const satisfies Pattern; + }); +}; + +const parseCallback = (rawCallback: Keymap[keyof Keymap]) => { + if (typeof rawCallback === 'object') { + return rawCallback.callback; + } + return rawCallback; +}; + +const parseOptions = (rawCallback: Keymap[keyof Keymap]) => { + const defaultOptions = { + allowRepeat: false, + } as const satisfies Action['options']; + if (typeof rawCallback === 'object') { + const { callback, ...rawOptions } = rawCallback; + const options = { ...defaultOptions, ...rawOptions }; + return { ...options } as const satisfies Action['options']; + } + return { ...defaultOptions } as const satisfies Action['options']; +}; + +const matchPatterns = (ev: KeyboardEvent, action: Action) => { + const { patterns, options, callback } = action; + if (ev.repeat && !options.allowRepeat) return false; + const key = ev.key.toLowerCase(); + return patterns.some(({ which, ctrl, shift, alt }) => { + if ( + options.allowRepeat === false && + latestHotkey != null && + latestHotkey.which.includes(key) && + latestHotkey.ctrl === ctrl && + latestHotkey.alt === alt && + latestHotkey.shift === shift && + latestHotkey.callback === callback + ) { + return false; + } + if (!which.includes(key)) return false; + if (ctrl !== (ev.ctrlKey || ev.metaKey)) return false; + if (alt !== ev.altKey) return false; + if (shift !== ev.shiftKey) return false; + return true; + }); +}; + +let lastHotKeyStoreTimer: number | null = null; + +const storePattern = (ev: KeyboardEvent, callback: CallbackFunction) => { + if (lastHotKeyStoreTimer != null) { + clearTimeout(lastHotKeyStoreTimer); + } + + latestHotkey = { + which: [ev.key.toLowerCase()], + ctrl: ev.ctrlKey || ev.metaKey, + alt: ev.altKey, + shift: ev.shiftKey, + callback, + }; + + lastHotKeyStoreTimer = window.setTimeout(() => { + latestHotkey = null; + }, 500); +}; + +const parseKeyCode = (input?: string | null) => { + if (input == null) return []; + const raw = getValueByKey(KEY_ALIASES, input); + if (raw == null) return [input]; + if (typeof raw === 'string') return [trimLower(raw)]; + return raw.map(trimLower); +}; + +const getValueByKey = < + T extends Record, + K extends keyof T | keyof any, + R extends K extends keyof T ? T[K] : T[keyof T] | undefined, +>(obj: T, key: K) => { + return obj[key] as R; +}; + +const trimLower = (str: string) => str.trim().toLowerCase(); +//#endregion diff --git a/packages/frontend/src/scripts/install-plugin.ts b/packages/frontend/src/scripts/install-plugin.ts index d0a8675b19..37f473b6de 100644 --- a/packages/frontend/src/scripts/install-plugin.ts +++ b/packages/frontend/src/scripts/install-plugin.ts @@ -103,7 +103,7 @@ export async function installPlugin(code: string, meta?: AiScriptPluginMeta) { } const token = realMeta.permissions == null || realMeta.permissions.length === 0 ? null : await new Promise((res, rej) => { - os.popup(defineAsyncComponent(() => import('@/components/MkTokenGenerateWindow.vue')), { + const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkTokenGenerateWindow.vue')), { title: i18n.ts.tokenRequested, information: i18n.ts.pluginTokenRequestedDescription, initialName: realMeta.name, @@ -118,7 +118,8 @@ export async function installPlugin(code: string, meta?: AiScriptPluginMeta) { }); res(token); }, - }, 'closed'); + closed: () => dispose(), + }); }); savePlugin({ diff --git a/packages/frontend/src/scripts/keycode.ts b/packages/frontend/src/scripts/keycode.ts deleted file mode 100644 index 7ffceafada..0000000000 --- a/packages/frontend/src/scripts/keycode.ts +++ /dev/null @@ -1,24 +0,0 @@ -/* - * SPDX-FileCopyrightText: syuilo and misskey-project - * SPDX-License-Identifier: AGPL-3.0-only - */ - -export default (input: string): string[] => { - if (Object.keys(aliases).some(a => a.toLowerCase() === input.toLowerCase())) { - const codes = aliases[input]; - return Array.isArray(codes) ? codes : [codes]; - } else { - return [input]; - } -}; - -export const aliases = { - 'esc': 'Escape', - 'enter': ['Enter', 'NumpadEnter'], - 'space': [' ', 'Spacebar'], - 'up': 'ArrowUp', - 'down': 'ArrowDown', - 'left': 'ArrowLeft', - 'right': 'ArrowRight', - 'plus': ['NumpadAdd', 'Semicolon'], -}; diff --git a/packages/frontend/src/scripts/mfm-function-picker.ts b/packages/frontend/src/scripts/mfm-function-picker.ts index 8867a8c50f..9938e534c1 100644 --- a/packages/frontend/src/scripts/mfm-function-picker.ts +++ b/packages/frontend/src/scripts/mfm-function-picker.ts @@ -7,29 +7,24 @@ import { Ref, nextTick } from 'vue'; import * as os from '@/os.js'; import { i18n } from '@/i18n.js'; import { MFM_TAGS } from '@/const.js'; +import type { MenuItem } from '@/types/menu.js'; /** * MFMの装飾のリストを表示する */ -export function mfmFunctionPicker(src: any, textArea: HTMLInputElement | HTMLTextAreaElement, textRef: Ref) { - return new Promise((res, rej) => { - os.popupMenu([{ - text: i18n.ts.addMfmFunction, - type: 'label', - }, ...getFunctionList(textArea, textRef)], src); - }); +export function mfmFunctionPicker(src: HTMLElement | EventTarget | null, textArea: HTMLInputElement | HTMLTextAreaElement, textRef: Ref) { + os.popupMenu([{ + text: i18n.ts.addMfmFunction, + type: 'label', + }, ...getFunctionList(textArea, textRef)], src); } -function getFunctionList(textArea: HTMLInputElement | HTMLTextAreaElement, textRef: Ref) : object[] { - const ret: object[] = []; - MFM_TAGS.forEach(tag => { - ret.push({ - text: tag, - icon: 'ti ti-icons', - action: () => add(textArea, textRef, tag), - }); - }); - return ret; +function getFunctionList(textArea: HTMLInputElement | HTMLTextAreaElement, textRef: Ref): MenuItem[] { + return MFM_TAGS.map(tag => ({ + text: tag, + icon: 'ti ti-icons', + action: () => add(textArea, textRef, tag), + })); } function add(textArea: HTMLInputElement | HTMLTextAreaElement, textRef: Ref, type: string) { diff --git a/packages/frontend/src/scripts/player-url-transform.ts b/packages/frontend/src/scripts/player-url-transform.ts new file mode 100644 index 0000000000..53b2a9e441 --- /dev/null +++ b/packages/frontend/src/scripts/player-url-transform.ts @@ -0,0 +1,26 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ +import { hostname } from '@/config.js'; + +export function transformPlayerUrl(url: string): string { + const urlObj = new URL(url); + if (!['https:', 'http:'].includes(urlObj.protocol)) throw new Error('Invalid protocol'); + + const urlParams = new URLSearchParams(urlObj.search); + + if (urlObj.hostname === 'player.twitch.tv') { + // TwitchはCSPの制約あり + // https://dev.twitch.tv/docs/embed/video-and-clips/ + urlParams.set('parent', hostname); + urlParams.set('allowfullscreen', ''); + urlParams.set('autoplay', 'true'); + } else { + urlParams.set('autoplay', '1'); + urlParams.set('auto_play', '1'); + } + urlObj.search = urlParams.toString(); + + return urlObj.toString(); +} diff --git a/packages/frontend/src/scripts/please-login.ts b/packages/frontend/src/scripts/please-login.ts index 9e51272791..18f05bc7f4 100644 --- a/packages/frontend/src/scripts/please-login.ts +++ b/packages/frontend/src/scripts/please-login.ts @@ -8,19 +8,57 @@ import { $i } from '@/account.js'; import { i18n } from '@/i18n.js'; import { popup } from '@/os.js'; -export function pleaseLogin(path?: string) { +export type OpenOnRemoteOptions = { + /** + * 外部のMisskey Webで特定のパスを開く + */ + type: 'web'; + + /** + * 内部パス(例: `/settings`) + */ + path: string; +} | { + /** + * 外部のMisskey Webで照会する + */ + type: 'lookup'; + + /** + * 照会したいエンティティのURL + * + * (例: `https://misskey.example.com/notes/abcdexxxxyz`) + */ + url: string; +} | { + /** + * 外部のMisskeyでノートする + */ + type: 'share'; + + /** + * `/share` ページに渡すクエリストリング + * + * @see https://go.misskey-hub.net/spec/share/ + */ + params: Record; +}; + +export function pleaseLogin(path?: string, openOnRemote?: OpenOnRemoteOptions) { if ($i) return; - popup(defineAsyncComponent(() => import('@/components/MkSigninDialog.vue')), { + const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkSigninDialog.vue')), { autoSet: true, - message: i18n.ts.signinRequired, + message: openOnRemote ? i18n.ts.signinOrContinueOnRemote : i18n.ts.signinRequired, + openOnRemote, }, { cancelled: () => { if (path) { window.location.href = path; } }, - }, 'closed'); + closed: () => dispose(), + }); throw new Error('signin required'); } diff --git a/packages/frontend/src/scripts/scroll.ts b/packages/frontend/src/scripts/scroll.ts index 8edb6fca05..f0274034b5 100644 --- a/packages/frontend/src/scripts/scroll.ts +++ b/packages/frontend/src/scripts/scroll.ts @@ -23,6 +23,14 @@ export function getStickyTop(el: HTMLElement, container: HTMLElement | null = nu return getStickyTop(el.parentElement, container, newTop); } +export function getStickyBottom(el: HTMLElement, container: HTMLElement | null = null, bottom = 0) { + if (!el.parentElement) return bottom; + const data = el.dataset.stickyContainerFooterHeight; + const newBottom = data ? Number(data) + bottom : bottom; + if (el === container) return newBottom; + return getStickyBottom(el.parentElement, container, newBottom); +} + export function getScrollPosition(el: HTMLElement | null): number { const container = getScrollContainer(el); return container == null ? window.scrollY : container.scrollTop; diff --git a/packages/frontend/src/scripts/sound.ts b/packages/frontend/src/scripts/sound.ts index fcd59510df..bba855cd64 100644 --- a/packages/frontend/src/scripts/sound.ts +++ b/packages/frontend/src/scripts/sound.ts @@ -74,8 +74,6 @@ export const soundsTypes = [ export const operationTypes = [ 'noteMy', 'note', - 'antenna', - 'channel', 'notification', 'reaction', ] as const; diff --git a/packages/frontend/src/scripts/url.ts b/packages/frontend/src/scripts/url.ts index e3072b3b7d..5a8265af9e 100644 --- a/packages/frontend/src/scripts/url.ts +++ b/packages/frontend/src/scripts/url.ts @@ -21,3 +21,8 @@ export function query(obj: Record): string { export function appendQuery(url: string, query: string): string { return `${url}${/\?/.test(url) ? url.endsWith('?') ? '' : '&' : '?'}${query}`; } + +export function extractDomain(url: string) { + const match = url.match(/^(?:https?:)?(?:\/\/)?(?:[^@\n]+@)?([^:\/\n]+)/im); + return match ? match[1] : null; +} diff --git a/packages/frontend/src/scripts/use-chart-tooltip.ts b/packages/frontend/src/scripts/use-chart-tooltip.ts index bed221a622..bba64fc6ee 100644 --- a/packages/frontend/src/scripts/use-chart-tooltip.ts +++ b/packages/frontend/src/scripts/use-chart-tooltip.ts @@ -17,20 +17,16 @@ export function useChartTooltip(opts: { position: 'top' | 'middle' } = { positio borderColor: string; text: string; }[] | null>(null); - let disposeTooltipComponent; - - os.popup(MkChartTooltip, { + const { dispose: disposeTooltipComponent } = os.popup(MkChartTooltip, { showing: tooltipShowing, x: tooltipX, y: tooltipY, title: tooltipTitle, series: tooltipSeries, - }, {}).then(({ dispose }) => { - disposeTooltipComponent = dispose; - }); + }, {}); onUnmounted(() => { - if (disposeTooltipComponent) disposeTooltipComponent(); + disposeTooltipComponent(); }); onDeactivated(() => { diff --git a/packages/frontend/src/store.ts b/packages/frontend/src/store.ts index e8eb5a1ed7..dbf6b8716f 100644 --- a/packages/frontend/src/store.ts +++ b/packages/frontend/src/store.ts @@ -454,6 +454,10 @@ export const defaultStore = markRaw(new Storage('base', { where: 'device', default: true, }, + confirmWhenRevealingSensitiveMedia: { + where: 'device', + default: false, + }, sound_masterVolume: { where: 'device', @@ -479,14 +483,6 @@ export const defaultStore = markRaw(new Storage('base', { where: 'device', default: { type: 'syuilo/n-ea', volume: 1 } as SoundStore, }, - sound_antenna: { - where: 'device', - default: { type: 'syuilo/triple', volume: 1 } as SoundStore, - }, - sound_channel: { - where: 'device', - default: { type: 'syuilo/square-pico', volume: 1 } as SoundStore, - }, sound_reaction: { where: 'device', default: { type: 'syuilo/bubble2', volume: 1 } as SoundStore, diff --git a/packages/frontend/src/style.scss b/packages/frontend/src/style.scss index 250a2616a7..2feb79ef81 100644 --- a/packages/frontend/src/style.scss +++ b/packages/frontend/src/style.scss @@ -113,6 +113,10 @@ a { -webkit-tap-highlight-color: transparent; -webkit-touch-callout: none; + &:focus-visible { + outline-offset: 2px; + } + &:hover { text-decoration: underline; } @@ -143,12 +147,21 @@ rt { white-space: initial; } +:focus-visible { + outline: var(--focus) solid 2px; + outline-offset: -2px; + + &:hover { + text-decoration: none; + } +} + .ti { width: 1.28em; vertical-align: -12%; line-height: 1em; - &:before { + &::before { font-size: 128%; } } @@ -230,10 +243,6 @@ rt { line-height: inherit; max-width: 100%; - &:focus-visible { - outline: none; - } - &:disabled { opacity: 0.5; cursor: default; @@ -270,13 +279,17 @@ rt { ._help { color: var(--accent); - cursor: help + cursor: help; } ._textButton { @extend ._button; color: var(--accent); + &:focus-visible { + outline-offset: 2px; + } + &:not(:disabled):hover { text-decoration: underline; } diff --git a/packages/frontend/src/ui/_common_/common.ts b/packages/frontend/src/ui/_common_/common.ts index 839fa5faf8..74c3028745 100644 --- a/packages/frontend/src/ui/_common_/common.ts +++ b/packages/frontend/src/ui/_common_/common.ts @@ -85,34 +85,36 @@ export function openInstanceMenu(ev: MouseEvent) { icon: 'ti ti-help-circle', to: '/contact', }, (instance.impressumUrl) ? { + type: 'a', text: i18n.ts.impressum, icon: 'ti ti-file-invoice', - action: () => { - window.open(instance.impressumUrl, '_blank', 'noopener'); - }, + href: instance.impressumUrl, + target: '_blank', } : undefined, (instance.tosUrl) ? { + type: 'a', text: i18n.ts.termsOfService, icon: 'ti ti-notebook', - action: () => { - window.open(instance.tosUrl, '_blank', 'noopener'); - }, + href: instance.tosUrl, + target: '_blank', } : undefined, (instance.privacyPolicyUrl) ? { + type: 'a', text: i18n.ts.privacyPolicy, icon: 'ti ti-shield-lock', - action: () => { - window.open(instance.privacyPolicyUrl, '_blank', 'noopener'); - }, + href: instance.privacyPolicyUrl, + target: '_blank', } : undefined, (!instance.impressumUrl && !instance.tosUrl && !instance.privacyPolicyUrl) ? undefined : { type: 'divider' }, { + type: 'a', text: i18n.ts.document, icon: 'ti ti-bulb', - action: () => { - window.open('https://misskey-hub.net/docs/for-users/', '_blank', 'noopener'); - }, + href: 'https://misskey-hub.net/docs/for-users/', + target: '_blank', }, ($i) ? { text: i18n.ts._initialTutorial.launchTutorial, icon: 'ti ti-presentation', action: () => { - os.popup(defineAsyncComponent(() => import('@/components/MkTutorialDialog.vue')), {}, {}, 'closed'); + const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkTutorialDialog.vue')), {}, { + closed: () => dispose(), + }); }, } : undefined, { type: 'link', diff --git a/packages/frontend/src/ui/_common_/common.vue b/packages/frontend/src/ui/_common_/common.vue index 822b552837..d7df2d10f9 100644 --- a/packages/frontend/src/ui/_common_/common.vue +++ b/packages/frontend/src/ui/_common_/common.vue @@ -227,7 +227,7 @@ if ($i) { right: 15px; pointer-events: none; - &:before { + &::before { content: ""; display: block; width: 18px; diff --git a/packages/frontend/src/ui/_common_/navbar-for-mobile.vue b/packages/frontend/src/ui/_common_/navbar-for-mobile.vue index 5d0e065f09..87e9e45e63 100644 --- a/packages/frontend/src/ui/_common_/navbar-for-mobile.vue +++ b/packages/frontend/src/ui/_common_/navbar-for-mobile.vue @@ -74,8 +74,9 @@ function openAccountMenu(ev: MouseEvent) { } function more() { - os.popup(defineAsyncComponent(() => import('@/components/MkLaunchPad.vue')), {}, { - }, 'closed'); + const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkLaunchPad.vue')), {}, { + closed: () => dispose(), + }); } @@ -138,7 +139,7 @@ function more() { font-weight: bold; text-align: left; - &:before { + &::before { content: ""; display: block; width: calc(100% - 38px); @@ -154,7 +155,7 @@ function more() { } &:hover, &.active { - &:before { + &::before { background: var(--accentLighten); } } @@ -225,7 +226,7 @@ function more() { } &:hover, &.active { - &:before { + &::before { content: ""; display: block; width: calc(100% - 24px); diff --git a/packages/frontend/src/ui/_common_/navbar.vue b/packages/frontend/src/ui/_common_/navbar.vue index fa1f0eb8c7..8307da0d42 100644 --- a/packages/frontend/src/ui/_common_/navbar.vue +++ b/packages/frontend/src/ui/_common_/navbar.vue @@ -99,10 +99,11 @@ function openAccountMenu(ev: MouseEvent) { } function more(ev: MouseEvent) { - os.popup(defineAsyncComponent(() => import('@/components/MkLaunchPad.vue')), { + const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkLaunchPad.vue')), { src: ev.currentTarget ?? ev.target, }, { - }, 'closed'); + closed: () => dispose(), + }); } @@ -165,6 +166,15 @@ function more(ev: MouseEvent) { display: block; text-align: center; width: 100%; + + &:focus-visible { + outline: none; + + > .instanceIcon { + outline: 2px solid var(--focus); + outline-offset: 2px; + } + } } .instanceIcon { @@ -191,7 +201,7 @@ function more(ev: MouseEvent) { font-weight: bold; text-align: left; - &:before { + &::before { content: ""; display: block; width: calc(100% - 38px); @@ -206,8 +216,17 @@ function more(ev: MouseEvent) { background: linear-gradient(90deg, var(--buttonGradateA), var(--buttonGradateB)); } + &:focus-visible { + outline: none; + + &::before { + outline: 2px solid var(--fgOnAccent); + outline-offset: -4px; + } + } + &:hover, &.active { - &:before { + &::before { background: var(--accentLighten); } } @@ -233,6 +252,14 @@ function more(ev: MouseEvent) { text-align: left; box-sizing: border-box; overflow: clip; + + &:focus-visible { + outline: none; + + > .avatar { + box-shadow: 0 0 0 4px var(--focus); + } + } } .avatar { @@ -281,10 +308,19 @@ function more(ev: MouseEvent) { color: var(--navActive); } - &:hover, &.active { + &:focus-visible { + outline: none; + + &::before { + outline: 2px solid var(--focus); + outline-offset: -2px; + } + } + + &:hover, &.active, &:focus { color: var(--accent); - &:before { + &::before { content: ""; display: block; width: calc(100% - 34px); @@ -351,6 +387,15 @@ function more(ev: MouseEvent) { display: block; text-align: center; width: 100%; + + &:focus-visible { + outline: none; + + > .instanceIcon { + outline: 2px solid var(--focus); + outline-offset: 2px; + } + } } .instanceIcon { @@ -375,7 +420,7 @@ function more(ev: MouseEvent) { height: 52px; text-align: center; - &:before { + &::before { content: ""; display: block; position: absolute; @@ -390,8 +435,17 @@ function more(ev: MouseEvent) { background: linear-gradient(90deg, var(--buttonGradateA), var(--buttonGradateB)); } + &:focus-visible { + outline: none; + + &::before { + outline: 2px solid var(--fgOnAccent); + outline-offset: -4px; + } + } + &:hover, &.active { - &:before { + &::before { background: var(--accentLighten); } } @@ -412,6 +466,14 @@ function more(ev: MouseEvent) { padding: 20px 0; width: 100%; overflow: clip; + + &:focus-visible { + outline: none; + + > .avatar { + box-shadow: 0 0 0 4px var(--focus); + } + } } .avatar { @@ -441,11 +503,20 @@ function more(ev: MouseEvent) { width: 100%; text-align: center; - &:hover, &.active { + &:focus-visible { + outline: none; + + &::before { + outline: 2px solid var(--focus); + outline-offset: -2px; + } + } + + &:hover, &.active, &:focus { text-decoration: none; color: var(--accent); - &:before { + &::before { content: ""; display: block; height: 100%; diff --git a/packages/frontend/src/ui/classic.header.vue b/packages/frontend/src/ui/classic.header.vue index ee5176b558..c03afd6cd6 100644 --- a/packages/frontend/src/ui/classic.header.vue +++ b/packages/frontend/src/ui/classic.header.vue @@ -71,11 +71,12 @@ const otherNavItemIndicated = computed(() => { }); function more(ev: MouseEvent) { - os.popup(defineAsyncComponent(() => import('@/components/MkLaunchPad.vue')), { + const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkLaunchPad.vue')), { src: ev.currentTarget ?? ev.target, anchor: { x: 'center', y: 'bottom' }, }, { - }, 'closed'); + closed: () => dispose(), + }); } function openAccountMenu(ev: MouseEvent) { diff --git a/packages/frontend/src/ui/classic.sidebar.vue b/packages/frontend/src/ui/classic.sidebar.vue index 19672ef87f..d8574a915f 100644 --- a/packages/frontend/src/ui/classic.sidebar.vue +++ b/packages/frontend/src/ui/classic.sidebar.vue @@ -86,9 +86,11 @@ function calcViewState() { } function more(ev: MouseEvent) { - os.popup(defineAsyncComponent(() => import('@/components/MkLaunchPad.vue')), { + const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkLaunchPad.vue')), { src: ev.currentTarget ?? ev.target, - }, {}, 'closed'); + }, { + closed: () => dispose(), + }); } function openAccountMenu(ev: MouseEvent) { diff --git a/packages/frontend/src/ui/deck/column.vue b/packages/frontend/src/ui/deck/column.vue index 07845bacbb..e96402d13b 100644 --- a/packages/frontend/src/ui/deck/column.vue +++ b/packages/frontend/src/ui/deck/column.vue @@ -271,7 +271,7 @@ function onDrop(ev) { border-radius: 10px; &.draghover { - &:after { + &::after { content: ""; display: block; position: absolute; @@ -285,7 +285,7 @@ function onDrop(ev) { } &.dragging { - &:after { + &::after { content: ""; display: block; position: absolute; diff --git a/packages/frontend/src/ui/deck/notifications-column.vue b/packages/frontend/src/ui/deck/notifications-column.vue index 451cc58791..23b0fd4f7b 100644 --- a/packages/frontend/src/ui/deck/notifications-column.vue +++ b/packages/frontend/src/ui/deck/notifications-column.vue @@ -27,7 +27,7 @@ const props = defineProps<{ const notificationsComponent = shallowRef>(); function func() { - os.popup(defineAsyncComponent(() => import('@/components/MkNotificationSelectWindow.vue')), { + const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkNotificationSelectWindow.vue')), { excludeTypes: props.column.excludeTypes, }, { done: async (res) => { @@ -36,7 +36,8 @@ function func() { excludeTypes: excludeTypes, }); }, - }, 'closed'); + closed: () => dispose(), + }); } const menu = [{ diff --git a/packages/frontend/src/ui/visitor.vue b/packages/frontend/src/ui/visitor.vue index 80623083cf..c229946bd4 100644 --- a/packages/frontend/src/ui/visitor.vue +++ b/packages/frontend/src/ui/visitor.vue @@ -126,15 +126,19 @@ const keymap = computed(() => { }); function signin() { - os.popup(XSigninDialog, { + const { dispose } = os.popup(XSigninDialog, { autoSet: true, - }, {}, 'closed'); + }, { + closed: () => dispose(), + }); } function signup() { - os.popup(XSignupDialog, { + const { dispose } = os.popup(XSignupDialog, { autoSet: true, - }, {}, 'closed'); + }, { + closed: () => dispose(), + }); } onMounted(() => { diff --git a/packages/frontend/src/widgets/WidgetCalendar.vue b/packages/frontend/src/widgets/WidgetCalendar.vue index c688e8a0b1..6ece33eff3 100644 --- a/packages/frontend/src/widgets/WidgetCalendar.vue +++ b/packages/frontend/src/widgets/WidgetCalendar.vue @@ -121,7 +121,7 @@ defineExpose({ .root { padding: 16px 0; - &:after { + &::after { content: ""; display: block; clear: both; diff --git a/packages/frontend/src/widgets/WidgetInstanceInfo.vue b/packages/frontend/src/widgets/WidgetInstanceInfo.vue index 25d824c8ae..5d8beaf9a9 100644 --- a/packages/frontend/src/widgets/WidgetInstanceInfo.vue +++ b/packages/frontend/src/widgets/WidgetInstanceInfo.vue @@ -81,16 +81,19 @@ defineExpose({ .body { text-overflow: ellipsis; overflow: clip; + margin-left: -10px; + padding: 10px; } .name { color: #fff; - filter: drop-shadow(0 0 4px #000); + filter: drop-shadow(0 0 4px #000) drop-shadow(0 0 0.1px rgba(0, 0, 0, 0.5)); font-weight: bold; } .host { color: #fff; - filter: drop-shadow(0 0 4px #000); + filter: drop-shadow(0 0 4px #000) drop-shadow(0 0 0.1px rgba(0, 0, 0, 0.5)); + } diff --git a/packages/frontend/src/widgets/WidgetNotifications.vue b/packages/frontend/src/widgets/WidgetNotifications.vue index 4b3265dab7..773c078b49 100644 --- a/packages/frontend/src/widgets/WidgetNotifications.vue +++ b/packages/frontend/src/widgets/WidgetNotifications.vue @@ -54,7 +54,7 @@ const { widgetProps, configure, save } = useWidgetPropsManager(name, ); const configureNotification = () => { - os.popup(defineAsyncComponent(() => import('@/components/MkNotificationSelectWindow.vue')), { + const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkNotificationSelectWindow.vue')), { excludeTypes: widgetProps.excludeTypes, }, { done: async (res) => { @@ -62,7 +62,8 @@ const configureNotification = () => { widgetProps.excludeTypes = excludeTypes; save(); }, - }, 'closed'); + closed: () => dispose(), + }); }; defineExpose({ diff --git a/packages/frontend/src/widgets/WidgetProfile.vue b/packages/frontend/src/widgets/WidgetProfile.vue index a5578d4de6..ae39098305 100644 --- a/packages/frontend/src/widgets/WidgetProfile.vue +++ b/packages/frontend/src/widgets/WidgetProfile.vue @@ -82,16 +82,19 @@ defineExpose({ .body { text-overflow: ellipsis; overflow: clip; + margin-left: -10px; + padding: 10px; } .name { color: #fff; - filter: drop-shadow(0 0 4px #000); + filter: drop-shadow(0 0 4px #000) drop-shadow(0 0 0.1px rgba(0, 0, 0, 0.5)); font-weight: bold; } .username { color: #fff; - filter: drop-shadow(0 0 4px #000); + filter: drop-shadow(0 0 4px #000) drop-shadow(0 0 0.1px rgba(0, 0, 0, 0.5)); + font-weight: normal; } diff --git a/packages/frontend/tsconfig.json b/packages/frontend/tsconfig.json index 819629a9cf..fe4d202894 100644 --- a/packages/frontend/tsconfig.json +++ b/packages/frontend/tsconfig.json @@ -37,13 +37,13 @@ ], "lib": [ "esnext", - "dom" + "dom", + "dom.iterable" ], "jsx": "preserve" }, "compileOnSave": false, "include": [ - ".eslintrc.js", "./**/*.ts", "./**/*.vue" ], diff --git a/packages/frontend/vite.config.local-dev.ts b/packages/frontend/vite.config.local-dev.ts index f9dff13b15..0a88e489c1 100644 --- a/packages/frontend/vite.config.local-dev.ts +++ b/packages/frontend/vite.config.local-dev.ts @@ -1,6 +1,8 @@ import dns from 'dns'; import { readFile } from 'node:fs/promises'; +import type { IncomingMessage } from 'node:http'; import { defineConfig } from 'vite'; +import type { UserConfig } from 'vite'; import * as yaml from 'js-yaml'; import locales from '../../locales/index.js'; import { getConfig } from './vite.config.js'; @@ -14,7 +16,15 @@ const { port } = yaml.load(await readFile('../../.config/default.yml', 'utf-8')) const httpUrl = `http://localhost:${port}/`; const websocketUrl = `ws://localhost:${port}/`; -const devConfig = { +// activitypubリクエストはProxyを通し、それ以外はViteの開発サーバーを返す +function varyHandler(req: IncomingMessage) { + if (req.headers.accept?.includes('application/activity+json')) { + return null; + } + return '/index.html'; +} + +const devConfig: UserConfig = { // 基本の設定は vite.config.js から引き継ぐ ...defaultConfig, root: 'src', @@ -54,15 +64,11 @@ const devConfig = { '/inbox': httpUrl, '/notes': { target: httpUrl, - headers: { - 'Accept': 'application/activity+json', - }, + bypass: varyHandler, }, '/users': { target: httpUrl, - headers: { - 'Accept': 'application/activity+json', - }, + bypass: varyHandler, }, '/.well-known': { target: httpUrl, diff --git a/packages/frontend/vite.config.ts b/packages/frontend/vite.config.ts index 82eb2af464..6decbc0ef7 100644 --- a/packages/frontend/vite.config.ts +++ b/packages/frontend/vite.config.ts @@ -5,7 +5,7 @@ import { type UserConfig, defineConfig } from 'vite'; import locales from '../../locales/index.js'; import meta from '../../package.json'; -import packageInfo from './package.json' assert { type: 'json' }; +import packageInfo from './package.json' with { type: 'json' }; import pluginUnwindCssModuleClassName from './lib/rollup-plugin-unwind-css-module-class-name.js'; import pluginJson5 from './vite.json5.js'; diff --git a/packages/misskey-bubble-game/.eslintignore b/packages/misskey-bubble-game/.eslintignore deleted file mode 100644 index 52ea8b3362..0000000000 --- a/packages/misskey-bubble-game/.eslintignore +++ /dev/null @@ -1,8 +0,0 @@ -node_modules -/built -/coverage -/.eslintrc.js -/jest.config.ts -/test -/test-d -build.js diff --git a/packages/misskey-bubble-game/.eslintrc.cjs b/packages/misskey-bubble-game/.eslintrc.cjs deleted file mode 100644 index e2e31e9e33..0000000000 --- a/packages/misskey-bubble-game/.eslintrc.cjs +++ /dev/null @@ -1,9 +0,0 @@ -module.exports = { - parserOptions: { - tsconfigRootDir: __dirname, - project: ['./tsconfig.json'], - }, - extends: [ - '../shared/.eslintrc.js', - ], -}; diff --git a/packages/misskey-bubble-game/build.js b/packages/misskey-bubble-game/build.js index 0b79f4b915..e626c97a59 100644 --- a/packages/misskey-bubble-game/build.js +++ b/packages/misskey-bubble-game/build.js @@ -95,7 +95,6 @@ async function watchSrc() { process.on('SIGHUP', resolve); process.on('SIGINT', resolve); process.on('SIGTERM', resolve); - process.on('SIGKILL', resolve); process.on('uncaughtException', reject); process.on('exit', resolve); }).finally(async () => { diff --git a/packages/misskey-bubble-game/eslint.config.js b/packages/misskey-bubble-game/eslint.config.js new file mode 100644 index 0000000000..86c21a22a3 --- /dev/null +++ b/packages/misskey-bubble-game/eslint.config.js @@ -0,0 +1,27 @@ +import tsParser from '@typescript-eslint/parser'; +import sharedConfig from '../shared/eslint.config.js'; + +export default [ + ...sharedConfig, + { + ignores: [ + '**/node_modules', + 'built', + 'coverage', + 'jest.config.ts', + 'test', + 'test-d', + ], + }, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + parser: tsParser, + project: ['./tsconfig.json'], + sourceType: 'module', + tsconfigRootDir: import.meta.dirname, + }, + }, + }, +]; diff --git a/packages/misskey-bubble-game/package.json b/packages/misskey-bubble-game/package.json index a3aad147a9..528eb00b74 100644 --- a/packages/misskey-bubble-game/package.json +++ b/packages/misskey-bubble-game/package.json @@ -17,18 +17,16 @@ "scripts": { "build": "node ./build.js", "watch": "nodemon -w package.json -e json --exec \"node ./build.js --watch\"", - "eslint": "eslint . --ext .js,.jsx,.ts,.tsx", + "eslint": "eslint './**/*.{js,jsx,ts,tsx}'", "typecheck": "tsc --noEmit", "lint": "pnpm typecheck && pnpm eslint" }, "devDependencies": { - "@misskey-dev/eslint-plugin": "1.0.0", "@types/matter-js": "0.19.6", "@types/seedrandom": "3.0.8", "@types/node": "20.11.5", "@typescript-eslint/eslint-plugin": "7.1.0", "@typescript-eslint/parser": "7.1.0", - "eslint": "8.57.0", "nodemon": "3.0.2", "execa": "8.0.1", "typescript": "5.3.3", diff --git a/packages/misskey-js/.eslintignore b/packages/misskey-js/.eslintignore deleted file mode 100644 index 52ea8b3362..0000000000 --- a/packages/misskey-js/.eslintignore +++ /dev/null @@ -1,8 +0,0 @@ -node_modules -/built -/coverage -/.eslintrc.js -/jest.config.ts -/test -/test-d -build.js diff --git a/packages/misskey-js/.eslintrc.cjs b/packages/misskey-js/.eslintrc.cjs deleted file mode 100644 index e2e31e9e33..0000000000 --- a/packages/misskey-js/.eslintrc.cjs +++ /dev/null @@ -1,9 +0,0 @@ -module.exports = { - parserOptions: { - tsconfigRootDir: __dirname, - project: ['./tsconfig.json'], - }, - extends: [ - '../shared/.eslintrc.js', - ], -}; diff --git a/packages/misskey-js/README.md b/packages/misskey-js/README.md index 63d4b36c56..4753e2434b 100644 --- a/packages/misskey-js/README.md +++ b/packages/misskey-js/README.md @@ -154,5 +154,5 @@ stream.on('_disconnected_', () => { ---
- +
diff --git a/packages/misskey-js/build.js b/packages/misskey-js/build.js index 0b79f4b915..a80b71646f 100644 --- a/packages/misskey-js/build.js +++ b/packages/misskey-js/build.js @@ -1,32 +1,32 @@ -import * as esbuild from "esbuild"; -import { build } from "esbuild"; -import { globSync } from "glob"; -import { execa } from "execa"; -import fs from "node:fs"; -import { fileURLToPath } from "node:url"; -import { dirname } from "node:path"; +import fs from 'node:fs'; +import { fileURLToPath } from 'node:url'; +import { dirname } from 'node:path'; +import * as esbuild from 'esbuild'; +import { build } from 'esbuild'; +import { globSync } from 'glob'; +import { execa } from 'execa'; const _filename = fileURLToPath(import.meta.url); const _dirname = dirname(_filename); const _package = JSON.parse(fs.readFileSync(_dirname + '/package.json', 'utf-8')); -const entryPoints = globSync("./src/**/**.{ts,tsx}"); +const entryPoints = globSync('./src/**/**.{ts,tsx}'); /** @type {import('esbuild').BuildOptions} */ const options = { entryPoints, minify: process.env.NODE_ENV === 'production', - outdir: "./built", - target: "es2022", - platform: "browser", - format: "esm", + outdir: './built', + target: 'es2022', + platform: 'browser', + format: 'esm', sourcemap: 'linked', }; // built配下をすべて削除する fs.rmSync('./built', { recursive: true, force: true }); -if (process.argv.map(arg => arg.toLowerCase()).includes("--watch")) { +if (process.argv.map(arg => arg.toLowerCase()).includes('--watch')) { await watchSrc(); } else { await buildSrc(); @@ -36,7 +36,7 @@ async function buildSrc() { console.log(`[${_package.name}] start building...`); await build(options) - .then(it => { + .then(() => { console.log(`[${_package.name}] build succeeded.`); }) .catch((err) => { @@ -65,7 +65,7 @@ function buildDts() { { stdout: process.stdout, stderr: process.stderr, - } + }, ); } @@ -86,7 +86,7 @@ async function watchSrc() { }, }]; - console.log(`[${_package.name}] start watching...`) + console.log(`[${_package.name}] start watching...`); const context = await esbuild.context({ ...options, plugins }); await context.watch(); @@ -95,7 +95,6 @@ async function watchSrc() { process.on('SIGHUP', resolve); process.on('SIGINT', resolve); process.on('SIGTERM', resolve); - process.on('SIGKILL', resolve); process.on('uncaughtException', reject); process.on('exit', resolve); }).finally(async () => { diff --git a/packages/misskey-js/eslint.config.js b/packages/misskey-js/eslint.config.js new file mode 100644 index 0000000000..e34e7510b2 --- /dev/null +++ b/packages/misskey-js/eslint.config.js @@ -0,0 +1,28 @@ +import tsParser from '@typescript-eslint/parser'; +import sharedConfig from '../shared/eslint.config.js'; + +export default [ + ...sharedConfig, + { + ignores: [ + '**/node_modules', + 'built', + 'coverage', + 'jest.config.ts', + 'test', + 'test-d', + 'generator', + ], + }, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + parser: tsParser, + project: ['./tsconfig.json'], + sourceType: 'module', + tsconfigRootDir: import.meta.dirname, + }, + }, + }, +]; diff --git a/packages/misskey-js/etc/misskey-js.api.md b/packages/misskey-js/etc/misskey-js.api.md index 3ffb3c8b21..c94c955bc5 100644 --- a/packages/misskey-js/etc/misskey-js.api.md +++ b/packages/misskey-js/etc/misskey-js.api.md @@ -6,6 +6,11 @@ import { EventEmitter } from 'eventemitter3'; +// Warning: (ae-forgotten-export) The symbol "components" needs to be exported by the entry point index.d.ts +// +// @public (undocumented) +type AbuseReportNotificationRecipient = components['schemas']['AbuseReportNotificationRecipient']; + // @public (undocumented) export type Acct = { username: string; @@ -21,13 +26,38 @@ declare namespace acct { } export { acct } -// Warning: (ae-forgotten-export) The symbol "components" needs to be exported by the entry point index.d.ts -// // @public (undocumented) type Ad = components['schemas']['Ad']; // Warning: (ae-forgotten-export) The symbol "operations" needs to be exported by the entry point index.d.ts // +// @public (undocumented) +type AdminAbuseReportNotificationRecipientCreateRequest = operations['admin___abuse-report___notification-recipient___create']['requestBody']['content']['application/json']; + +// @public (undocumented) +type AdminAbuseReportNotificationRecipientCreateResponse = operations['admin___abuse-report___notification-recipient___create']['responses']['200']['content']['application/json']; + +// @public (undocumented) +type AdminAbuseReportNotificationRecipientDeleteRequest = operations['admin___abuse-report___notification-recipient___delete']['requestBody']['content']['application/json']; + +// @public (undocumented) +type AdminAbuseReportNotificationRecipientListRequest = operations['admin___abuse-report___notification-recipient___list']['requestBody']['content']['application/json']; + +// @public (undocumented) +type AdminAbuseReportNotificationRecipientListResponse = operations['admin___abuse-report___notification-recipient___list']['responses']['200']['content']['application/json']; + +// @public (undocumented) +type AdminAbuseReportNotificationRecipientShowRequest = operations['admin___abuse-report___notification-recipient___show']['requestBody']['content']['application/json']; + +// @public (undocumented) +type AdminAbuseReportNotificationRecipientShowResponse = operations['admin___abuse-report___notification-recipient___show']['responses']['200']['content']['application/json']; + +// @public (undocumented) +type AdminAbuseReportNotificationRecipientUpdateRequest = operations['admin___abuse-report___notification-recipient___update']['requestBody']['content']['application/json']; + +// @public (undocumented) +type AdminAbuseReportNotificationRecipientUpdateResponse = operations['admin___abuse-report___notification-recipient___update']['responses']['200']['content']['application/json']; + // @public (undocumented) type AdminAbuseUserReportsRequest = operations['admin___abuse-user-reports']['requestBody']['content']['application/json']; @@ -307,6 +337,33 @@ type AdminShowUsersResponse = operations['admin___show-users']['responses']['200 // @public (undocumented) type AdminSuspendUserRequest = operations['admin___suspend-user']['requestBody']['content']['application/json']; +// @public (undocumented) +type AdminSystemWebhookCreateRequest = operations['admin___system-webhook___create']['requestBody']['content']['application/json']; + +// @public (undocumented) +type AdminSystemWebhookCreateResponse = operations['admin___system-webhook___create']['responses']['200']['content']['application/json']; + +// @public (undocumented) +type AdminSystemWebhookDeleteRequest = operations['admin___system-webhook___delete']['requestBody']['content']['application/json']; + +// @public (undocumented) +type AdminSystemWebhookListRequest = operations['admin___system-webhook___list']['requestBody']['content']['application/json']; + +// @public (undocumented) +type AdminSystemWebhookListResponse = operations['admin___system-webhook___list']['responses']['200']['content']['application/json']; + +// @public (undocumented) +type AdminSystemWebhookShowRequest = operations['admin___system-webhook___show']['requestBody']['content']['application/json']; + +// @public (undocumented) +type AdminSystemWebhookShowResponse = operations['admin___system-webhook___show']['responses']['200']['content']['application/json']; + +// @public (undocumented) +type AdminSystemWebhookUpdateRequest = operations['admin___system-webhook___update']['requestBody']['content']['application/json']; + +// @public (undocumented) +type AdminSystemWebhookUpdateResponse = operations['admin___system-webhook___update']['responses']['200']['content']['application/json']; + // @public (undocumented) type AdminUnsetUserAvatarRequest = operations['admin___unset-user-avatar']['requestBody']['content']['application/json']; @@ -1108,6 +1165,12 @@ export type Endpoints = Overwrite; + res: AdminRolesCreateResponse; + }; }>; // @public (undocumented) @@ -1133,11 +1196,21 @@ declare namespace entities { SignupPendingResponse, SigninRequest, SigninResponse, + PartialRolePolicyOverride, EmptyRequest, EmptyResponse, AdminMetaResponse, AdminAbuseUserReportsRequest, AdminAbuseUserReportsResponse, + AdminAbuseReportNotificationRecipientListRequest, + AdminAbuseReportNotificationRecipientListResponse, + AdminAbuseReportNotificationRecipientShowRequest, + AdminAbuseReportNotificationRecipientShowResponse, + AdminAbuseReportNotificationRecipientCreateRequest, + AdminAbuseReportNotificationRecipientCreateResponse, + AdminAbuseReportNotificationRecipientUpdateRequest, + AdminAbuseReportNotificationRecipientUpdateResponse, + AdminAbuseReportNotificationRecipientDeleteRequest, AdminAccountsCreateRequest, AdminAccountsCreateResponse, AdminAccountsDeleteRequest, @@ -1233,6 +1306,15 @@ declare namespace entities { AdminRolesUpdateDefaultPoliciesRequest, AdminRolesUsersRequest, AdminRolesUsersResponse, + AdminSystemWebhookCreateRequest, + AdminSystemWebhookCreateResponse, + AdminSystemWebhookDeleteRequest, + AdminSystemWebhookListRequest, + AdminSystemWebhookListResponse, + AdminSystemWebhookShowRequest, + AdminSystemWebhookShowResponse, + AdminSystemWebhookUpdateRequest, + AdminSystemWebhookUpdateResponse, AnnouncementsRequest, AnnouncementsResponse, AnnouncementsShowRequest, @@ -1738,7 +1820,9 @@ declare namespace entities { ReversiGameDetailed, MetaLite, MetaDetailedOnly, - MetaDetailed + MetaDetailed, + SystemWebhook, + AbuseReportNotificationRecipient } } export { entities } @@ -1797,7 +1881,7 @@ type FetchExternalResourcesResponse = operations['fetch-external-resources']['re // @public (undocumented) type FetchLike = (input: string, init?: { method?: string; - body?: string; + body?: Blob | FormData | string; credentials?: RequestCredentials; cache?: RequestCache; headers: { @@ -2385,8 +2469,23 @@ type ModerationLog = { type: 'unsetUserAvatar'; info: ModerationLogPayloads['unsetUserAvatar']; } | { - type: 'unsetUserBanner'; - info: ModerationLogPayloads['unsetUserBanner']; + type: 'createSystemWebhook'; + info: ModerationLogPayloads['createSystemWebhook']; +} | { + type: 'updateSystemWebhook'; + info: ModerationLogPayloads['updateSystemWebhook']; +} | { + type: 'deleteSystemWebhook'; + info: ModerationLogPayloads['deleteSystemWebhook']; +} | { + type: 'createAbuseReportNotificationRecipient'; + info: ModerationLogPayloads['createAbuseReportNotificationRecipient']; +} | { + type: 'updateAbuseReportNotificationRecipient'; + info: ModerationLogPayloads['updateAbuseReportNotificationRecipient']; +} | { + type: 'deleteAbuseReportNotificationRecipient'; + info: ModerationLogPayloads['deleteAbuseReportNotificationRecipient']; }); // @public (undocumented) @@ -2638,6 +2737,15 @@ type PagesUpdateRequest = operations['pages___update']['requestBody']['content'] // @public (undocumented) function parse(acct: string): Acct; +// Warning: (ae-forgotten-export) The symbol "Values" needs to be exported by the entry point index.d.ts +// +// @public (undocumented) +type PartialRolePolicyOverride = Partial<{ + [k in keyof RolePolicies]: Omit, 'value'> & { + value: RolePolicies[k]; + }; +}>; + // @public (undocumented) export const permissions: readonly ["read:account", "write:account", "read:blocks", "write:blocks", "read:drive", "write:drive", "read:favorites", "write:favorites", "read:following", "write:following", "read:messaging", "write:messaging", "read:mutes", "write:mutes", "write:notes", "read:notifications", "write:notifications", "read:reactions", "write:reactions", "write:votes", "read:pages", "write:pages", "write:page-likes", "read:page-likes", "read:user-groups", "write:user-groups", "read:channels", "write:channels", "read:gallery", "write:gallery", "read:gallery-likes", "write:gallery-likes", "read:flash", "write:flash", "read:flash-likes", "write:flash-likes", "read:admin:abuse-user-reports", "write:admin:delete-account", "write:admin:delete-all-files-of-a-user", "read:admin:index-stats", "read:admin:table-stats", "read:admin:user-ips", "read:admin:meta", "write:admin:reset-password", "write:admin:resolve-abuse-user-report", "write:admin:send-email", "read:admin:server-info", "read:admin:show-moderation-log", "read:admin:show-user", "write:admin:suspend-user", "write:admin:unset-user-avatar", "write:admin:unset-user-banner", "write:admin:unsuspend-user", "write:admin:meta", "write:admin:user-note", "write:admin:roles", "read:admin:roles", "write:admin:relays", "read:admin:relays", "write:admin:invite-codes", "read:admin:invite-codes", "write:admin:announcements", "read:admin:announcements", "write:admin:avatar-decorations", "read:admin:avatar-decorations", "write:admin:federation", "write:admin:account", "read:admin:account", "write:admin:emoji", "read:admin:emoji", "write:admin:queue", "read:admin:queue", "write:admin:promo", "write:admin:drive", "read:admin:drive", "write:admin:ad", "read:admin:ad", "write:invite-codes", "read:invite-codes", "write:clip-favorite", "read:clip-favorite", "read:federation", "write:report-abuse"]; @@ -2926,6 +3034,9 @@ type SwUpdateRegistrationRequest = operations['sw___update-registration']['reque // @public (undocumented) type SwUpdateRegistrationResponse = operations['sw___update-registration']['responses']['200']['content']['application/json']; +// @public (undocumented) +type SystemWebhook = components['schemas']['SystemWebhook']; + // @public (undocumented) type TestRequest = operations['test']['requestBody']['content']['application/json']; @@ -3123,7 +3234,7 @@ type UsersUpdateMemoRequest = operations['users___update-memo']['requestBody'][' // Warnings were encountered during analysis: // -// src/entities.ts:25:2 - (ae-forgotten-export) The symbol "ModerationLogPayloads" needs to be exported by the entry point index.d.ts +// src/entities.ts:34:2 - (ae-forgotten-export) The symbol "ModerationLogPayloads" needs to be exported by the entry point index.d.ts // (No @packageDocumentation comment for this package) diff --git a/packages/misskey-js/generator/.eslintrc.cjs b/packages/misskey-js/generator/.eslintrc.cjs deleted file mode 100644 index 6a8b31da9c..0000000000 --- a/packages/misskey-js/generator/.eslintrc.cjs +++ /dev/null @@ -1,9 +0,0 @@ -module.exports = { - parserOptions: { - tsconfigRootDir: __dirname, - project: ['./tsconfig.json'], - }, - extends: [ - '../../shared/.eslintrc.js', - ], -}; diff --git a/packages/misskey-js/generator/eslint.config.js b/packages/misskey-js/generator/eslint.config.js new file mode 100644 index 0000000000..4bf78c3b91 --- /dev/null +++ b/packages/misskey-js/generator/eslint.config.js @@ -0,0 +1,17 @@ +import tsParser from '@typescript-eslint/parser'; +import sharedConfig from '../../shared/eslint.config.js'; + +export default [ + ...sharedConfig, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + parser: tsParser, + project: ['./tsconfig.json'], + sourceType: 'module', + tsconfigRootDir: import.meta.dirname, + }, + }, + }, +]; diff --git a/packages/misskey-js/generator/package.json b/packages/misskey-js/generator/package.json index a1c0f41cb2..4a02bcd8ff 100644 --- a/packages/misskey-js/generator/package.json +++ b/packages/misskey-js/generator/package.json @@ -4,15 +4,13 @@ "description": "Misskey TypeGenerator", "type": "module", "scripts": { - "generate": "tsx src/generator.ts && eslint ./built/**/* --ext .ts --fix" + "generate": "tsx src/generator.ts && eslint ./built/**/*.ts --fix" }, "devDependencies": { - "@misskey-dev/eslint-plugin": "^1.0.0", "@readme/openapi-parser": "2.5.0", "@types/node": "20.9.1", "@typescript-eslint/eslint-plugin": "6.11.0", "@typescript-eslint/parser": "6.11.0", - "eslint": "8.53.0", "openapi-types": "12.1.3", "openapi-typescript": "6.7.3", "ts-case-convert": "2.0.2", diff --git a/packages/misskey-js/generator/src/generator.ts b/packages/misskey-js/generator/src/generator.ts index 78178d7c7e..4ae00a4522 100644 --- a/packages/misskey-js/generator/src/generator.ts +++ b/packages/misskey-js/generator/src/generator.ts @@ -20,7 +20,14 @@ async function generateBaseTypes( } lines.push(''); - const generatedTypes = await openapiTS(openApiJsonPath, { exportType: true }); + const generatedTypes = await openapiTS(openApiJsonPath, { + exportType: true, + transform(schemaObject) { + if ('format' in schemaObject && schemaObject.format === 'binary') { + return schemaObject.nullable ? 'Blob | null' : 'Blob'; + } + }, + }); lines.push(generatedTypes); lines.push(''); @@ -56,6 +63,8 @@ async function generateEndpoints( endpointOutputPath: string, ) { const endpoints: Endpoint[] = []; + const endpointReqMediaTypes: EndpointReqMediaType[] = []; + const endpointReqMediaTypesSet = new Set(); // misskey-jsはPOST固定で送っているので、こちらも決め打ちする。別メソッドに対応することがあればこちらも直す必要あり const paths = openApiDocs.paths ?? {}; @@ -78,13 +87,24 @@ async function generateEndpoints( const supportMediaTypes = Object.keys(reqContent); if (supportMediaTypes.length > 0) { // いまのところ複数のメディアタイプをとるエンドポイントは無いので決め打ちする - endpoint.request = new OperationTypeAlias( + const req = new OperationTypeAlias( operationId, path, supportMediaTypes[0], OperationsAliasType.REQUEST, ); + endpoint.request = req; + + const reqType = new EndpointReqMediaType(path, req); + endpointReqMediaTypesSet.add(reqType.getMediaType()); + endpointReqMediaTypes.push(reqType); + } else { + endpointReqMediaTypesSet.add('application/json'); + endpointReqMediaTypes.push(new EndpointReqMediaType(path, undefined, 'application/json')); } + } else { + endpointReqMediaTypesSet.add('application/json'); + endpointReqMediaTypes.push(new EndpointReqMediaType(path, undefined, 'application/json')); } if (operation.responses && isResponseObject(operation.responses['200']) && operation.responses['200'].content) { @@ -137,6 +157,19 @@ async function generateEndpoints( endpointOutputLine.push('}'); endpointOutputLine.push(''); + function generateEndpointReqMediaTypesType() { + return `Record `'${t}'`).join(' | ')}>`; + } + + endpointOutputLine.push(`export const endpointReqTypes: ${generateEndpointReqMediaTypesType()} = {`); + + endpointOutputLine.push( + ...endpointReqMediaTypes.map(it => '\t' + it.toLine()), + ); + + endpointOutputLine.push('};'); + endpointOutputLine.push(''); + await writeFile(endpointOutputPath, endpointOutputLine.join('\n')); } @@ -314,6 +347,26 @@ class Endpoint { } } +class EndpointReqMediaType { + public readonly path: string; + public readonly mediaType: string; + + constructor(path: string, request: OperationTypeAlias, mediaType?: undefined); + constructor(path: string, request: undefined, mediaType: string); + constructor(path: string, request: OperationTypeAlias | undefined, mediaType?: string) { + this.path = path; + this.mediaType = mediaType ?? request?.mediaType ?? 'application/json'; + } + + getMediaType(): string { + return this.mediaType; + } + + toLine(): string { + return `'${this.path}': '${this.mediaType}',`; + } +} + async function main() { const generatePath = './built/autogen'; await mkdir(generatePath, { recursive: true }); diff --git a/packages/misskey-js/package.json b/packages/misskey-js/package.json index 4ff1a57309..d494b6b58e 100644 --- a/packages/misskey-js/package.json +++ b/packages/misskey-js/package.json @@ -1,7 +1,7 @@ { "type": "module", "name": "misskey-js", - "version": "2024.5.0", + "version": "2024.7.0-beta.1", "description": "Misskey SDK for JavaScript", "license": "MIT", "main": "./built/index.js", @@ -22,7 +22,7 @@ "tsd": "tsd", "api": "pnpm api-extractor run --local --verbose", "api-prod": "pnpm api-extractor run --verbose", - "eslint": "eslint . --ext .js,.jsx,.ts,.tsx", + "eslint": "eslint './**/*.{js,jsx,ts,tsx}'", "typecheck": "tsc --noEmit", "lint": "pnpm typecheck && pnpm eslint", "jest": "jest --coverage --detectOpenHandles", @@ -35,25 +35,23 @@ "directory": "packages/misskey-js" }, "devDependencies": { - "@microsoft/api-extractor": "7.43.1", - "@misskey-dev/eslint-plugin": "1.0.0", + "@microsoft/api-extractor": "7.47.0", "@swc/jest": "0.2.36", "@types/jest": "29.5.12", - "@types/node": "20.12.7", - "@typescript-eslint/eslint-plugin": "7.7.1", - "@typescript-eslint/parser": "7.7.1", - "eslint": "8.57.0", + "@types/node": "20.14.9", + "@typescript-eslint/eslint-plugin": "7.15.0", + "@typescript-eslint/parser": "7.15.0", "jest": "29.7.0", "jest-fetch-mock": "3.0.3", "jest-websocket-mock": "2.5.0", "mock-socket": "9.3.1", "ncp": "2.0.0", - "nodemon": "3.1.0", - "execa": "8.0.1", - "tsd": "0.30.7", - "typescript": "5.4.5", - "esbuild": "0.19.11", - "glob": "10.3.12" + "nodemon": "3.1.4", + "execa": "9.2.0", + "tsd": "0.31.1", + "typescript": "5.5.3", + "esbuild": "0.22.0", + "glob": "10.4.2" }, "files": [ "built" diff --git a/packages/misskey-js/src/api.ts b/packages/misskey-js/src/api.ts index 959a634a74..76d055cbe4 100644 --- a/packages/misskey-js/src/api.ts +++ b/packages/misskey-js/src/api.ts @@ -1,7 +1,7 @@ import './autogen/apiClientJSDoc.js'; -import { SwitchCaseResponseType } from './api.types.js'; -import type { Endpoints } from './api.types.js'; +import { endpointReqTypes } from './autogen/endpoint.js'; +import type { SwitchCaseResponseType, Endpoints } from './api.types.js'; export type { SwitchCaseResponseType, @@ -23,7 +23,7 @@ export function isAPIError(reason: Record): reason is APIE export type FetchLike = (input: string, init?: { method?: string; - body?: string; + body?: Blob | FormData | string; credentials?: RequestCredentials; cache?: RequestCache; headers: { [key in string]: string } @@ -49,20 +49,55 @@ export class APIClient { this.fetch = opts.fetch ?? ((...args) => fetch(...args)); } + private assertIsRecord(obj: T): obj is T & Record { + return obj !== null && typeof obj === 'object' && !Array.isArray(obj); + } + public request( endpoint: E, params: P = {} as P, credential?: string | null, ): Promise> { return new Promise((resolve, reject) => { - this.fetch(`${this.origin}/api/${endpoint}`, { - method: 'POST', - body: JSON.stringify({ + let mediaType = 'application/json'; + if (endpoint in endpointReqTypes) { + mediaType = endpointReqTypes[endpoint]; + } + let payload: FormData | string = '{}'; + + if (mediaType === 'application/json') { + payload = JSON.stringify({ ...params, i: credential !== undefined ? credential : this.credential, - }), + }); + } else if (mediaType === 'multipart/form-data') { + payload = new FormData(); + const i = credential !== undefined ? credential : this.credential; + if (i != null) { + payload.append('i', i); + } + if (this.assertIsRecord(params)) { + for (const key in params) { + const value = params[key]; + + if (value == null) continue; + + if (value instanceof File || value instanceof Blob) { + payload.append(key, value); + } else if (typeof value === 'object') { + payload.append(key, JSON.stringify(value)); + } else { + payload.append(key, value); + } + } + } + } + + this.fetch(`${this.origin}/api/${endpoint}`, { + method: 'POST', + body: payload, headers: { - 'Content-Type': 'application/json', + 'Content-Type': endpointReqTypes[endpoint], }, credentials: 'omit', cache: 'no-cache', diff --git a/packages/misskey-js/src/api.types.ts b/packages/misskey-js/src/api.types.ts index af0bade5b3..8c403639b7 100644 --- a/packages/misskey-js/src/api.types.ts +++ b/packages/misskey-js/src/api.types.ts @@ -1,7 +1,8 @@ import { Endpoints as Gen } from './autogen/endpoint.js'; import { UserDetailed } from './autogen/models.js'; -import { UsersShowRequest } from './autogen/entities.js'; +import { AdminRolesCreateRequest, AdminRolesCreateResponse, UsersShowRequest } from './autogen/entities.js'; import { + PartialRolePolicyOverride, SigninRequest, SigninResponse, SignupPendingRequest, @@ -79,5 +80,9 @@ export type Endpoints = Overwrite< req: SigninRequest; res: SigninResponse; }, + 'admin/roles/create': { + req: Overwrite; + res: AdminRolesCreateResponse; + } } > diff --git a/packages/misskey-js/src/autogen/apiClientJSDoc.ts b/packages/misskey-js/src/autogen/apiClientJSDoc.ts index 181f7274b7..e799d4a0c5 100644 --- a/packages/misskey-js/src/autogen/apiClientJSDoc.ts +++ b/packages/misskey-js/src/autogen/apiClientJSDoc.ts @@ -25,6 +25,66 @@ declare module '../api.js' { credential?: string | null, ): Promise>; + /** + * No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* / **Permission**: *read:admin:abuse-report:notification-recipient* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* / **Permission**: *read:admin:abuse-report:notification-recipient* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* / **Permission**: *write:admin:abuse-report:notification-recipient* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* / **Permission**: *write:admin:abuse-report:notification-recipient* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* / **Permission**: *write:admin:abuse-report:notification-recipient* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + /** * No description provided. * @@ -840,6 +900,66 @@ declare module '../api.js' { credential?: string | null, ): Promise>; + /** + * No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* / **Permission**: *write:admin:system-webhook* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* / **Permission**: *write:admin:system-webhook* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* / **Permission**: *write:admin:system-webhook* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* / **Permission**: *write:admin:system-webhook* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + + /** + * No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* / **Permission**: *write:admin:system-webhook* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + /** * No description provided. * diff --git a/packages/misskey-js/src/autogen/endpoint.ts b/packages/misskey-js/src/autogen/endpoint.ts index ab3baf1670..be41951e4d 100644 --- a/packages/misskey-js/src/autogen/endpoint.ts +++ b/packages/misskey-js/src/autogen/endpoint.ts @@ -4,6 +4,15 @@ import type { AdminMetaResponse, AdminAbuseUserReportsRequest, AdminAbuseUserReportsResponse, + AdminAbuseReportNotificationRecipientListRequest, + AdminAbuseReportNotificationRecipientListResponse, + AdminAbuseReportNotificationRecipientShowRequest, + AdminAbuseReportNotificationRecipientShowResponse, + AdminAbuseReportNotificationRecipientCreateRequest, + AdminAbuseReportNotificationRecipientCreateResponse, + AdminAbuseReportNotificationRecipientUpdateRequest, + AdminAbuseReportNotificationRecipientUpdateResponse, + AdminAbuseReportNotificationRecipientDeleteRequest, AdminAccountsCreateRequest, AdminAccountsCreateResponse, AdminAccountsDeleteRequest, @@ -99,6 +108,15 @@ import type { AdminRolesUpdateDefaultPoliciesRequest, AdminRolesUsersRequest, AdminRolesUsersResponse, + AdminSystemWebhookCreateRequest, + AdminSystemWebhookCreateResponse, + AdminSystemWebhookDeleteRequest, + AdminSystemWebhookListRequest, + AdminSystemWebhookListResponse, + AdminSystemWebhookShowRequest, + AdminSystemWebhookShowResponse, + AdminSystemWebhookUpdateRequest, + AdminSystemWebhookUpdateResponse, AnnouncementsRequest, AnnouncementsResponse, AnnouncementsShowRequest, @@ -558,6 +576,11 @@ import type { export type Endpoints = { 'admin/meta': { req: EmptyRequest; res: AdminMetaResponse }; 'admin/abuse-user-reports': { req: AdminAbuseUserReportsRequest; res: AdminAbuseUserReportsResponse }; + 'admin/abuse-report/notification-recipient/list': { req: AdminAbuseReportNotificationRecipientListRequest; res: AdminAbuseReportNotificationRecipientListResponse }; + 'admin/abuse-report/notification-recipient/show': { req: AdminAbuseReportNotificationRecipientShowRequest; res: AdminAbuseReportNotificationRecipientShowResponse }; + 'admin/abuse-report/notification-recipient/create': { req: AdminAbuseReportNotificationRecipientCreateRequest; res: AdminAbuseReportNotificationRecipientCreateResponse }; + 'admin/abuse-report/notification-recipient/update': { req: AdminAbuseReportNotificationRecipientUpdateRequest; res: AdminAbuseReportNotificationRecipientUpdateResponse }; + 'admin/abuse-report/notification-recipient/delete': { req: AdminAbuseReportNotificationRecipientDeleteRequest; res: EmptyResponse }; 'admin/accounts/create': { req: AdminAccountsCreateRequest; res: AdminAccountsCreateResponse }; 'admin/accounts/delete': { req: AdminAccountsDeleteRequest; res: EmptyResponse }; 'admin/accounts/find-by-email': { req: AdminAccountsFindByEmailRequest; res: AdminAccountsFindByEmailResponse }; @@ -632,6 +655,11 @@ export type Endpoints = { 'admin/roles/unassign': { req: AdminRolesUnassignRequest; res: EmptyResponse }; 'admin/roles/update-default-policies': { req: AdminRolesUpdateDefaultPoliciesRequest; res: EmptyResponse }; 'admin/roles/users': { req: AdminRolesUsersRequest; res: AdminRolesUsersResponse }; + 'admin/system-webhook/create': { req: AdminSystemWebhookCreateRequest; res: AdminSystemWebhookCreateResponse }; + 'admin/system-webhook/delete': { req: AdminSystemWebhookDeleteRequest; res: EmptyResponse }; + 'admin/system-webhook/list': { req: AdminSystemWebhookListRequest; res: AdminSystemWebhookListResponse }; + 'admin/system-webhook/show': { req: AdminSystemWebhookShowRequest; res: AdminSystemWebhookShowResponse }; + 'admin/system-webhook/update': { req: AdminSystemWebhookUpdateRequest; res: AdminSystemWebhookUpdateResponse }; 'announcements': { req: AnnouncementsRequest; res: AnnouncementsResponse }; 'announcements/show': { req: AnnouncementsShowRequest; res: AnnouncementsShowResponse }; 'antennas/create': { req: AntennasCreateRequest; res: AntennasCreateResponse }; @@ -926,3 +954,385 @@ export type Endpoints = { 'reversi/surrender': { req: ReversiSurrenderRequest; res: EmptyResponse }; 'reversi/verify': { req: ReversiVerifyRequest; res: ReversiVerifyResponse }; } + +export const endpointReqTypes: Record = { + 'admin/meta': 'application/json', + 'admin/abuse-user-reports': 'application/json', + 'admin/abuse-report/notification-recipient/list': 'application/json', + 'admin/abuse-report/notification-recipient/show': 'application/json', + 'admin/abuse-report/notification-recipient/create': 'application/json', + 'admin/abuse-report/notification-recipient/update': 'application/json', + 'admin/abuse-report/notification-recipient/delete': 'application/json', + 'admin/accounts/create': 'application/json', + 'admin/accounts/delete': 'application/json', + 'admin/accounts/find-by-email': 'application/json', + 'admin/ad/create': 'application/json', + 'admin/ad/delete': 'application/json', + 'admin/ad/list': 'application/json', + 'admin/ad/update': 'application/json', + 'admin/announcements/create': 'application/json', + 'admin/announcements/delete': 'application/json', + 'admin/announcements/list': 'application/json', + 'admin/announcements/update': 'application/json', + 'admin/avatar-decorations/create': 'application/json', + 'admin/avatar-decorations/delete': 'application/json', + 'admin/avatar-decorations/list': 'application/json', + 'admin/avatar-decorations/update': 'application/json', + 'admin/delete-all-files-of-a-user': 'application/json', + 'admin/unset-user-avatar': 'application/json', + 'admin/unset-user-banner': 'application/json', + 'admin/drive/clean-remote-files': 'application/json', + 'admin/drive/cleanup': 'application/json', + 'admin/drive/files': 'application/json', + 'admin/drive/show-file': 'application/json', + 'admin/emoji/add-aliases-bulk': 'application/json', + 'admin/emoji/add': 'application/json', + 'admin/emoji/copy': 'application/json', + 'admin/emoji/delete-bulk': 'application/json', + 'admin/emoji/delete': 'application/json', + 'admin/emoji/import-zip': 'application/json', + 'admin/emoji/list-remote': 'application/json', + 'admin/emoji/list': 'application/json', + 'admin/emoji/remove-aliases-bulk': 'application/json', + 'admin/emoji/set-aliases-bulk': 'application/json', + 'admin/emoji/set-category-bulk': 'application/json', + 'admin/emoji/set-license-bulk': 'application/json', + 'admin/emoji/update': 'application/json', + 'admin/federation/delete-all-files': 'application/json', + 'admin/federation/refresh-remote-instance-metadata': 'application/json', + 'admin/federation/remove-all-following': 'application/json', + 'admin/federation/update-instance': 'application/json', + 'admin/get-index-stats': 'application/json', + 'admin/get-table-stats': 'application/json', + 'admin/get-user-ips': 'application/json', + 'admin/invite/create': 'application/json', + 'admin/invite/list': 'application/json', + 'admin/promo/create': 'application/json', + 'admin/queue/clear': 'application/json', + 'admin/queue/deliver-delayed': 'application/json', + 'admin/queue/inbox-delayed': 'application/json', + 'admin/queue/promote': 'application/json', + 'admin/queue/stats': 'application/json', + 'admin/relays/add': 'application/json', + 'admin/relays/list': 'application/json', + 'admin/relays/remove': 'application/json', + 'admin/reset-password': 'application/json', + 'admin/resolve-abuse-user-report': 'application/json', + 'admin/send-email': 'application/json', + 'admin/server-info': 'application/json', + 'admin/show-moderation-logs': 'application/json', + 'admin/show-user': 'application/json', + 'admin/show-users': 'application/json', + 'admin/suspend-user': 'application/json', + 'admin/unsuspend-user': 'application/json', + 'admin/update-meta': 'application/json', + 'admin/delete-account': 'application/json', + 'admin/update-user-note': 'application/json', + 'admin/roles/create': 'application/json', + 'admin/roles/delete': 'application/json', + 'admin/roles/list': 'application/json', + 'admin/roles/show': 'application/json', + 'admin/roles/update': 'application/json', + 'admin/roles/assign': 'application/json', + 'admin/roles/unassign': 'application/json', + 'admin/roles/update-default-policies': 'application/json', + 'admin/roles/users': 'application/json', + 'admin/system-webhook/create': 'application/json', + 'admin/system-webhook/delete': 'application/json', + 'admin/system-webhook/list': 'application/json', + 'admin/system-webhook/show': 'application/json', + 'admin/system-webhook/update': 'application/json', + 'announcements': 'application/json', + 'announcements/show': 'application/json', + 'antennas/create': 'application/json', + 'antennas/delete': 'application/json', + 'antennas/list': 'application/json', + 'antennas/notes': 'application/json', + 'antennas/show': 'application/json', + 'antennas/update': 'application/json', + 'ap/get': 'application/json', + 'ap/show': 'application/json', + 'app/create': 'application/json', + 'app/show': 'application/json', + 'auth/accept': 'application/json', + 'auth/session/generate': 'application/json', + 'auth/session/show': 'application/json', + 'auth/session/userkey': 'application/json', + 'blocking/create': 'application/json', + 'blocking/delete': 'application/json', + 'blocking/list': 'application/json', + 'channels/create': 'application/json', + 'channels/featured': 'application/json', + 'channels/follow': 'application/json', + 'channels/followed': 'application/json', + 'channels/owned': 'application/json', + 'channels/show': 'application/json', + 'channels/timeline': 'application/json', + 'channels/unfollow': 'application/json', + 'channels/update': 'application/json', + 'channels/favorite': 'application/json', + 'channels/unfavorite': 'application/json', + 'channels/my-favorites': 'application/json', + 'channels/search': 'application/json', + 'charts/active-users': 'application/json', + 'charts/ap-request': 'application/json', + 'charts/drive': 'application/json', + 'charts/federation': 'application/json', + 'charts/instance': 'application/json', + 'charts/notes': 'application/json', + 'charts/user/drive': 'application/json', + 'charts/user/following': 'application/json', + 'charts/user/notes': 'application/json', + 'charts/user/pv': 'application/json', + 'charts/user/reactions': 'application/json', + 'charts/users': 'application/json', + 'clips/add-note': 'application/json', + 'clips/remove-note': 'application/json', + 'clips/create': 'application/json', + 'clips/delete': 'application/json', + 'clips/list': 'application/json', + 'clips/notes': 'application/json', + 'clips/show': 'application/json', + 'clips/update': 'application/json', + 'clips/favorite': 'application/json', + 'clips/unfavorite': 'application/json', + 'clips/my-favorites': 'application/json', + 'drive': 'application/json', + 'drive/files': 'application/json', + 'drive/files/attached-notes': 'application/json', + 'drive/files/check-existence': 'application/json', + 'drive/files/create': 'multipart/form-data', + 'drive/files/delete': 'application/json', + 'drive/files/find-by-hash': 'application/json', + 'drive/files/find': 'application/json', + 'drive/files/show': 'application/json', + 'drive/files/update': 'application/json', + 'drive/files/upload-from-url': 'application/json', + 'drive/folders': 'application/json', + 'drive/folders/create': 'application/json', + 'drive/folders/delete': 'application/json', + 'drive/folders/find': 'application/json', + 'drive/folders/show': 'application/json', + 'drive/folders/update': 'application/json', + 'drive/stream': 'application/json', + 'email-address/available': 'application/json', + 'endpoint': 'application/json', + 'endpoints': 'application/json', + 'export-custom-emojis': 'application/json', + 'federation/followers': 'application/json', + 'federation/following': 'application/json', + 'federation/instances': 'application/json', + 'federation/show-instance': 'application/json', + 'federation/update-remote-user': 'application/json', + 'federation/users': 'application/json', + 'federation/stats': 'application/json', + 'following/create': 'application/json', + 'following/delete': 'application/json', + 'following/update': 'application/json', + 'following/update-all': 'application/json', + 'following/invalidate': 'application/json', + 'following/requests/accept': 'application/json', + 'following/requests/cancel': 'application/json', + 'following/requests/list': 'application/json', + 'following/requests/reject': 'application/json', + 'gallery/featured': 'application/json', + 'gallery/popular': 'application/json', + 'gallery/posts': 'application/json', + 'gallery/posts/create': 'application/json', + 'gallery/posts/delete': 'application/json', + 'gallery/posts/like': 'application/json', + 'gallery/posts/show': 'application/json', + 'gallery/posts/unlike': 'application/json', + 'gallery/posts/update': 'application/json', + 'get-online-users-count': 'application/json', + 'get-avatar-decorations': 'application/json', + 'hashtags/list': 'application/json', + 'hashtags/search': 'application/json', + 'hashtags/show': 'application/json', + 'hashtags/trend': 'application/json', + 'hashtags/users': 'application/json', + 'i': 'application/json', + 'i/2fa/done': 'application/json', + 'i/2fa/key-done': 'application/json', + 'i/2fa/password-less': 'application/json', + 'i/2fa/register-key': 'application/json', + 'i/2fa/register': 'application/json', + 'i/2fa/update-key': 'application/json', + 'i/2fa/remove-key': 'application/json', + 'i/2fa/unregister': 'application/json', + 'i/apps': 'application/json', + 'i/authorized-apps': 'application/json', + 'i/claim-achievement': 'application/json', + 'i/change-password': 'application/json', + 'i/delete-account': 'application/json', + 'i/export-blocking': 'application/json', + 'i/export-following': 'application/json', + 'i/export-mute': 'application/json', + 'i/export-notes': 'application/json', + 'i/export-clips': 'application/json', + 'i/export-favorites': 'application/json', + 'i/export-user-lists': 'application/json', + 'i/export-antennas': 'application/json', + 'i/favorites': 'application/json', + 'i/gallery/likes': 'application/json', + 'i/gallery/posts': 'application/json', + 'i/import-blocking': 'application/json', + 'i/import-following': 'application/json', + 'i/import-muting': 'application/json', + 'i/import-user-lists': 'application/json', + 'i/import-antennas': 'application/json', + 'i/notifications': 'application/json', + 'i/notifications-grouped': 'application/json', + 'i/page-likes': 'application/json', + 'i/pages': 'application/json', + 'i/pin': 'application/json', + 'i/read-all-unread-notes': 'application/json', + 'i/read-announcement': 'application/json', + 'i/regenerate-token': 'application/json', + 'i/registry/get-all': 'application/json', + 'i/registry/get-detail': 'application/json', + 'i/registry/get': 'application/json', + 'i/registry/keys-with-type': 'application/json', + 'i/registry/keys': 'application/json', + 'i/registry/remove': 'application/json', + 'i/registry/scopes-with-domain': 'application/json', + 'i/registry/set': 'application/json', + 'i/revoke-token': 'application/json', + 'i/signin-history': 'application/json', + 'i/unpin': 'application/json', + 'i/update-email': 'application/json', + 'i/update': 'application/json', + 'i/move': 'application/json', + 'i/webhooks/create': 'application/json', + 'i/webhooks/list': 'application/json', + 'i/webhooks/show': 'application/json', + 'i/webhooks/update': 'application/json', + 'i/webhooks/delete': 'application/json', + 'invite/create': 'application/json', + 'invite/delete': 'application/json', + 'invite/list': 'application/json', + 'invite/limit': 'application/json', + 'meta': 'application/json', + 'emojis': 'application/json', + 'emoji': 'application/json', + 'miauth/gen-token': 'application/json', + 'mute/create': 'application/json', + 'mute/delete': 'application/json', + 'mute/list': 'application/json', + 'renote-mute/create': 'application/json', + 'renote-mute/delete': 'application/json', + 'renote-mute/list': 'application/json', + 'my/apps': 'application/json', + 'notes': 'application/json', + 'notes/children': 'application/json', + 'notes/clips': 'application/json', + 'notes/conversation': 'application/json', + 'notes/create': 'application/json', + 'notes/delete': 'application/json', + 'notes/favorites/create': 'application/json', + 'notes/favorites/delete': 'application/json', + 'notes/featured': 'application/json', + 'notes/global-timeline': 'application/json', + 'notes/hybrid-timeline': 'application/json', + 'notes/local-timeline': 'application/json', + 'notes/mentions': 'application/json', + 'notes/polls/recommendation': 'application/json', + 'notes/polls/vote': 'application/json', + 'notes/reactions': 'application/json', + 'notes/reactions/create': 'application/json', + 'notes/reactions/delete': 'application/json', + 'notes/renotes': 'application/json', + 'notes/replies': 'application/json', + 'notes/search-by-tag': 'application/json', + 'notes/search': 'application/json', + 'notes/show': 'application/json', + 'notes/state': 'application/json', + 'notes/thread-muting/create': 'application/json', + 'notes/thread-muting/delete': 'application/json', + 'notes/timeline': 'application/json', + 'notes/translate': 'application/json', + 'notes/unrenote': 'application/json', + 'notes/user-list-timeline': 'application/json', + 'notifications/create': 'application/json', + 'notifications/flush': 'application/json', + 'notifications/mark-all-as-read': 'application/json', + 'notifications/test-notification': 'application/json', + 'page-push': 'application/json', + 'pages/create': 'application/json', + 'pages/delete': 'application/json', + 'pages/featured': 'application/json', + 'pages/like': 'application/json', + 'pages/show': 'application/json', + 'pages/unlike': 'application/json', + 'pages/update': 'application/json', + 'flash/create': 'application/json', + 'flash/delete': 'application/json', + 'flash/featured': 'application/json', + 'flash/like': 'application/json', + 'flash/show': 'application/json', + 'flash/unlike': 'application/json', + 'flash/update': 'application/json', + 'flash/my': 'application/json', + 'flash/my-likes': 'application/json', + 'ping': 'application/json', + 'pinned-users': 'application/json', + 'promo/read': 'application/json', + 'roles/list': 'application/json', + 'roles/show': 'application/json', + 'roles/users': 'application/json', + 'roles/notes': 'application/json', + 'request-reset-password': 'application/json', + 'reset-db': 'application/json', + 'reset-password': 'application/json', + 'server-info': 'application/json', + 'stats': 'application/json', + 'sw/show-registration': 'application/json', + 'sw/update-registration': 'application/json', + 'sw/register': 'application/json', + 'sw/unregister': 'application/json', + 'test': 'application/json', + 'username/available': 'application/json', + 'users': 'application/json', + 'users/clips': 'application/json', + 'users/followers': 'application/json', + 'users/following': 'application/json', + 'users/gallery/posts': 'application/json', + 'users/get-frequently-replied-users': 'application/json', + 'users/featured-notes': 'application/json', + 'users/lists/create': 'application/json', + 'users/lists/delete': 'application/json', + 'users/lists/list': 'application/json', + 'users/lists/pull': 'application/json', + 'users/lists/push': 'application/json', + 'users/lists/show': 'application/json', + 'users/lists/favorite': 'application/json', + 'users/lists/unfavorite': 'application/json', + 'users/lists/update': 'application/json', + 'users/lists/create-from-public': 'application/json', + 'users/lists/update-membership': 'application/json', + 'users/lists/get-memberships': 'application/json', + 'users/notes': 'application/json', + 'users/pages': 'application/json', + 'users/flashs': 'application/json', + 'users/reactions': 'application/json', + 'users/recommendation': 'application/json', + 'users/relation': 'application/json', + 'users/report-abuse': 'application/json', + 'users/search-by-username-and-host': 'application/json', + 'users/search': 'application/json', + 'users/show': 'application/json', + 'users/achievements': 'application/json', + 'users/update-memo': 'application/json', + 'fetch-rss': 'application/json', + 'fetch-external-resources': 'application/json', + 'retention': 'application/json', + 'bubble-game/register': 'application/json', + 'bubble-game/ranking': 'application/json', + 'reversi/cancel-match': 'application/json', + 'reversi/games': 'application/json', + 'reversi/match': 'application/json', + 'reversi/invitations': 'application/json', + 'reversi/show-game': 'application/json', + 'reversi/surrender': 'application/json', + 'reversi/verify': 'application/json', +}; diff --git a/packages/misskey-js/src/autogen/entities.ts b/packages/misskey-js/src/autogen/entities.ts index 02ca932d8a..357b5e9eaf 100644 --- a/packages/misskey-js/src/autogen/entities.ts +++ b/packages/misskey-js/src/autogen/entities.ts @@ -7,6 +7,15 @@ export type EmptyResponse = Record | undefined; export type AdminMetaResponse = operations['admin___meta']['responses']['200']['content']['application/json']; export type AdminAbuseUserReportsRequest = operations['admin___abuse-user-reports']['requestBody']['content']['application/json']; export type AdminAbuseUserReportsResponse = operations['admin___abuse-user-reports']['responses']['200']['content']['application/json']; +export type AdminAbuseReportNotificationRecipientListRequest = operations['admin___abuse-report___notification-recipient___list']['requestBody']['content']['application/json']; +export type AdminAbuseReportNotificationRecipientListResponse = operations['admin___abuse-report___notification-recipient___list']['responses']['200']['content']['application/json']; +export type AdminAbuseReportNotificationRecipientShowRequest = operations['admin___abuse-report___notification-recipient___show']['requestBody']['content']['application/json']; +export type AdminAbuseReportNotificationRecipientShowResponse = operations['admin___abuse-report___notification-recipient___show']['responses']['200']['content']['application/json']; +export type AdminAbuseReportNotificationRecipientCreateRequest = operations['admin___abuse-report___notification-recipient___create']['requestBody']['content']['application/json']; +export type AdminAbuseReportNotificationRecipientCreateResponse = operations['admin___abuse-report___notification-recipient___create']['responses']['200']['content']['application/json']; +export type AdminAbuseReportNotificationRecipientUpdateRequest = operations['admin___abuse-report___notification-recipient___update']['requestBody']['content']['application/json']; +export type AdminAbuseReportNotificationRecipientUpdateResponse = operations['admin___abuse-report___notification-recipient___update']['responses']['200']['content']['application/json']; +export type AdminAbuseReportNotificationRecipientDeleteRequest = operations['admin___abuse-report___notification-recipient___delete']['requestBody']['content']['application/json']; export type AdminAccountsCreateRequest = operations['admin___accounts___create']['requestBody']['content']['application/json']; export type AdminAccountsCreateResponse = operations['admin___accounts___create']['responses']['200']['content']['application/json']; export type AdminAccountsDeleteRequest = operations['admin___accounts___delete']['requestBody']['content']['application/json']; @@ -102,6 +111,15 @@ export type AdminRolesUnassignRequest = operations['admin___roles___unassign'][' export type AdminRolesUpdateDefaultPoliciesRequest = operations['admin___roles___update-default-policies']['requestBody']['content']['application/json']; export type AdminRolesUsersRequest = operations['admin___roles___users']['requestBody']['content']['application/json']; export type AdminRolesUsersResponse = operations['admin___roles___users']['responses']['200']['content']['application/json']; +export type AdminSystemWebhookCreateRequest = operations['admin___system-webhook___create']['requestBody']['content']['application/json']; +export type AdminSystemWebhookCreateResponse = operations['admin___system-webhook___create']['responses']['200']['content']['application/json']; +export type AdminSystemWebhookDeleteRequest = operations['admin___system-webhook___delete']['requestBody']['content']['application/json']; +export type AdminSystemWebhookListRequest = operations['admin___system-webhook___list']['requestBody']['content']['application/json']; +export type AdminSystemWebhookListResponse = operations['admin___system-webhook___list']['responses']['200']['content']['application/json']; +export type AdminSystemWebhookShowRequest = operations['admin___system-webhook___show']['requestBody']['content']['application/json']; +export type AdminSystemWebhookShowResponse = operations['admin___system-webhook___show']['responses']['200']['content']['application/json']; +export type AdminSystemWebhookUpdateRequest = operations['admin___system-webhook___update']['requestBody']['content']['application/json']; +export type AdminSystemWebhookUpdateResponse = operations['admin___system-webhook___update']['responses']['200']['content']['application/json']; export type AnnouncementsRequest = operations['announcements']['requestBody']['content']['application/json']; export type AnnouncementsResponse = operations['announcements']['responses']['200']['content']['application/json']; export type AnnouncementsShowRequest = operations['announcements___show']['requestBody']['content']['application/json']; diff --git a/packages/misskey-js/src/autogen/models.ts b/packages/misskey-js/src/autogen/models.ts index a6e5fbe689..04574849d4 100644 --- a/packages/misskey-js/src/autogen/models.ts +++ b/packages/misskey-js/src/autogen/models.ts @@ -51,3 +51,5 @@ export type ReversiGameDetailed = components['schemas']['ReversiGameDetailed']; export type MetaLite = components['schemas']['MetaLite']; export type MetaDetailedOnly = components['schemas']['MetaDetailedOnly']; export type MetaDetailed = components['schemas']['MetaDetailed']; +export type SystemWebhook = components['schemas']['SystemWebhook']; +export type AbuseReportNotificationRecipient = components['schemas']['AbuseReportNotificationRecipient']; diff --git a/packages/misskey-js/src/autogen/types.ts b/packages/misskey-js/src/autogen/types.ts index 2c80676f3e..2a7e5a323d 100644 --- a/packages/misskey-js/src/autogen/types.ts +++ b/packages/misskey-js/src/autogen/types.ts @@ -30,6 +30,56 @@ export type paths = { */ post: operations['admin___abuse-user-reports']; }; + '/admin/abuse-report/notification-recipient/list': { + /** + * admin/abuse-report/notification-recipient/list + * @description No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* / **Permission**: *read:admin:abuse-report:notification-recipient* + */ + post: operations['admin___abuse-report___notification-recipient___list']; + }; + '/admin/abuse-report/notification-recipient/show': { + /** + * admin/abuse-report/notification-recipient/show + * @description No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* / **Permission**: *read:admin:abuse-report:notification-recipient* + */ + post: operations['admin___abuse-report___notification-recipient___show']; + }; + '/admin/abuse-report/notification-recipient/create': { + /** + * admin/abuse-report/notification-recipient/create + * @description No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* / **Permission**: *write:admin:abuse-report:notification-recipient* + */ + post: operations['admin___abuse-report___notification-recipient___create']; + }; + '/admin/abuse-report/notification-recipient/update': { + /** + * admin/abuse-report/notification-recipient/update + * @description No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* / **Permission**: *write:admin:abuse-report:notification-recipient* + */ + post: operations['admin___abuse-report___notification-recipient___update']; + }; + '/admin/abuse-report/notification-recipient/delete': { + /** + * admin/abuse-report/notification-recipient/delete + * @description No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* / **Permission**: *write:admin:abuse-report:notification-recipient* + */ + post: operations['admin___abuse-report___notification-recipient___delete']; + }; '/admin/accounts/create': { /** * admin/accounts/create @@ -697,6 +747,56 @@ export type paths = { */ post: operations['admin___roles___users']; }; + '/admin/system-webhook/create': { + /** + * admin/system-webhook/create + * @description No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* / **Permission**: *write:admin:system-webhook* + */ + post: operations['admin___system-webhook___create']; + }; + '/admin/system-webhook/delete': { + /** + * admin/system-webhook/delete + * @description No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* / **Permission**: *write:admin:system-webhook* + */ + post: operations['admin___system-webhook___delete']; + }; + '/admin/system-webhook/list': { + /** + * admin/system-webhook/list + * @description No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* / **Permission**: *write:admin:system-webhook* + */ + post: operations['admin___system-webhook___list']; + }; + '/admin/system-webhook/show': { + /** + * admin/system-webhook/show + * @description No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* / **Permission**: *write:admin:system-webhook* + */ + post: operations['admin___system-webhook___show']; + }; + '/admin/system-webhook/update': { + /** + * admin/system-webhook/update + * @description No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* / **Permission**: *write:admin:system-webhook* + */ + post: operations['admin___system-webhook___update']; + }; '/announcements': { /** * announcements @@ -4199,7 +4299,7 @@ export type components = { id: string; /** Format: date-time */ createdAt: string; - /** @example lenna.jpg */ + /** @example 192.jpg */ name: string; /** @example image/jpeg */ type: string; @@ -4508,6 +4608,7 @@ export type components = { /** Format: date-time */ latestRequestReceivedAt: string | null; moderationNote?: string | null; + httpMessageSignaturesImplementationLevel: string; }; GalleryPost: { /** @@ -4686,6 +4787,7 @@ export type components = { canHideAds: boolean; driveCapacityMb: number; alwaysMarkNsfw: boolean; + canUpdateBioMedia: boolean; pinLimit: number; antennaLimit: number; wordMuteLimit: number; @@ -4859,6 +4961,32 @@ export type components = { cacheRemoteSensitiveFiles: boolean; }; MetaDetailed: components['schemas']['MetaLite'] & components['schemas']['MetaDetailedOnly']; + SystemWebhook: { + id: string; + isActive: boolean; + /** Format: date-time */ + updatedAt: string; + /** Format: date-time */ + latestSentAt: string | null; + latestStatus: number | null; + name: string; + on: ('abuseReport' | 'abuseReportResolved')[]; + url: string; + secret: string; + }; + AbuseReportNotificationRecipient: { + id: string; + isActive: boolean; + /** Format: date-time */ + updatedAt: string; + name: string; + /** @enum {string} */ + method: 'email' | 'webhook'; + userId?: string; + user?: components['schemas']['UserLite']; + systemWebhookId?: string; + systemWebhook?: components['schemas']['SystemWebhook']; + }; }; responses: never; parameters: never; @@ -5125,6 +5253,292 @@ export type operations = { }; }; }; + /** + * admin/abuse-report/notification-recipient/list + * @description No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* / **Permission**: *read:admin:abuse-report:notification-recipient* + */ + 'admin___abuse-report___notification-recipient___list': { + requestBody: { + content: { + 'application/json': { + method?: ('email' | 'webhook')[]; + }; + }; + }; + responses: { + /** @description OK (with results) */ + 200: { + content: { + 'application/json': components['schemas']['AbuseReportNotificationRecipient'][]; + }; + }; + /** @description Client error */ + 400: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Authentication error */ + 401: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Forbidden error */ + 403: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description I'm Ai */ + 418: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Internal server error */ + 500: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + }; + }; + /** + * admin/abuse-report/notification-recipient/show + * @description No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* / **Permission**: *read:admin:abuse-report:notification-recipient* + */ + 'admin___abuse-report___notification-recipient___show': { + requestBody: { + content: { + 'application/json': { + /** Format: misskey:id */ + id: string; + }; + }; + }; + responses: { + /** @description OK (with results) */ + 200: { + content: { + 'application/json': components['schemas']['AbuseReportNotificationRecipient']; + }; + }; + /** @description Client error */ + 400: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Authentication error */ + 401: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Forbidden error */ + 403: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description I'm Ai */ + 418: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Internal server error */ + 500: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + }; + }; + /** + * admin/abuse-report/notification-recipient/create + * @description No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* / **Permission**: *write:admin:abuse-report:notification-recipient* + */ + 'admin___abuse-report___notification-recipient___create': { + requestBody: { + content: { + 'application/json': { + isActive: boolean; + name: string; + /** @enum {string} */ + method: 'email' | 'webhook'; + /** Format: misskey:id */ + userId?: string; + /** Format: misskey:id */ + systemWebhookId?: string; + }; + }; + }; + responses: { + /** @description OK (with results) */ + 200: { + content: { + 'application/json': components['schemas']['AbuseReportNotificationRecipient']; + }; + }; + /** @description Client error */ + 400: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Authentication error */ + 401: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Forbidden error */ + 403: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description I'm Ai */ + 418: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Internal server error */ + 500: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + }; + }; + /** + * admin/abuse-report/notification-recipient/update + * @description No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* / **Permission**: *write:admin:abuse-report:notification-recipient* + */ + 'admin___abuse-report___notification-recipient___update': { + requestBody: { + content: { + 'application/json': { + /** Format: misskey:id */ + id: string; + isActive: boolean; + name: string; + /** @enum {string} */ + method: 'email' | 'webhook'; + /** Format: misskey:id */ + userId?: string; + /** Format: misskey:id */ + systemWebhookId?: string; + }; + }; + }; + responses: { + /** @description OK (with results) */ + 200: { + content: { + 'application/json': components['schemas']['AbuseReportNotificationRecipient']; + }; + }; + /** @description Client error */ + 400: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Authentication error */ + 401: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Forbidden error */ + 403: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description I'm Ai */ + 418: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Internal server error */ + 500: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + }; + }; + /** + * admin/abuse-report/notification-recipient/delete + * @description No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* / **Permission**: *write:admin:abuse-report:notification-recipient* + */ + 'admin___abuse-report___notification-recipient___delete': { + requestBody: { + content: { + 'application/json': { + /** Format: misskey:id */ + id: string; + }; + }; + }; + responses: { + /** @description OK (without any results) */ + 204: { + content: never; + }; + /** @description Client error */ + 400: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Authentication error */ + 401: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Forbidden error */ + 403: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description I'm Ai */ + 418: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Internal server error */ + 500: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + }; + }; /** * admin/accounts/create * @description No description provided. @@ -5469,15 +5883,15 @@ export type operations = { 'application/json': { /** Format: misskey:id */ id: string; - memo: string; - url: string; - imageUrl: string; - place: string; - priority: string; - ratio: number; - expiresAt: number; - startsAt: number; - dayOfWeek: number; + memo?: string; + url?: string; + imageUrl?: string; + place?: string; + priority?: string; + ratio?: number; + expiresAt?: number; + startsAt?: number; + dayOfWeek?: number; }; }; }; @@ -6387,7 +6801,7 @@ export type operations = { * @example 15eca7fba0480996e2245f5185bf39f2 */ md5: string; - /** @example lenna.jpg */ + /** @example 192.jpg */ name: string; /** @example image/jpeg */ type: string; @@ -9332,21 +9746,21 @@ export type operations = { 'application/json': { /** Format: misskey:id */ roleId: string; - name: string; - description: string; - color: string | null; - iconUrl: string | null; + name?: string; + description?: string; + color?: string | null; + iconUrl?: string | null; /** @enum {string} */ - target: 'manual' | 'conditional'; - condFormula: Record; - isPublic: boolean; - isModerator: boolean; - isAdministrator: boolean; + target?: 'manual' | 'conditional'; + condFormula?: Record; + isPublic?: boolean; + isModerator?: boolean; + isAdministrator?: boolean; isExplorable?: boolean; - asBadge: boolean; - canEditMembersByModerator: boolean; - displayOrder: number; - policies: Record; + asBadge?: boolean; + canEditMembersByModerator?: boolean; + displayOrder?: number; + policies?: Record; }; }; }; @@ -9615,6 +10029,287 @@ export type operations = { }; }; }; + /** + * admin/system-webhook/create + * @description No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* / **Permission**: *write:admin:system-webhook* + */ + 'admin___system-webhook___create': { + requestBody: { + content: { + 'application/json': { + isActive: boolean; + name: string; + on: ('abuseReport' | 'abuseReportResolved')[]; + url: string; + secret: string; + }; + }; + }; + responses: { + /** @description OK (with results) */ + 200: { + content: { + 'application/json': components['schemas']['SystemWebhook']; + }; + }; + /** @description Client error */ + 400: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Authentication error */ + 401: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Forbidden error */ + 403: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description I'm Ai */ + 418: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Internal server error */ + 500: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + }; + }; + /** + * admin/system-webhook/delete + * @description No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* / **Permission**: *write:admin:system-webhook* + */ + 'admin___system-webhook___delete': { + requestBody: { + content: { + 'application/json': { + /** Format: misskey:id */ + id: string; + }; + }; + }; + responses: { + /** @description OK (without any results) */ + 204: { + content: never; + }; + /** @description Client error */ + 400: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Authentication error */ + 401: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Forbidden error */ + 403: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description I'm Ai */ + 418: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Internal server error */ + 500: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + }; + }; + /** + * admin/system-webhook/list + * @description No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* / **Permission**: *write:admin:system-webhook* + */ + 'admin___system-webhook___list': { + requestBody: { + content: { + 'application/json': { + isActive?: boolean; + on?: ('abuseReport' | 'abuseReportResolved')[]; + }; + }; + }; + responses: { + /** @description OK (with results) */ + 200: { + content: { + 'application/json': components['schemas']['SystemWebhook'][]; + }; + }; + /** @description Client error */ + 400: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Authentication error */ + 401: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Forbidden error */ + 403: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description I'm Ai */ + 418: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Internal server error */ + 500: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + }; + }; + /** + * admin/system-webhook/show + * @description No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* / **Permission**: *write:admin:system-webhook* + */ + 'admin___system-webhook___show': { + requestBody: { + content: { + 'application/json': { + /** Format: misskey:id */ + id: string; + }; + }; + }; + responses: { + /** @description OK (with results) */ + 200: { + content: { + 'application/json': components['schemas']['SystemWebhook']; + }; + }; + /** @description Client error */ + 400: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Authentication error */ + 401: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Forbidden error */ + 403: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description I'm Ai */ + 418: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Internal server error */ + 500: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + }; + }; + /** + * admin/system-webhook/update + * @description No description provided. + * + * **Internal Endpoint**: This endpoint is an API for the misskey mainframe and is not intended for use by third parties. + * **Credential required**: *Yes* / **Permission**: *write:admin:system-webhook* + */ + 'admin___system-webhook___update': { + requestBody: { + content: { + 'application/json': { + /** Format: misskey:id */ + id: string; + isActive: boolean; + name: string; + on: ('abuseReport' | 'abuseReportResolved')[]; + url: string; + secret: string; + }; + }; + }; + responses: { + /** @description OK (with results) */ + 200: { + content: { + 'application/json': components['schemas']['SystemWebhook']; + }; + }; + /** @description Client error */ + 400: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Authentication error */ + 401: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Forbidden error */ + 403: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description I'm Ai */ + 418: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Internal server error */ + 500: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + }; + }; /** * announcements * @description No description provided. @@ -12707,7 +13402,7 @@ export type operations = { 'application/json': { /** Format: misskey:id */ clipId: string; - name: string; + name?: string; isPublic?: boolean; description?: string | null; }; @@ -13157,7 +13852,7 @@ export type operations = { * Format: binary * @description The file contents. */ - file: string; + file: Blob; }; }; }; @@ -15554,9 +16249,9 @@ export type operations = { 'application/json': { /** Format: misskey:id */ postId: string; - title: string; + title?: string; description?: string | null; - fileIds: string[]; + fileIds?: string[]; /** @default false */ isSensitive?: boolean; }; @@ -19337,12 +20032,11 @@ export type operations = { 'application/json': { /** Format: misskey:id */ webhookId: string; - name: string; - url: string; - /** @default */ - secret?: string; - on: ('mention' | 'unfollow' | 'follow' | 'followed' | 'note' | 'reply' | 'renote' | 'reaction')[]; - active: boolean; + name?: string; + url?: string; + secret?: string | null; + on?: ('mention' | 'unfollow' | 'follow' | 'followed' | 'note' | 'reply' | 'renote' | 'reaction')[]; + active?: boolean; }; }; }; @@ -22711,16 +23405,16 @@ export type operations = { 'application/json': { /** Format: misskey:id */ pageId: string; - title: string; - name: string; + title?: string; + name?: string; summary?: string | null; - content: { + content?: { [key: string]: unknown; }[]; - variables: { + variables?: { [key: string]: unknown; }[]; - script: string; + script?: string; /** Format: misskey:id */ eyeCatchingImageId?: string | null; /** @enum {string} */ diff --git a/packages/misskey-js/src/consts.ts b/packages/misskey-js/src/consts.ts index fd6ef4d68d..03b9069290 100644 --- a/packages/misskey-js/src/consts.ts +++ b/packages/misskey-js/src/consts.ts @@ -325,4 +325,30 @@ export type ModerationLogPayloads = { userHost: string | null; fileId: string; }; + createSystemWebhook: { + systemWebhookId: string; + webhook: any; + }; + updateSystemWebhook: { + systemWebhookId: string; + before: any; + after: any; + }; + deleteSystemWebhook: { + systemWebhookId: string; + webhook: any; + }; + createAbuseReportNotificationRecipient: { + recipientId: string; + recipient: any; + }; + updateAbuseReportNotificationRecipient: { + recipientId: string; + before: any; + after: any; + }; + deleteAbuseReportNotificationRecipient: { + recipientId: string; + recipient: any; + }; }; diff --git a/packages/misskey-js/src/entities.ts b/packages/misskey-js/src/entities.ts index 35503d6d6f..7331a55a1c 100644 --- a/packages/misskey-js/src/entities.ts +++ b/packages/misskey-js/src/entities.ts @@ -1,5 +1,14 @@ import { ModerationLogPayloads } from './consts.js'; -import { Announcement, EmojiDetailed, MeDetailed, Page, User, UserDetailedNotMe } from './autogen/models.js'; +import { + Announcement, + EmojiDetailed, + MeDetailed, + Page, + Role, + RolePolicies, + User, + UserDetailedNotMe +} from './autogen/models.js'; export * from './autogen/entities.js'; export * from './autogen/models.js'; @@ -132,8 +141,23 @@ export type ModerationLog = { type: 'unsetUserAvatar'; info: ModerationLogPayloads['unsetUserAvatar']; } | { - type: 'unsetUserBanner'; - info: ModerationLogPayloads['unsetUserBanner']; + type: 'createSystemWebhook'; + info: ModerationLogPayloads['createSystemWebhook']; +} | { + type: 'updateSystemWebhook'; + info: ModerationLogPayloads['updateSystemWebhook']; +} | { + type: 'deleteSystemWebhook'; + info: ModerationLogPayloads['deleteSystemWebhook']; +} | { + type: 'createAbuseReportNotificationRecipient'; + info: ModerationLogPayloads['createAbuseReportNotificationRecipient']; +} | { + type: 'updateAbuseReportNotificationRecipient'; + info: ModerationLogPayloads['updateAbuseReportNotificationRecipient']; +} | { + type: 'deleteAbuseReportNotificationRecipient'; + info: ModerationLogPayloads['deleteAbuseReportNotificationRecipient']; }); export type ServerStats = { @@ -221,3 +245,7 @@ export type SigninResponse = { id: User['id'], i: string, }; + +type Values> = T[keyof T]; + +export type PartialRolePolicyOverride = Partial<{[k in keyof RolePolicies]: Omit, 'value'> & { value: RolePolicies[k] }}>; diff --git a/packages/misskey-js/src/streaming.ts b/packages/misskey-js/src/streaming.ts index 0f26857782..83930e621c 100644 --- a/packages/misskey-js/src/streaming.ts +++ b/packages/misskey-js/src/streaming.ts @@ -291,7 +291,9 @@ export abstract class Connection = any> extends this.stream = stream; this.channel = channel; - this.name = name; + if (name !== undefined) { + this.name = name; + } } public send(type: T, body: Channel['receives'][T]): void { diff --git a/packages/misskey-js/test/api.ts b/packages/misskey-js/test/api.ts index fa31d23faa..1a7574de25 100644 --- a/packages/misskey-js/test/api.ts +++ b/packages/misskey-js/test/api.ts @@ -5,13 +5,19 @@ enableFetchMocks(); function getFetchCall(call: any[]) { const { body, method } = call[1]; - if (body != null && typeof body != 'string') { + const contentType = call[1].headers['Content-Type']; + if ( + body == null || + (contentType === 'application/json' && typeof body !== 'string') || + (contentType === 'multipart/form-data' && !(body instanceof FormData)) + ) { throw new Error('invalid body'); } return { url: call[0], method: method, - body: JSON.parse(body as any) + contentType: contentType, + body: body instanceof FormData ? Object.fromEntries(body.entries()) : JSON.parse(body), }; } @@ -45,6 +51,7 @@ describe('API', () => { expect(getFetchCall(fetchMock.mock.calls[0])).toEqual({ url: 'https://misskey.test/api/i', method: 'POST', + contentType: 'application/json', body: { i: 'TOKEN' } }); }); @@ -78,10 +85,52 @@ describe('API', () => { expect(getFetchCall(fetchMock.mock.calls[0])).toEqual({ url: 'https://misskey.test/api/notes/show', method: 'POST', + contentType: 'application/json', body: { i: 'TOKEN', noteId: 'aaaaa' } }); }); + test('multipart/form-data', async () => { + fetchMock.resetMocks(); + fetchMock.mockResponse(async (req) => { + if (req.method == 'POST' && req.url == 'https://misskey.test/api/drive/files/create') { + if (req.headers.get('Content-Type')?.includes('multipart/form-data')) { + return JSON.stringify({ id: 'foo' }); + } else { + return { status: 400 }; + } + } else { + return { status: 404 }; + } + }); + + const cli = new APIClient({ + origin: 'https://misskey.test', + credential: 'TOKEN', + }); + + const testFile = new File([], 'foo.txt'); + + const res = await cli.request('drive/files/create', { + file: testFile, + name: null, // nullのパラメータは消える + }); + + expect(res).toEqual({ + id: 'foo' + }); + + expect(getFetchCall(fetchMock.mock.calls[0])).toEqual({ + url: 'https://misskey.test/api/drive/files/create', + method: 'POST', + contentType: 'multipart/form-data', + body: { + i: 'TOKEN', + file: testFile, + } + }); + }); + test('204 No Content で null が返る', async () => { fetchMock.resetMocks(); fetchMock.mockResponse(async (req) => { @@ -104,6 +153,7 @@ describe('API', () => { expect(getFetchCall(fetchMock.mock.calls[0])).toEqual({ url: 'https://misskey.test/api/reset-password', method: 'POST', + contentType: 'application/json', body: { i: 'TOKEN', token: 'aaa', password: 'aaa' } }); }); @@ -209,4 +259,42 @@ describe('API', () => { expect(isAPIError(e)).toEqual(false); } }); + + test('admin/roles/create の型が合う', async() => { + fetchMock.resetMocks(); + fetchMock.mockResponse(async () => { + return { + // 本来返すべき値は`Role`型だが、テストなのでお茶を濁す + status: 200, + body: '{}' + }; + }); + + const cli = new APIClient({ + origin: 'https://misskey.test', + credential: 'TOKEN', + }); + await cli.request('admin/roles/create', { + name: 'aaa', + asBadge: false, + canEditMembersByModerator: false, + color: '#123456', + condFormula: {}, + description: '', + displayOrder: 0, + iconUrl: '', + isAdministrator: false, + isExplorable: false, + isModerator: false, + isPublic: false, + policies: { + ltlAvailable: { + value: true, + priority: 0, + useDefault: false, + }, + }, + target: 'manual', + }); + }) }); diff --git a/packages/misskey-js/tsconfig.json b/packages/misskey-js/tsconfig.json index 6e34e332e0..f7bbc47304 100644 --- a/packages/misskey-js/tsconfig.json +++ b/packages/misskey-js/tsconfig.json @@ -15,6 +15,7 @@ "experimentalDecorators": true, "noImplicitReturns": true, "esModuleInterop": true, + "exactOptionalPropertyTypes": true, "typeRoots": [ "./node_modules/@types" ], diff --git a/packages/misskey-reversi/.eslintignore b/packages/misskey-reversi/.eslintignore deleted file mode 100644 index 52ea8b3362..0000000000 --- a/packages/misskey-reversi/.eslintignore +++ /dev/null @@ -1,8 +0,0 @@ -node_modules -/built -/coverage -/.eslintrc.js -/jest.config.ts -/test -/test-d -build.js diff --git a/packages/misskey-reversi/.eslintrc.cjs b/packages/misskey-reversi/.eslintrc.cjs deleted file mode 100644 index db37a01098..0000000000 --- a/packages/misskey-reversi/.eslintrc.cjs +++ /dev/null @@ -1,10 +0,0 @@ -module.exports = { - root: true, - parserOptions: { - tsconfigRootDir: __dirname, - project: ['./tsconfig.json'], - }, - extends: [ - '../shared/.eslintrc.js', - ], -}; diff --git a/packages/misskey-reversi/build.js b/packages/misskey-reversi/build.js index 0b79f4b915..e626c97a59 100644 --- a/packages/misskey-reversi/build.js +++ b/packages/misskey-reversi/build.js @@ -95,7 +95,6 @@ async function watchSrc() { process.on('SIGHUP', resolve); process.on('SIGINT', resolve); process.on('SIGTERM', resolve); - process.on('SIGKILL', resolve); process.on('uncaughtException', reject); process.on('exit', resolve); }).finally(async () => { diff --git a/packages/misskey-reversi/eslint.config.js b/packages/misskey-reversi/eslint.config.js new file mode 100644 index 0000000000..3f81df7145 --- /dev/null +++ b/packages/misskey-reversi/eslint.config.js @@ -0,0 +1,23 @@ +import tsParser from '@typescript-eslint/parser'; +import sharedConfig from '../shared/eslint.config.js'; + +export default [ + ...sharedConfig, + { + ignores: [ + '**/node_modules', + 'built', + ], + }, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + parser: tsParser, + project: ['./tsconfig.json'], + sourceType: 'module', + tsconfigRootDir: import.meta.dirname, + }, + }, + }, +]; diff --git a/packages/misskey-reversi/package.json b/packages/misskey-reversi/package.json index 45a6120861..c6db6e6221 100644 --- a/packages/misskey-reversi/package.json +++ b/packages/misskey-reversi/package.json @@ -17,16 +17,14 @@ "scripts": { "build": "node ./build.js", "watch": "nodemon -w package.json -e json --exec \"node ./build.js --watch\"", - "eslint": "eslint . --ext .js,.jsx,.ts,.tsx", + "eslint": "eslint './**/*.{js,jsx,ts,tsx}'", "typecheck": "tsc --noEmit", "lint": "pnpm typecheck && pnpm eslint" }, "devDependencies": { - "@misskey-dev/eslint-plugin": "1.0.0", "@types/node": "20.11.5", "@typescript-eslint/eslint-plugin": "7.1.0", "@typescript-eslint/parser": "7.1.0", - "eslint": "8.57.0", "execa": "8.0.1", "nodemon": "3.0.2", "typescript": "5.3.3", diff --git a/packages/shared/.eslintrc.js b/packages/shared/.eslintrc.js deleted file mode 100644 index 58247877ae..0000000000 --- a/packages/shared/.eslintrc.js +++ /dev/null @@ -1,7 +0,0 @@ -module.exports = { - root: true, - ignorePatterns: ['**/.eslintrc.cjs'], - extends: [ - 'plugin:@misskey-dev/recommended', - ], -}; diff --git a/packages/shared/eslint.config.js b/packages/shared/eslint.config.js new file mode 100644 index 0000000000..e9d27c4a72 --- /dev/null +++ b/packages/shared/eslint.config.js @@ -0,0 +1,28 @@ +import globals from 'globals'; +import pluginMisskey from '@misskey-dev/eslint-plugin'; + +export default [ + ...pluginMisskey.configs['recommended'], + { + files: ['**/*.cjs'], + languageOptions: { + parserOptions: { + sourceType: 'commonjs', + }, + }, + }, + { + files: ['**/*.js', '**/*.jsx'], + languageOptions: { + parserOptions: { + sourceType: 'module', + }, + }, + }, + { + files: ['build.js'], + languageOptions: { + globals: globals.node, + }, + }, +]; diff --git a/packages/shared/package.json b/packages/shared/package.json new file mode 100644 index 0000000000..bedb411a91 --- /dev/null +++ b/packages/shared/package.json @@ -0,0 +1,3 @@ +{ + "type": "module" +} diff --git a/packages/sw/.eslintrc.cjs b/packages/sw/.eslintrc.cjs deleted file mode 100644 index b1fd6b5edc..0000000000 --- a/packages/sw/.eslintrc.cjs +++ /dev/null @@ -1,20 +0,0 @@ -module.exports = { - root: true, - env: { - node: false, - }, - parserOptions: { - parser: '@typescript-eslint/parser', - tsconfigRootDir: __dirname, - project: ['./tsconfig.json'], - }, - extends: ['../shared/.eslintrc.js'], - globals: { - require: false, - _DEV_: false, - _LANGS_: false, - _VERSION_: false, - _ENV_: false, - _PERF_PREFIX_: false, - }, -}; diff --git a/packages/sw/build.js b/packages/sw/build.js index eb9a944f47..9522d061e0 100644 --- a/packages/sw/build.js +++ b/packages/sw/build.js @@ -8,7 +8,7 @@ import { fileURLToPath } from 'node:url'; import * as esbuild from 'esbuild'; import locales from '../../locales/index.js'; -import meta from '../../package.json' assert { type: "json" }; +import meta from '../../package.json' with { type: "json" }; const watch = process.argv[2]?.includes('watch'); const __dirname = fileURLToPath(new URL('.', import.meta.url)) diff --git a/packages/sw/eslint.config.js b/packages/sw/eslint.config.js new file mode 100644 index 0000000000..c62a2eadc6 --- /dev/null +++ b/packages/sw/eslint.config.js @@ -0,0 +1,32 @@ +import globals from 'globals'; +import tsParser from '@typescript-eslint/parser'; +import sharedConfig from '../shared/eslint.config.js'; + +export default [ + ...sharedConfig, + { + ignores: ['build.js'], + languageOptions: { + globals: { + ...Object.fromEntries(Object.entries(globals.node).map(([key]) => [key, 'off'])), + require: false, + _DEV_: false, + _LANGS_: false, + _VERSION_: false, + _ENV_: false, + _PERF_PREFIX_: false, + }, + }, + }, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + parser: tsParser, + project: ['./tsconfig.json'], + sourceType: 'module', + tsconfigRootDir: import.meta.dirname, + }, + }, + }, +]; diff --git a/packages/sw/package.json b/packages/sw/package.json index cb59a70238..bcd642ffc4 100644 --- a/packages/sw/package.json +++ b/packages/sw/package.json @@ -9,18 +9,16 @@ "lint": "pnpm typecheck && pnpm eslint" }, "dependencies": { - "esbuild": "0.20.2", + "esbuild": "0.22.0", "idb-keyval": "6.2.1", "misskey-js": "workspace:*" }, "devDependencies": { - "@misskey-dev/eslint-plugin": "1.0.0", - "@typescript-eslint/parser": "7.7.1", + "@typescript-eslint/parser": "7.15.0", "@typescript/lib-webworker": "npm:@types/serviceworker@0.0.67", - "eslint": "8.57.0", "eslint-plugin-import": "2.29.1", - "nodemon": "3.1.0", - "typescript": "5.4.5" + "nodemon": "3.1.4", + "typescript": "5.5.3" }, "type": "module" } diff --git a/packages/sw/tsconfig.json b/packages/sw/tsconfig.json index f3f3543013..50d4aae19d 100644 --- a/packages/sw/tsconfig.json +++ b/packages/sw/tsconfig.json @@ -2,7 +2,6 @@ "compilerOptions": { "allowJs": true, "noEmitOnError": false, - "noImplicitAny": false, "noImplicitReturns": true, "noUnusedParameters": false, "noUnusedLocals": true, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6bf1cf158c..2d426c2fa8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -16,8 +16,8 @@ importers: specifier: 6.1.2 version: 6.1.2(postcss@8.4.38) esbuild: - specifier: 0.20.2 - version: 0.20.2 + specifier: 0.22.0 + version: 0.22.0 execa: specifier: 8.0.1 version: 8.0.1 @@ -40,58 +40,64 @@ importers: specifier: 6.2.1 version: 6.2.1 terser: - specifier: 5.30.3 - version: 5.30.3 + specifier: 5.31.1 + version: 5.31.1 typescript: - specifier: 5.4.5 - version: 5.4.5 + specifier: 5.5.3 + version: 5.5.3 optionalDependencies: '@tensorflow/tfjs-core': specifier: 4.4.0 - version: 4.4.0(encoding@0.1.13) + version: 4.20.0(encoding@0.1.13) devDependencies: + '@misskey-dev/eslint-plugin': + specifier: 2.0.2 + version: 2.0.2(@eslint/compat@1.1.1)(@typescript-eslint/eslint-plugin@7.15.0(@typescript-eslint/parser@7.15.0(eslint@9.6.0)(typescript@5.5.3))(eslint@9.6.0)(typescript@5.5.3))(@typescript-eslint/parser@7.15.0(eslint@9.6.0)(typescript@5.5.3))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.15.0(eslint@9.6.0)(typescript@5.5.3))(eslint@9.6.0))(eslint@9.6.0)(globals@15.7.0) '@types/node': - specifier: 20.12.7 - version: 20.12.7 + specifier: 20.14.9 + version: 20.14.9 '@typescript-eslint/eslint-plugin': - specifier: 7.7.1 - version: 7.7.1(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5) + specifier: 7.15.0 + version: 7.15.0(@typescript-eslint/parser@7.15.0(eslint@9.6.0)(typescript@5.5.3))(eslint@9.6.0)(typescript@5.5.3) '@typescript-eslint/parser': - specifier: 7.7.1 - version: 7.7.1(eslint@8.57.0)(typescript@5.4.5) + specifier: 7.15.0 + version: 7.15.0(eslint@9.6.0)(typescript@5.5.3) cross-env: specifier: 7.0.3 version: 7.0.3 cypress: - specifier: 13.7.3 - version: 13.7.3 + specifier: 13.13.0 + version: 13.13.0 eslint: - specifier: 8.57.0 - version: 8.57.0 + specifier: 9.6.0 + version: 9.6.0 + globals: + specifier: 15.7.0 + version: 15.7.0 ncp: specifier: 2.0.0 version: 2.0.0 start-server-and-test: - specifier: 2.0.3 - version: 2.0.3 + specifier: 2.0.4 + version: 2.0.4 packages/backend: dependencies: '@aws-sdk/client-s3': - specifier: 3.412.0 - version: 3.412.0 + specifier: 3.600.0 + version: 3.600.0 '@aws-sdk/lib-storage': - specifier: 3.412.0 - version: 3.412.0(@aws-sdk/client-s3@3.412.0) + specifier: 3.600.0 + version: 3.600.0(@aws-sdk/client-s3@3.600.0) '@bull-board/api': - specifier: 5.17.0 - version: 5.17.0(@bull-board/ui@5.17.0) + specifier: 5.20.5 + version: 5.20.5(@bull-board/ui@5.20.5) '@bull-board/fastify': - specifier: 5.17.0 - version: 5.17.0 + specifier: 5.20.5 + version: 5.20.5 '@bull-board/ui': - specifier: 5.17.0 - version: 5.17.0 + specifier: 5.20.5 + version: 5.20.5 '@discordapp/twemoji': specifier: 15.0.3 version: 15.0.3 @@ -109,16 +115,19 @@ importers: version: 3.0.0 '@fastify/http-proxy': specifier: 9.5.0 - version: 9.5.0(bufferutil@4.0.7)(utf-8-validate@6.0.3) + version: 9.5.0(bufferutil@4.0.8)(utf-8-validate@6.0.4) '@fastify/multipart': - specifier: 8.2.0 - version: 8.2.0 + specifier: 8.3.0 + version: 8.3.0 '@fastify/static': - specifier: 7.0.3 - version: 7.0.3 + specifier: 7.0.4 + version: 7.0.4 '@fastify/view': specifier: 9.1.0 version: 9.1.0 + '@misskey-dev/node-http-message-signatures': + specifier: 0.0.10 + version: 0.0.10 '@misskey-dev/sharp-read-bmp': specifier: 1.2.0 version: 1.2.0 @@ -126,26 +135,23 @@ importers: specifier: 5.1.0 version: 5.1.0 '@napi-rs/canvas': - specifier: ^0.1.52 - version: 0.1.52 + specifier: ^0.1.53 + version: 0.1.53 '@nestjs/common': - specifier: 10.3.8 - version: 10.3.8(reflect-metadata@0.2.2)(rxjs@7.8.1) + specifier: 10.3.10 + version: 10.3.10(reflect-metadata@0.2.2)(rxjs@7.8.1) '@nestjs/core': - specifier: 10.3.8 - version: 10.3.8(@nestjs/common@10.3.8(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.3.8)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1) + specifier: 10.3.10 + version: 10.3.10(@nestjs/common@10.3.10(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.3.10)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1) '@nestjs/testing': - specifier: 10.3.8 - version: 10.3.8(@nestjs/common@10.3.8(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.3.8(@nestjs/common@10.3.8(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.3.8)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.3.8(@nestjs/common@10.3.8(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.3.8)) - '@peertube/http-signature': - specifier: 1.7.0 - version: 1.7.0 + specifier: 10.3.10 + version: 10.3.10(@nestjs/common@10.3.10(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.3.10(@nestjs/common@10.3.10(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.3.10)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.3.10(@nestjs/common@10.3.10(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.3.10)) '@sentry/node': - specifier: ^8.5.0 - version: 8.5.0 + specifier: 8.13.0 + version: 8.13.0 '@sentry/profiling-node': - specifier: ^8.5.0 - version: 8.5.0 + specifier: 8.13.0 + version: 8.13.0 '@simplewebauthn/server': specifier: 10.0.0 version: 10.0.0(encoding@0.1.13) @@ -157,10 +163,10 @@ importers: version: 2.5.0 '@swc/cli': specifier: 0.3.12 - version: 0.3.12(@swc/core@1.4.17)(chokidar@3.5.3) + version: 0.3.12(@swc/core@1.6.6)(chokidar@3.5.3) '@swc/core': - specifier: 1.4.17 - version: 1.4.17 + specifier: 1.6.6 + version: 1.6.6 '@twemoji/parser': specifier: 15.1.1 version: 15.1.1 @@ -168,8 +174,8 @@ importers: specifier: 1.3.8 version: 1.3.8 ajv: - specifier: 8.13.0 - version: 8.13.0 + specifier: 8.16.0 + version: 8.16.0 archiver: specifier: 7.0.1 version: 7.0.1 @@ -186,8 +192,8 @@ importers: specifier: 1.20.2 version: 1.20.2 bullmq: - specifier: 5.7.8 - version: 5.7.8 + specifier: 5.8.3 + version: 5.8.3 cacheable-lookup: specifier: 7.0.0 version: 7.0.0 @@ -219,8 +225,8 @@ importers: specifier: 0.1.21 version: 0.1.21 fastify: - specifier: 4.26.2 - version: 4.26.2 + specifier: 4.28.1 + version: 4.28.1 fastify-raw-body: specifier: 4.3.0 version: 4.3.0 @@ -231,14 +237,14 @@ importers: specifier: 19.0.0 version: 19.0.0 fluent-ffmpeg: - specifier: 2.1.2 - version: 2.1.2 + specifier: 2.1.3 + version: 2.1.3 form-data: specifier: 4.0.0 version: 4.0.0 got: - specifier: 14.2.1 - version: 14.2.1 + specifier: 14.4.1 + version: 14.4.1 happy-dom: specifier: 10.0.3 version: 10.0.3 @@ -255,32 +261,32 @@ importers: specifier: 5.4.1 version: 5.4.1 ip-cidr: - specifier: 3.1.0 - version: 3.1.0 + specifier: 4.0.1 + version: 4.0.1 ipaddr.js: specifier: 2.2.0 version: 2.2.0 is-svg: - specifier: 5.0.0 - version: 5.0.0 + specifier: 5.0.1 + version: 5.0.1 js-yaml: specifier: 4.1.0 version: 4.1.0 jsdom: - specifier: 24.0.0 - version: 24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3) + specifier: 24.1.0 + version: 24.1.0(bufferutil@4.0.8)(utf-8-validate@6.0.4) json5: specifier: 2.2.3 version: 2.2.3 jsonld: specifier: 8.3.2 - version: 8.3.2(web-streams-polyfill@3.2.1) + version: 8.3.2(web-streams-polyfill@4.0.0) jsrsasign: specifier: 11.1.0 version: 11.1.0 meilisearch: - specifier: 0.38.0 - version: 0.38.0(encoding@0.1.13) + specifier: 0.41.0 + version: 0.41.0(encoding@0.1.13) mfm-js: specifier: 0.24.0 version: 0.24.0 @@ -309,11 +315,11 @@ importers: specifier: 3.3.2 version: 3.3.2 nodemailer: - specifier: 6.9.13 - version: 6.9.13 + specifier: 6.9.14 + version: 6.9.14 nsfwjs: specifier: 2.4.2 - version: 2.4.2(@tensorflow/tfjs@4.4.0(encoding@0.1.13)(seedrandom@3.0.5)) + version: 2.4.2(@tensorflow/tfjs@4.20.0(encoding@0.1.13)(seedrandom@3.0.5)) oauth: specifier: 0.10.0 version: 0.10.0 @@ -327,14 +333,14 @@ importers: specifier: 0.0.14 version: 0.0.14 otpauth: - specifier: 9.2.3 - version: 9.2.3 + specifier: 9.3.1 + version: 9.3.1 parse5: specifier: 7.1.2 version: 7.1.2 pg: - specifier: 8.11.5 - version: 8.11.5 + specifier: 8.12.0 + version: 8.12.0 pkce-challenge: specifier: 4.1.0 version: 4.1.0 @@ -345,8 +351,8 @@ importers: specifier: 2.7.0 version: 2.7.0 pug: - specifier: 3.0.2 - version: 3.0.2 + specifier: 3.0.3 + version: 3.0.3 punycode: specifier: 2.3.1 version: 2.3.1 @@ -360,8 +366,8 @@ importers: specifier: 3.4.1 version: 3.4.1 re2: - specifier: 1.20.10 - version: 1.20.10 + specifier: 1.21.3 + version: 1.21.3 redis-lock: specifier: 0.1.4 version: 0.1.4 @@ -384,8 +390,8 @@ importers: specifier: 2.7.0 version: 2.7.0 sharp: - specifier: 0.33.3 - version: 0.33.3 + specifier: 0.33.4 + version: 0.33.4 slacc: specifier: 0.0.10 version: 0.0.10 @@ -396,8 +402,8 @@ importers: specifier: 2.1.0 version: 2.1.0 systeminformation: - specifier: 5.22.7 - version: 5.22.7 + specifier: 5.22.11 + version: 5.22.11 tinycolor2: specifier: 1.6.0 version: 1.6.0 @@ -405,17 +411,17 @@ importers: specifier: 0.2.3 version: 0.2.3 tsc-alias: - specifier: 1.8.8 - version: 1.8.8 + specifier: 1.8.10 + version: 1.8.10 tsconfig-paths: specifier: 4.2.0 version: 4.2.0 typeorm: specifier: 0.3.20 - version: 0.3.20(ioredis@5.4.1)(pg@8.11.5) + version: 0.3.20(ioredis@5.4.1)(pg@8.12.0) typescript: - specifier: 5.4.5 - version: 5.4.5 + specifier: 5.5.3 + version: 5.5.3 ulid: specifier: 2.3.0 version: 2.3.0 @@ -426,8 +432,8 @@ importers: specifier: 3.6.7 version: 3.6.7 ws: - specifier: 8.17.0 - version: 8.17.0(bufferutil@4.0.7)(utf-8-validate@6.0.3) + specifier: 8.17.1 + version: 8.17.1(bufferutil@4.0.8)(utf-8-validate@6.0.4) xev: specifier: 3.0.2 version: 3.0.2 @@ -437,46 +443,46 @@ importers: version: 1.3.11 '@swc/core-darwin-arm64': specifier: 1.3.56 - version: 1.3.56 + version: 1.7.0-nightly-20240715.2 '@swc/core-darwin-x64': specifier: 1.3.56 - version: 1.3.56 + version: 1.7.0-nightly-20240715.2 '@swc/core-freebsd-x64': specifier: 1.3.11 version: 1.3.11 '@swc/core-linux-arm-gnueabihf': specifier: 1.3.56 - version: 1.3.56 + version: 1.7.0-nightly-20240715.2 '@swc/core-linux-arm64-gnu': specifier: 1.3.56 - version: 1.3.56 + version: 1.7.0-nightly-20240715.2 '@swc/core-linux-arm64-musl': specifier: 1.3.56 - version: 1.3.56 + version: 1.7.0-nightly-20240715.2 '@swc/core-linux-x64-gnu': specifier: 1.3.56 - version: 1.3.56 + version: 1.7.0-nightly-20240715.2 '@swc/core-linux-x64-musl': specifier: 1.3.56 - version: 1.3.56 + version: 1.7.0-nightly-20240715.2 '@swc/core-win32-arm64-msvc': specifier: 1.3.56 - version: 1.3.56 + version: 1.7.0-nightly-20240715.2 '@swc/core-win32-ia32-msvc': specifier: 1.3.56 - version: 1.3.56 + version: 1.7.0-nightly-20240715.2 '@swc/core-win32-x64-msvc': specifier: 1.3.56 - version: 1.3.56 + version: 1.7.0-nightly-20240715.2 '@tensorflow/tfjs': specifier: 4.4.0 - version: 4.4.0(encoding@0.1.13)(seedrandom@3.0.5) + version: 4.20.0(encoding@0.1.13)(seedrandom@3.0.5) '@tensorflow/tfjs-node': specifier: 4.4.0 - version: 4.4.0(encoding@0.1.13)(seedrandom@3.0.5) + version: 4.20.0(encoding@0.1.13)(seedrandom@3.0.5) bufferutil: specifier: 4.0.7 - version: 4.0.7 + version: 4.0.8 slacc-android-arm-eabi: specifier: 0.0.10 version: 0.0.10 @@ -518,23 +524,20 @@ importers: version: 0.0.10 utf-8-validate: specifier: 6.0.3 - version: 6.0.3 + version: 6.0.4 devDependencies: '@jest/globals': specifier: 29.7.0 version: 29.7.0 - '@misskey-dev/eslint-plugin': - specifier: 1.0.0 - version: 1.0.0(@typescript-eslint/eslint-plugin@7.7.1(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5))(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0))(eslint@8.57.0) '@nestjs/platform-express': - specifier: 10.3.8 - version: 10.3.8(@nestjs/common@10.3.8(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.3.8) + specifier: 10.3.10 + version: 10.3.10(@nestjs/common@10.3.10(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.3.10) '@simplewebauthn/types': specifier: 10.0.0 version: 10.0.0 '@swc/jest': specifier: 0.2.36 - version: 0.2.36(@swc/core@1.4.17) + version: 0.2.36(@swc/core@1.6.6) '@types/accepts': specifier: 1.3.7 version: 1.3.7 @@ -557,11 +560,11 @@ importers: specifier: 2.1.24 version: 2.1.24 '@types/htmlescape': - specifier: ^1.1.3 + specifier: 1.1.3 version: 1.1.3 '@types/http-link-header': - specifier: 1.0.5 - version: 1.0.5 + specifier: 1.0.7 + version: 1.0.7 '@types/jest': specifier: 29.5.12 version: 29.5.12 @@ -569,11 +572,11 @@ importers: specifier: 4.0.9 version: 4.0.9 '@types/jsdom': - specifier: 21.1.6 - version: 21.1.6 + specifier: 21.1.7 + version: 21.1.7 '@types/jsonld': - specifier: 1.5.13 - version: 1.5.13 + specifier: 1.5.14 + version: 1.5.14 '@types/jsrsasign': specifier: 10.5.14 version: 10.5.14 @@ -584,17 +587,14 @@ importers: specifier: 0.7.34 version: 0.7.34 '@types/node': - specifier: 20.12.7 - version: 20.12.7 - '@types/node-fetch': - specifier: 3.0.3 - version: 3.0.3 + specifier: 20.14.9 + version: 20.14.9 '@types/nodemailer': specifier: 6.4.15 version: 6.4.15 '@types/oauth': - specifier: 0.9.4 - version: 0.9.4 + specifier: 0.9.5 + version: 0.9.5 '@types/oauth2orize': specifier: 1.11.5 version: 1.11.5 @@ -602,8 +602,8 @@ importers: specifier: 0.1.2 version: 0.1.2 '@types/pg': - specifier: 8.11.5 - version: 8.11.5 + specifier: 8.11.6 + version: 8.11.6 '@types/pug': specifier: 2.0.10 version: 2.0.10 @@ -650,44 +650,41 @@ importers: specifier: 8.5.10 version: 8.5.10 '@typescript-eslint/eslint-plugin': - specifier: 7.7.1 - version: 7.7.1(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5) + specifier: 7.15.0 + version: 7.15.0(@typescript-eslint/parser@7.15.0(eslint@9.7.0)(typescript@5.5.3))(eslint@9.7.0)(typescript@5.5.3) '@typescript-eslint/parser': - specifier: 7.7.1 - version: 7.7.1(eslint@8.57.0)(typescript@5.4.5) + specifier: 7.15.0 + version: 7.15.0(eslint@9.7.0)(typescript@5.5.3) aws-sdk-client-mock: - specifier: 3.0.1 - version: 3.0.1 + specifier: 4.0.1 + version: 4.0.1 cross-env: specifier: 7.0.3 version: 7.0.3 - eslint: - specifier: 8.57.0 - version: 8.57.0 eslint-plugin-import: specifier: 2.29.1 - version: 2.29.1(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0) + version: 2.29.1(@typescript-eslint/parser@7.15.0(eslint@9.7.0)(typescript@5.5.3))(eslint@9.7.0) execa: - specifier: 8.0.1 - version: 8.0.1 + specifier: 9.2.0 + version: 9.2.0 fkill: - specifier: ^9.0.0 + specifier: 9.0.0 version: 9.0.0 jest: specifier: 29.7.0 - version: 29.7.0(@types/node@20.12.7) + version: 29.7.0(@types/node@20.14.9) jest-mock: specifier: 29.7.0 version: 29.7.0 nodemon: - specifier: 3.1.0 - version: 3.1.0 + specifier: 3.1.4 + version: 3.1.4 pid-port: specifier: 1.0.0 version: 1.0.0 simple-oauth2: - specifier: 5.0.0 - version: 5.0.0 + specifier: 5.0.1 + version: 5.0.1 packages/frontend: dependencies: @@ -705,16 +702,16 @@ importers: version: 2024.1.0 '@rollup/plugin-json': specifier: 6.1.0 - version: 6.1.0(rollup@4.17.2) + version: 6.1.0(rollup@4.18.0) '@rollup/plugin-replace': - specifier: 5.0.5 - version: 5.0.5(rollup@4.17.2) + specifier: 5.0.7 + version: 5.0.7(rollup@4.18.0) '@rollup/pluginutils': specifier: 5.1.0 - version: 5.1.0(rollup@4.17.2) + version: 5.1.0(rollup@4.18.0) '@syuilo/aiscript': - specifier: 0.18.0 - version: 0.18.0 + specifier: 0.19.0 + version: 0.19.0 '@tabler/icons-webfont': specifier: 3.3.0 version: 3.3.0 @@ -722,14 +719,14 @@ importers: specifier: 15.1.1 version: 15.1.1 '@vitejs/plugin-vue': - specifier: 5.0.4 - version: 5.0.4(vite@5.2.11(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3))(vue@3.4.26(typescript@5.4.5)) + specifier: 5.0.5 + version: 5.0.5(vite@5.3.2(@types/node@20.14.9)(sass@1.77.6)(terser@5.31.2))(vue@3.4.31(typescript@5.5.3)) '@vue/compiler-sfc': - specifier: 3.4.26 - version: 3.4.26 + specifier: 3.4.31 + version: 3.4.31 aiscript-vscode: - specifier: github:aiscript-dev/aiscript-vscode#v0.1.9 - version: https://codeload.github.com/aiscript-dev/aiscript-vscode/tar.gz/34bf4e1530efcf1efa855bd04e2dab39735e1b02 + specifier: github:aiscript-dev/aiscript-vscode#v0.1.11 + version: https://codeload.github.com/aiscript-dev/aiscript-vscode/tar.gz/e1e1b27f2f72cd28a473e004b6da0d8fc0bd40d9 astring: specifier: 1.8.6 version: 1.8.6 @@ -743,23 +740,23 @@ importers: specifier: 1.9.3 version: 1.9.3 chart.js: - specifier: 4.4.2 - version: 4.4.2 + specifier: 4.4.3 + version: 4.4.3 chartjs-adapter-date-fns: specifier: 3.0.0 - version: 3.0.0(chart.js@4.4.2)(date-fns@2.30.0) + version: 3.0.0(chart.js@4.4.3)(date-fns@2.30.0) chartjs-chart-matrix: specifier: 2.0.1 - version: 2.0.1(chart.js@4.4.2) + version: 2.0.1(chart.js@4.4.3) chartjs-plugin-gradient: specifier: 0.6.1 - version: 0.6.1(chart.js@4.4.2) + version: 0.6.1(chart.js@4.4.3) chartjs-plugin-zoom: specifier: 2.0.1 - version: 2.0.1(chart.js@4.4.2) + version: 2.0.1(chart.js@4.4.3) chromatic: - specifier: 11.3.0 - version: 11.3.0 + specifier: 11.5.4 + version: 11.5.4 compare-versions: specifier: 6.1.0 version: 6.1.0 @@ -806,23 +803,23 @@ importers: specifier: workspace:* version: link:../misskey-reversi photoswipe: - specifier: 5.4.3 - version: 5.4.3 + specifier: 5.4.4 + version: 5.4.4 punycode: specifier: 2.3.1 version: 2.3.1 rollup: - specifier: 4.17.2 - version: 4.17.2 + specifier: 4.18.0 + version: 4.18.0 sanitize-html: specifier: 2.13.0 version: 2.13.0 sass: - specifier: 1.76.0 - version: 1.76.0 + specifier: 1.77.6 + version: 1.77.6 shiki: - specifier: 1.4.0 - version: 1.4.0 + specifier: 1.10.0 + version: 1.10.0 strict-event-emitter-types: specifier: 2.0.0 version: 2.0.0 @@ -830,102 +827,99 @@ importers: specifier: 3.1.0 version: 3.1.0 three: - specifier: 0.164.1 - version: 0.164.1 + specifier: 0.165.0 + version: 0.165.0 throttle-debounce: - specifier: 5.0.0 - version: 5.0.0 + specifier: 5.0.2 + version: 5.0.2 tinycolor2: specifier: 1.6.0 version: 1.6.0 tsc-alias: - specifier: 1.8.8 - version: 1.8.8 + specifier: 1.8.10 + version: 1.8.10 tsconfig-paths: specifier: 4.2.0 version: 4.2.0 typescript: - specifier: 5.4.5 - version: 5.4.5 + specifier: 5.5.3 + version: 5.5.3 uuid: - specifier: 9.0.1 - version: 9.0.1 + specifier: 10.0.0 + version: 10.0.0 v-code-diff: - specifier: 1.11.0 - version: 1.11.0(vue@3.4.26(typescript@5.4.5)) + specifier: 1.12.0 + version: 1.12.0(vue@3.4.31(typescript@5.5.3)) vite: - specifier: 5.2.11 - version: 5.2.11(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3) + specifier: 5.3.2 + version: 5.3.2(@types/node@20.14.9)(sass@1.77.6)(terser@5.31.2) vue: - specifier: 3.4.26 - version: 3.4.26(typescript@5.4.5) + specifier: 3.4.31 + version: 3.4.31(typescript@5.5.3) vuedraggable: specifier: next - version: 4.1.0(vue@3.4.26(typescript@5.4.5)) + version: 4.1.0(vue@3.4.31(typescript@5.5.3)) devDependencies: - '@misskey-dev/eslint-plugin': - specifier: 1.0.0 - version: 1.0.0(@typescript-eslint/eslint-plugin@7.7.1(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5))(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0))(eslint@8.57.0) '@misskey-dev/summaly': specifier: 5.1.0 version: 5.1.0 '@storybook/addon-actions': - specifier: 8.0.9 - version: 8.0.9 + specifier: 8.1.11 + version: 8.1.11 '@storybook/addon-essentials': - specifier: 8.0.9 - version: 8.0.9(@types/react@18.0.28)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + specifier: 8.1.11 + version: 8.1.11(@types/react@18.0.28)(encoding@0.1.13)(prettier@3.3.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@storybook/addon-interactions': - specifier: 8.0.9 - version: 8.0.9(@jest/globals@29.7.0)(@types/jest@29.5.12)(jest@29.7.0(@types/node@20.12.7))(vitest@0.34.6(happy-dom@10.0.3)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3)) + specifier: 8.1.11 + version: 8.1.11(@jest/globals@29.7.0)(@types/jest@29.5.12)(jest@29.7.0(@types/node@20.14.9))(vitest@1.6.0(@types/node@20.14.9)(happy-dom@10.0.3)(jsdom@24.1.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))(sass@1.77.6)(terser@5.31.2)) '@storybook/addon-links': - specifier: 8.0.9 - version: 8.0.9(react@18.3.1) + specifier: 8.1.11 + version: 8.1.11(react@18.3.1) '@storybook/addon-mdx-gfm': - specifier: 8.0.9 - version: 8.0.9 + specifier: 8.1.11 + version: 8.1.11 '@storybook/addon-storysource': - specifier: 8.0.9 - version: 8.0.9 + specifier: 8.1.11 + version: 8.1.11 '@storybook/blocks': - specifier: 8.0.9 - version: 8.0.9(@types/react@18.0.28)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + specifier: 8.1.11 + version: 8.1.11(@types/react@18.0.28)(encoding@0.1.13)(prettier@3.3.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@storybook/components': - specifier: 8.0.9 - version: 8.0.9(@types/react@18.0.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + specifier: 8.1.11 + version: 8.1.11(@types/react@18.0.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@storybook/core-events': - specifier: 8.0.9 - version: 8.0.9 + specifier: 8.1.11 + version: 8.1.11 '@storybook/manager-api': - specifier: 8.0.9 - version: 8.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + specifier: 8.1.11 + version: 8.1.11(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@storybook/preview-api': - specifier: 8.0.9 - version: 8.0.9 + specifier: 8.1.11 + version: 8.1.11 '@storybook/react': - specifier: 8.0.9 - version: 8.0.9(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5) + specifier: 8.1.11 + version: 8.1.11(encoding@0.1.13)(prettier@3.3.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.3) '@storybook/react-vite': - specifier: 8.0.9 - version: 8.0.9(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@4.17.2)(typescript@5.4.5)(vite@5.2.11(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3)) + specifier: 8.1.11 + version: 8.1.11(encoding@0.1.13)(prettier@3.3.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@4.18.0)(typescript@5.5.3)(vite@5.3.2(@types/node@20.14.9)(sass@1.77.6)(terser@5.31.2)) '@storybook/test': - specifier: 8.0.9 - version: 8.0.9(@jest/globals@29.7.0)(@types/jest@29.5.12)(jest@29.7.0(@types/node@20.12.7))(vitest@0.34.6(happy-dom@10.0.3)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3)) + specifier: 8.1.11 + version: 8.1.11(@jest/globals@29.7.0)(@types/jest@29.5.12)(jest@29.7.0(@types/node@20.14.9))(vitest@1.6.0(@types/node@20.14.9)(happy-dom@10.0.3)(jsdom@24.1.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))(sass@1.77.6)(terser@5.31.2)) '@storybook/theming': - specifier: 8.0.9 - version: 8.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + specifier: 8.1.11 + version: 8.1.11(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@storybook/types': - specifier: 8.0.9 - version: 8.0.9 + specifier: 8.1.11 + version: 8.1.11 '@storybook/vue3': - specifier: 8.0.9 - version: 8.0.9(encoding@0.1.13)(vue@3.4.26(typescript@5.4.5)) + specifier: 8.1.11 + version: 8.1.11(encoding@0.1.13)(prettier@3.3.2)(vue@3.4.31(typescript@5.5.3)) '@storybook/vue3-vite': - specifier: 8.0.9 - version: 8.0.9(bufferutil@4.0.7)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(utf-8-validate@6.0.3)(vite@5.2.11(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3))(vue@3.4.26(typescript@5.4.5)) + specifier: 8.1.11 + version: 8.1.11(bufferutil@4.0.8)(encoding@0.1.13)(prettier@3.3.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(utf-8-validate@6.0.4)(vite@5.3.2(@types/node@20.14.9)(sass@1.77.6)(terser@5.31.2))(vue@3.4.31(typescript@5.5.3)) '@testing-library/vue': - specifier: 8.0.3 - version: 8.0.3(@vue/compiler-sfc@3.4.26)(@vue/server-renderer@3.4.26(vue@3.4.26(typescript@5.4.5)))(vue@3.4.26(typescript@5.4.5)) + specifier: 8.1.0 + version: 8.1.0(@vue/compiler-sfc@3.4.31)(@vue/server-renderer@3.4.31(vue@3.4.31(typescript@5.5.3)))(vue@3.4.31(typescript@5.5.3)) '@types/escape-regexp': specifier: 0.0.3 version: 0.0.3 @@ -936,17 +930,20 @@ importers: specifier: 0.19.6 version: 0.19.6 '@types/micromatch': - specifier: 4.0.7 - version: 4.0.7 + specifier: 4.0.9 + version: 4.0.9 '@types/node': - specifier: 20.12.7 - version: 20.12.7 + specifier: 20.14.9 + version: 20.14.9 '@types/punycode': specifier: 2.1.4 version: 2.1.4 '@types/sanitize-html': specifier: 2.11.0 version: 2.11.0 + '@types/seedrandom': + specifier: 3.0.8 + version: 3.0.8 '@types/throttle-debounce': specifier: 5.0.2 version: 5.0.2 @@ -954,41 +951,38 @@ importers: specifier: 1.4.6 version: 1.4.6 '@types/uuid': - specifier: 9.0.8 - version: 9.0.8 + specifier: 10.0.0 + version: 10.0.0 '@types/ws': specifier: 8.5.10 version: 8.5.10 '@typescript-eslint/eslint-plugin': - specifier: 7.7.1 - version: 7.7.1(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5) + specifier: 7.15.0 + version: 7.15.0(@typescript-eslint/parser@7.15.0(eslint@9.7.0)(typescript@5.5.3))(eslint@9.7.0)(typescript@5.5.3) '@typescript-eslint/parser': - specifier: 7.7.1 - version: 7.7.1(eslint@8.57.0)(typescript@5.4.5) + specifier: 7.15.0 + version: 7.15.0(eslint@9.7.0)(typescript@5.5.3) '@vitest/coverage-v8': - specifier: 0.34.6 - version: 0.34.6(vitest@0.34.6(happy-dom@10.0.3)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3)) + specifier: 1.6.0 + version: 1.6.0(vitest@1.6.0(@types/node@20.14.9)(happy-dom@10.0.3)(jsdom@24.1.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))(sass@1.77.6)(terser@5.31.2)) '@vue/runtime-core': - specifier: 3.4.26 - version: 3.4.26 + specifier: 3.4.31 + version: 3.4.31 acorn: - specifier: 8.11.3 - version: 8.11.3 + specifier: 8.12.0 + version: 8.12.0 cross-env: specifier: 7.0.3 version: 7.0.3 cypress: - specifier: 13.8.1 - version: 13.8.1 - eslint: - specifier: 8.57.0 - version: 8.57.0 + specifier: 13.13.0 + version: 13.13.0 eslint-plugin-import: specifier: 2.29.1 - version: 2.29.1(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0) + version: 2.29.1(@typescript-eslint/parser@7.15.0(eslint@9.7.0)(typescript@5.5.3))(eslint@9.7.0) eslint-plugin-vue: - specifier: 9.25.0 - version: 9.25.0(eslint@8.57.0) + specifier: 9.26.0 + version: 9.26.0(eslint@9.7.0) fast-glob: specifier: 3.3.2 version: 3.3.2 @@ -999,53 +993,56 @@ importers: specifier: 0.12.2 version: 0.12.2 micromatch: - specifier: 4.0.5 - version: 4.0.5 + specifier: 4.0.7 + version: 4.0.7 msw: - specifier: 2.2.14 - version: 2.2.14(typescript@5.4.5) + specifier: 2.3.1 + version: 2.3.1(typescript@5.5.3) msw-storybook-addon: - specifier: 2.0.1 - version: 2.0.1(msw@2.2.14(typescript@5.4.5)) + specifier: 2.0.2 + version: 2.0.2(msw@2.3.1(typescript@5.5.3)) nodemon: - specifier: 3.1.0 - version: 3.1.0 + specifier: 3.1.4 + version: 3.1.4 prettier: - specifier: 3.2.5 - version: 3.2.5 + specifier: 3.3.2 + version: 3.3.2 react: specifier: 18.3.1 version: 18.3.1 react-dom: specifier: 18.3.1 version: 18.3.1(react@18.3.1) + seedrandom: + specifier: 3.0.5 + version: 3.0.5 start-server-and-test: - specifier: 2.0.3 - version: 2.0.3 + specifier: 2.0.4 + version: 2.0.4 storybook: - specifier: 8.0.9 - version: 8.0.9(@babel/preset-env@7.23.5(@babel/core@7.24.0))(bufferutil@4.0.7)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(utf-8-validate@6.0.3) + specifier: 8.1.11 + version: 8.1.11(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(utf-8-validate@6.0.4) storybook-addon-misskey-theme: specifier: github:misskey-dev/storybook-addon-misskey-theme - version: https://codeload.github.com/misskey-dev/storybook-addon-misskey-theme/tar.gz/cf583db098365b2ccc81a82f63ca9c93bc32b640(@storybook/blocks@8.0.9(@types/react@18.0.28)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@storybook/components@8.0.9(@types/react@18.0.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@storybook/core-events@8.0.9)(@storybook/manager-api@8.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@storybook/preview-api@8.0.9)(@storybook/theming@8.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@storybook/types@8.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: https://codeload.github.com/misskey-dev/storybook-addon-misskey-theme/tar.gz/cf583db098365b2ccc81a82f63ca9c93bc32b640(@storybook/blocks@8.1.11(@types/react@18.0.28)(encoding@0.1.13)(prettier@3.3.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@storybook/components@8.1.11(@types/react@18.0.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@storybook/core-events@8.1.11)(@storybook/manager-api@8.1.11(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@storybook/preview-api@8.1.11)(@storybook/theming@8.1.11(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@storybook/types@8.1.11)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) vite-plugin-turbosnap: specifier: 1.0.3 version: 1.0.3 vitest: - specifier: 0.34.6 - version: 0.34.6(happy-dom@10.0.3)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3) + specifier: 1.6.0 + version: 1.6.0(@types/node@20.14.9)(happy-dom@10.0.3)(jsdom@24.1.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))(sass@1.77.6)(terser@5.31.2) vitest-fetch-mock: specifier: 0.2.2 - version: 0.2.2(encoding@0.1.13)(vitest@0.34.6(happy-dom@10.0.3)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3)) + version: 0.2.2(encoding@0.1.13)(vitest@1.6.0(@types/node@20.14.9)(happy-dom@10.0.3)(jsdom@24.1.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))(sass@1.77.6)(terser@5.31.2)) vue-component-type-helpers: - specifier: 2.0.16 - version: 2.0.16 + specifier: 2.0.24 + version: 2.0.24 vue-eslint-parser: - specifier: 9.4.2 - version: 9.4.2(eslint@8.57.0) + specifier: 9.4.3 + version: 9.4.3(eslint@9.7.0) vue-tsc: - specifier: 2.0.16 - version: 2.0.16(typescript@5.4.5) + specifier: 2.0.24 + version: 2.0.24(typescript@5.5.3) packages/misskey-bubble-game: dependencies: @@ -1059,9 +1056,6 @@ importers: specifier: 3.0.5 version: 3.0.5 devDependencies: - '@misskey-dev/eslint-plugin': - specifier: 1.0.0 - version: 1.0.0(@typescript-eslint/eslint-plugin@7.1.0(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint@8.57.0)(typescript@5.3.3))(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint@8.57.0))(eslint@8.57.0) '@types/matter-js': specifier: 0.19.6 version: 0.19.6 @@ -1073,16 +1067,13 @@ importers: version: 3.0.8 '@typescript-eslint/eslint-plugin': specifier: 7.1.0 - version: 7.1.0(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint@8.57.0)(typescript@5.3.3) + version: 7.1.0(@typescript-eslint/parser@7.1.0(eslint@9.7.0)(typescript@5.3.3))(eslint@9.7.0)(typescript@5.3.3) '@typescript-eslint/parser': specifier: 7.1.0 - version: 7.1.0(eslint@8.57.0)(typescript@5.3.3) + version: 7.1.0(eslint@9.7.0)(typescript@5.3.3) esbuild: specifier: 0.19.11 version: 0.19.11 - eslint: - specifier: 8.57.0 - version: 8.57.0 execa: specifier: 8.0.1 version: 8.0.1 @@ -1106,41 +1097,35 @@ importers: version: 4.4.0 devDependencies: '@microsoft/api-extractor': - specifier: 7.43.1 - version: 7.43.1(@types/node@20.12.7) - '@misskey-dev/eslint-plugin': - specifier: 1.0.0 - version: 1.0.0(@typescript-eslint/eslint-plugin@7.7.1(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5))(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0))(eslint@8.57.0) + specifier: 7.47.0 + version: 7.47.0(@types/node@20.14.9) '@swc/jest': specifier: 0.2.36 - version: 0.2.36(@swc/core@1.4.17) + version: 0.2.36(@swc/core@1.6.13) '@types/jest': specifier: 29.5.12 version: 29.5.12 '@types/node': - specifier: 20.12.7 - version: 20.12.7 + specifier: 20.14.9 + version: 20.14.9 '@typescript-eslint/eslint-plugin': - specifier: 7.7.1 - version: 7.7.1(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5) + specifier: 7.15.0 + version: 7.15.0(@typescript-eslint/parser@7.15.0(eslint@9.7.0)(typescript@5.5.3))(eslint@9.7.0)(typescript@5.5.3) '@typescript-eslint/parser': - specifier: 7.7.1 - version: 7.7.1(eslint@8.57.0)(typescript@5.4.5) + specifier: 7.15.0 + version: 7.15.0(eslint@9.7.0)(typescript@5.5.3) esbuild: - specifier: 0.19.11 - version: 0.19.11 - eslint: - specifier: 8.57.0 - version: 8.57.0 + specifier: 0.22.0 + version: 0.22.0 execa: - specifier: 8.0.1 - version: 8.0.1 + specifier: 9.2.0 + version: 9.2.0 glob: - specifier: 10.3.12 - version: 10.3.12 + specifier: 10.4.2 + version: 10.4.2 jest: specifier: 29.7.0 - version: 29.7.0(@types/node@20.12.7) + version: 29.7.0(@types/node@20.14.9) jest-fetch-mock: specifier: 3.0.3 version: 3.0.3(encoding@0.1.13) @@ -1154,20 +1139,17 @@ importers: specifier: 2.0.0 version: 2.0.0 nodemon: - specifier: 3.1.0 - version: 3.1.0 + specifier: 3.1.4 + version: 3.1.4 tsd: - specifier: 0.30.7 - version: 0.30.7 + specifier: 0.31.1 + version: 0.31.1 typescript: - specifier: 5.4.5 - version: 5.4.5 + specifier: 5.5.3 + version: 5.5.3 packages/misskey-js/generator: devDependencies: - '@misskey-dev/eslint-plugin': - specifier: ^1.0.0 - version: 1.0.0(@typescript-eslint/eslint-plugin@6.11.0(@typescript-eslint/parser@6.11.0(eslint@8.53.0)(typescript@5.3.3))(eslint@8.53.0)(typescript@5.3.3))(@typescript-eslint/parser@6.11.0(eslint@8.53.0)(typescript@5.3.3))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.11.0(eslint@8.53.0)(typescript@5.3.3))(eslint@8.53.0))(eslint@8.53.0) '@readme/openapi-parser': specifier: 2.5.0 version: 2.5.0(openapi-types@12.1.3) @@ -1176,13 +1158,10 @@ importers: version: 20.9.1 '@typescript-eslint/eslint-plugin': specifier: 6.11.0 - version: 6.11.0(@typescript-eslint/parser@6.11.0(eslint@8.53.0)(typescript@5.3.3))(eslint@8.53.0)(typescript@5.3.3) + version: 6.11.0(@typescript-eslint/parser@6.11.0(eslint@9.7.0)(typescript@5.3.3))(eslint@9.7.0)(typescript@5.3.3) '@typescript-eslint/parser': specifier: 6.11.0 - version: 6.11.0(eslint@8.53.0)(typescript@5.3.3) - eslint: - specifier: 8.53.0 - version: 8.53.0 + version: 6.11.0(eslint@9.7.0)(typescript@5.3.3) openapi-types: specifier: 12.1.3 version: 12.1.3 @@ -1205,24 +1184,18 @@ importers: specifier: 1.2.2 version: 1.2.2 devDependencies: - '@misskey-dev/eslint-plugin': - specifier: 1.0.0 - version: 1.0.0(@typescript-eslint/eslint-plugin@7.1.0(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint@8.57.0)(typescript@5.3.3))(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint@8.57.0))(eslint@8.57.0) '@types/node': specifier: 20.11.5 version: 20.11.5 '@typescript-eslint/eslint-plugin': specifier: 7.1.0 - version: 7.1.0(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint@8.57.0)(typescript@5.3.3) + version: 7.1.0(@typescript-eslint/parser@7.1.0(eslint@9.7.0)(typescript@5.3.3))(eslint@9.7.0)(typescript@5.3.3) '@typescript-eslint/parser': specifier: 7.1.0 - version: 7.1.0(eslint@8.57.0)(typescript@5.3.3) + version: 7.1.0(eslint@9.7.0)(typescript@5.3.3) esbuild: specifier: 0.19.11 version: 0.19.11 - eslint: - specifier: 8.57.0 - version: 8.57.0 execa: specifier: 8.0.1 version: 8.0.1 @@ -1239,8 +1212,8 @@ importers: packages/sw: dependencies: esbuild: - specifier: 0.20.2 - version: 0.20.2 + specifier: 0.22.0 + version: 0.22.0 idb-keyval: specifier: 6.2.1 version: 6.2.1 @@ -1248,27 +1221,21 @@ importers: specifier: workspace:* version: link:../misskey-js devDependencies: - '@misskey-dev/eslint-plugin': - specifier: 1.0.0 - version: 1.0.0(@typescript-eslint/eslint-plugin@7.7.1(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5))(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0))(eslint@8.57.0) '@typescript-eslint/parser': - specifier: 7.7.1 - version: 7.7.1(eslint@8.57.0)(typescript@5.4.5) + specifier: 7.15.0 + version: 7.15.0(eslint@9.7.0)(typescript@5.5.3) '@typescript/lib-webworker': specifier: npm:@types/serviceworker@0.0.67 version: '@types/serviceworker@0.0.67' - eslint: - specifier: 8.57.0 - version: 8.57.0 eslint-plugin-import: specifier: 2.29.1 - version: 2.29.1(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0) + version: 2.29.1(@typescript-eslint/parser@7.15.0(eslint@9.7.0)(typescript@5.5.3))(eslint@9.7.0) nodemon: - specifier: 3.1.0 - version: 3.1.0 + specifier: 3.1.4 + version: 3.1.4 typescript: - specifier: 5.4.5 - version: 5.4.5 + specifier: 5.5.3 + version: 5.5.3 packages: @@ -1299,221 +1266,239 @@ packages: resolution: {integrity: sha512-Xk1sIhyNC/esHGGVjL/niHLowM0csl/kFO5uawBy4IrWwy0o1G8LGt3jP6nmWGz+USxeeqbihAmp/oVZju6wug==} hasBin: true - '@aws-crypto/crc32@3.0.0': - resolution: {integrity: sha512-IzSgsrxUcsrejQbPVilIKy16kAT52EwB6zSaI+M3xxIhKh5+aldEyvI+z6erM7TCLB2BJsFrtHjp6/4/sr+3dA==} + '@aws-crypto/crc32@5.2.0': + resolution: {integrity: sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg==} + engines: {node: '>=16.0.0'} - '@aws-crypto/crc32c@3.0.0': - resolution: {integrity: sha512-ENNPPManmnVJ4BTXlOjAgD7URidbAznURqD0KvfREyc4o20DPYdEldU1f5cQ7Jbj0CJJSPaMIk/9ZshdB3210w==} + '@aws-crypto/crc32c@5.2.0': + resolution: {integrity: sha512-+iWb8qaHLYKrNvGRbiYRHSdKRWhto5XlZUEBwDjYNf+ly5SVYG6zEoYIdxvf5R3zyeP16w4PLBn3rH1xc74Rag==} - '@aws-crypto/ie11-detection@3.0.0': - resolution: {integrity: sha512-341lBBkiY1DfDNKai/wXM3aujNBkXR7tq1URPQDL9wi3AUbI80NR74uF1TXHMm7po1AcnFk8iu2S2IeU/+/A+Q==} + '@aws-crypto/sha1-browser@5.2.0': + resolution: {integrity: sha512-OH6lveCFfcDjX4dbAvCFSYUjJZjDr/3XJ3xHtjn3Oj5b9RjojQo8npoLeA/bNwkOkrSQ0wgrHzXk4tDRxGKJeg==} - '@aws-crypto/sha1-browser@3.0.0': - resolution: {integrity: sha512-NJth5c997GLHs6nOYTzFKTbYdMNA6/1XlKVgnZoaZcQ7z7UJlOgj2JdbHE8tiYLS3fzXNCguct77SPGat2raSw==} + '@aws-crypto/sha256-browser@5.2.0': + resolution: {integrity: sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==} - '@aws-crypto/sha256-browser@3.0.0': - resolution: {integrity: sha512-8VLmW2B+gjFbU5uMeqtQM6Nj0/F1bro80xQXCW6CQBWgosFWXTx77aeOF5CAIAmbOK64SdMBJdNr6J41yP5mvQ==} + '@aws-crypto/sha256-js@5.2.0': + resolution: {integrity: sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==} + engines: {node: '>=16.0.0'} - '@aws-crypto/sha256-js@3.0.0': - resolution: {integrity: sha512-PnNN7os0+yd1XvXAy23CFOmTbMaDxgxXtTKHybrJ39Y8kGzBATgBFibWJKH6BhytLI/Zyszs87xCOBNyBig6vQ==} + '@aws-crypto/supports-web-crypto@5.2.0': + resolution: {integrity: sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==} - '@aws-crypto/supports-web-crypto@3.0.0': - resolution: {integrity: sha512-06hBdMwUAb2WFTuGG73LSC0wfPu93xWwo5vL2et9eymgmu3Id5vFAHBbajVWiGhPO37qcsdCap/FqXvJGJWPIg==} + '@aws-crypto/util@5.2.0': + resolution: {integrity: sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==} - '@aws-crypto/util@3.0.0': - resolution: {integrity: sha512-2OJlpeJpCR48CC8r+uKVChzs9Iungj9wkZrl8Z041DWEWvyIHILYKCPNzJghKsivj+S3mLo6BVc7mBNzdxA46w==} + '@aws-sdk/client-s3@3.600.0': + resolution: {integrity: sha512-iYoKbJTputbf+ubkX6gSK/y/4uJEBRaXZ18jykLdBQ8UJuGrk2gqvV8h7OlGAhToCeysmmMqM0vDWyLt6lP8nw==} + engines: {node: '>=16.0.0'} - '@aws-sdk/client-s3@3.412.0': - resolution: {integrity: sha512-sNrlx9sSBmFUCqMgTznwk9Fee3PJat0nZ3RIDR5Crhsld/eexxrqb6TYKsxzFfBfXTL/oPh+/S5driRV2xsB8A==} - engines: {node: '>=14.0.0'} + '@aws-sdk/client-sso-oidc@3.600.0': + resolution: {integrity: sha512-7+I8RWURGfzvChyNQSyj5/tKrqRbzRl7H+BnTOf/4Vsw1nFOi5ROhlhD4X/Y0QCTacxnaoNcIrqnY7uGGvVRzw==} + engines: {node: '>=16.0.0'} - '@aws-sdk/client-sso@3.410.0': - resolution: {integrity: sha512-MC9GrgwtlOuSL2WS3DRM3dQ/5y+49KSMMJRH6JiEcU5vE0dX/OtEcX+VfEwpi73x5pSfIjm7xnzjzOFx+sQBIg==} - engines: {node: '>=14.0.0'} + '@aws-sdk/client-sso@3.598.0': + resolution: {integrity: sha512-nOI5lqPYa+YZlrrzwAJywJSw3MKVjvu6Ge2fCqQUNYMfxFB0NAaDFnl0EPjXi+sEbtCuz/uWE77poHbqiZ+7Iw==} + engines: {node: '>=16.0.0'} - '@aws-sdk/client-sts@3.410.0': - resolution: {integrity: sha512-e6VMrBJtnTxxUXwDmkADGIvyppmDMFf4+cGGA68tVCUm1cFNlCI6M/67bVSIPN/WVKAAfhEL5O2vVXCM7aatYg==} - engines: {node: '>=14.0.0'} + '@aws-sdk/client-sts@3.600.0': + resolution: {integrity: sha512-KQG97B7LvTtTiGmjlrG1LRAY8wUvCQzrmZVV5bjrJ/1oXAU7DITYwVbSJeX9NWg6hDuSk0VE3MFwIXS2SvfLIA==} + engines: {node: '>=16.0.0'} - '@aws-sdk/credential-provider-env@3.410.0': - resolution: {integrity: sha512-c7TB9LbN0PkFOsXI0lcRJnqPNOmc4VBvrHf8jP/BkTDg4YUoKQKOFd4d0SqzODmlZiAyoMQVZTR4ISZo95Zj4Q==} - engines: {node: '>=14.0.0'} + '@aws-sdk/core@3.598.0': + resolution: {integrity: sha512-HaSjt7puO5Cc7cOlrXFCW0rtA0BM9lvzjl56x0A20Pt+0wxXGeTOZZOkXQIepbrFkV2e/HYukuT9e99vXDm59g==} + engines: {node: '>=16.0.0'} - '@aws-sdk/credential-provider-ini@3.410.0': - resolution: {integrity: sha512-D8rcr5bRCFD0f42MPQ7K6TWZq5d3pfqrKINL1/bpfkK5BJbvq1BGYmR88UC6CLpTRtZ1LHY2HgYG0fp/2zjjww==} - engines: {node: '>=14.0.0'} + '@aws-sdk/credential-provider-env@3.598.0': + resolution: {integrity: sha512-vi1khgn7yXzLCcgSIzQrrtd2ilUM0dWodxj3PQ6BLfP0O+q1imO3hG1nq7DVyJtq7rFHs6+9N8G4mYvTkxby2w==} + engines: {node: '>=16.0.0'} - '@aws-sdk/credential-provider-node@3.410.0': - resolution: {integrity: sha512-0wmVm33T/j1FS7MZ/j+WsPlgSc0YnCXnpbWSov1Mn6R86SHI2b2JhdIPRRE4XbGfyW2QGNUl2CwoZVaqhXeF5g==} - engines: {node: '>=14.0.0'} + '@aws-sdk/credential-provider-http@3.598.0': + resolution: {integrity: sha512-N7cIafi4HVlQvEgvZSo1G4T9qb/JMLGMdBsDCT5XkeJrF0aptQWzTFH0jIdZcLrMYvzPcuEyO3yCBe6cy/ba0g==} + engines: {node: '>=16.0.0'} - '@aws-sdk/credential-provider-process@3.410.0': - resolution: {integrity: sha512-BMju1hlDCDNkkSZpKF5SQ8G0WCLRj6/Jvw9QmudLHJuVwYJXEW1r2AsVMg98OZ3hB9G+MAvHruHZIbMiNmUMXQ==} - engines: {node: '>=14.0.0'} - - '@aws-sdk/credential-provider-sso@3.410.0': - resolution: {integrity: sha512-zEaoY/sY+KYTlQUkp9dvveAHf175b8RIt0DsQkDrRPtrg/RBHR00r5rFvz9+nrwsR8546RaBU7h/zzTaQGhmcA==} - engines: {node: '>=14.0.0'} - - '@aws-sdk/credential-provider-web-identity@3.410.0': - resolution: {integrity: sha512-cE0l8LmEHdWbDkdPNgrfdYSgp4/cIVXrjUKI1QCATA729CrHZ/OQjB/maOBOrMHO9YTiggko887NkslVvwVB7w==} - engines: {node: '>=14.0.0'} - - '@aws-sdk/lib-storage@3.412.0': - resolution: {integrity: sha512-uAdVtNuip06rJOs28zVrYXLNeHfKraxvJRTzTA+DW1dXkzh70GTKqDKHWH9IJkW/xMTE6wGSM+fDs8jsMOn/yA==} - engines: {node: '>=14.0.0'} + '@aws-sdk/credential-provider-ini@3.598.0': + resolution: {integrity: sha512-/ppcIVUbRwDIwJDoYfp90X3+AuJo2mvE52Y1t2VSrvUovYn6N4v95/vXj6LS8CNDhz2jvEJYmu+0cTMHdhI6eA==} + engines: {node: '>=16.0.0'} peerDependencies: - '@aws-sdk/client-s3': ^3.0.0 + '@aws-sdk/client-sts': ^3.598.0 - '@aws-sdk/middleware-bucket-endpoint@3.410.0': - resolution: {integrity: sha512-pUGrpFgCKf9fDHu01JJhhw+MUImheS0HFlZwNG37OMubkxUAbCdmYGewGxfTCUvWyZJtx9bVjrSu6gG7w+RARg==} - engines: {node: '>=14.0.0'} + '@aws-sdk/credential-provider-node@3.600.0': + resolution: {integrity: sha512-1pC7MPMYD45J7yFjA90SxpR0yaSvy+yZiq23aXhAPZLYgJBAxHLu0s0mDCk/piWGPh8+UGur5K0bVdx4B1D5hw==} + engines: {node: '>=16.0.0'} - '@aws-sdk/middleware-expect-continue@3.410.0': - resolution: {integrity: sha512-e5YqGCNmW99GZjEPPujJ02RlEZql19U40oORysBhVF7mKz8BBvF3s8l37tvu37oxebDEkh1u/2cm2+ggOXxLjQ==} - engines: {node: '>=14.0.0'} + '@aws-sdk/credential-provider-process@3.598.0': + resolution: {integrity: sha512-rM707XbLW8huMk722AgjVyxu2tMZee++fNA8TJVNgs1Ma02Wx6bBrfIvlyK0rCcIRb0WdQYP6fe3Xhiu4e8IBA==} + engines: {node: '>=16.0.0'} - '@aws-sdk/middleware-flexible-checksums@3.410.0': - resolution: {integrity: sha512-IK7KlvEKtrQVBfmAp/MmGd0wbWLuN2GZwwfAmsU0qFb0f5vOVUbKDsu6tudtDKCBG9uXyTEsx3/QGvoK2zDy+g==} - engines: {node: '>=14.0.0'} + '@aws-sdk/credential-provider-sso@3.598.0': + resolution: {integrity: sha512-5InwUmrAuqQdOOgxTccRayMMkSmekdLk6s+az9tmikq0QFAHUCtofI+/fllMXSR9iL6JbGYi1940+EUmS4pHJA==} + engines: {node: '>=16.0.0'} - '@aws-sdk/middleware-host-header@3.410.0': - resolution: {integrity: sha512-ED/OVcyITln5rrxnajZP+V0PN1nug+gSDHJDqdDo/oLy7eiDr/ZWn3nlWW7WcMplQ1/Jnb+hK0UetBp/25XooA==} - engines: {node: '>=14.0.0'} + '@aws-sdk/credential-provider-web-identity@3.598.0': + resolution: {integrity: sha512-GV5GdiMbz5Tz9JO4NJtRoFXjW0GPEujA0j+5J/B723rTN+REHthJu48HdBKouHGhdzkDWkkh1bu52V02Wprw8w==} + engines: {node: '>=16.0.0'} + peerDependencies: + '@aws-sdk/client-sts': ^3.598.0 - '@aws-sdk/middleware-location-constraint@3.410.0': - resolution: {integrity: sha512-jAftSpOpw/5AdpOJ/cGiXCb+Vv22KXR5QZmxmllUDsnlm18672tpRaI2plmu/1d98CVvqhY61eSklFMrIf2c4w==} - engines: {node: '>=14.0.0'} + '@aws-sdk/lib-storage@3.600.0': + resolution: {integrity: sha512-jjgGMmFykXBAs8YO3ghgnVSjM/uf99jvVQqKJfDjwXUCLPrsZqk14v2WcDCWAXzeAroDvIOVQO1V/RR8fK18Pw==} + engines: {node: '>=16.0.0'} + peerDependencies: + '@aws-sdk/client-s3': ^3.600.0 - '@aws-sdk/middleware-logger@3.410.0': - resolution: {integrity: sha512-YtmKYCVtBfScq3/UFJk+aSZOktKJBNZL9DaSc2aPcy/goCVsYDOkGwtHk0jIkC1JRSNCkVTqL7ya60sSr8zaQQ==} - engines: {node: '>=14.0.0'} + '@aws-sdk/middleware-bucket-endpoint@3.598.0': + resolution: {integrity: sha512-PM7BcFfGUSkmkT6+LU9TyJiB4S8yI7dfuKQDwK5ZR3P7MKaK4Uj4yyDiv0oe5xvkF6+O2+rShj+eh8YuWkOZ/Q==} + engines: {node: '>=16.0.0'} - '@aws-sdk/middleware-recursion-detection@3.410.0': - resolution: {integrity: sha512-KWaes5FLzRqj28vaIEE4Bimpga2E596WdPF2HaH6zsVMJddoRDsc3ZX9ZhLOGrXzIO1RqBd0QxbLrM0S/B2aOQ==} - engines: {node: '>=14.0.0'} + '@aws-sdk/middleware-expect-continue@3.598.0': + resolution: {integrity: sha512-ZuHW18kaeHR8TQyhEOYMr8VwiIh0bMvF7J1OTqXHxDteQIavJWA3CbfZ9sgS4XGtrBZDyHJhjZKeCfLhN2rq3w==} + engines: {node: '>=16.0.0'} - '@aws-sdk/middleware-sdk-s3@3.410.0': - resolution: {integrity: sha512-K2sG2V1ZkezYMCIy3uMt0MwtflcfIwLptwm0iFLaYitiINZQ1tcslk9ggAjyTHg0rslDSI4/zjkhy8VHFOV7HA==} - engines: {node: '>=14.0.0'} + '@aws-sdk/middleware-flexible-checksums@3.598.0': + resolution: {integrity: sha512-xukAzds0GQXvMEY9G6qt+CzwVzTx8NyKKh04O2Q+nOch6QQ8Rs+2kTRy3Z4wQmXq2pK9hlOWb5nXA7HWpmz6Ng==} + engines: {node: '>=16.0.0'} - '@aws-sdk/middleware-sdk-sts@3.410.0': - resolution: {integrity: sha512-YfBpctDocRR4CcROoDueJA7D+aMLBV8nTFfmVNdLLLgyuLZ/AUR11VQSu1lf9gQZKl8IpKE/BLf2fRE/qV1ZuA==} - engines: {node: '>=14.0.0'} + '@aws-sdk/middleware-host-header@3.598.0': + resolution: {integrity: sha512-WiaG059YBQwQraNejLIi0gMNkX7dfPZ8hDIhvMr5aVPRbaHH8AYF3iNSsXYCHvA2Cfa1O9haYXsuMF9flXnCmA==} + engines: {node: '>=16.0.0'} - '@aws-sdk/middleware-signing@3.410.0': - resolution: {integrity: sha512-KBAZ/eoAJUSJv5us2HsKwK2OszG2s9FEyKpEhgnHLcbbKzW873zHBH5GcOGEQu4AWArTy2ndzJu3FF+9/J9hJQ==} - engines: {node: '>=14.0.0'} + '@aws-sdk/middleware-location-constraint@3.598.0': + resolution: {integrity: sha512-8oybQxN3F1ISOMULk7JKJz5DuAm5hCUcxMW9noWShbxTJuStNvuHf/WLUzXrf8oSITyYzIHPtf8VPlKR7I3orQ==} + engines: {node: '>=16.0.0'} - '@aws-sdk/middleware-ssec@3.410.0': - resolution: {integrity: sha512-DNsjVTXoxIh+PuW9o45CFaMiconbuZRm19MC3NA1yNCaCj3ZxD5OdXAutq6UjQdrx8UG4EjUlCJEEvBKmboITw==} - engines: {node: '>=14.0.0'} + '@aws-sdk/middleware-logger@3.598.0': + resolution: {integrity: sha512-bxBjf/VYiu3zfu8SYM2S9dQQc3tz5uBAOcPz/Bt8DyyK3GgOpjhschH/2XuUErsoUO1gDJqZSdGOmuHGZQn00Q==} + engines: {node: '>=16.0.0'} - '@aws-sdk/middleware-user-agent@3.410.0': - resolution: {integrity: sha512-ZayDtLfvCZUohSxQc/49BfoU/y6bDHLfLdyyUJbJ54Sv8zQcrmdyKvCBFUZwE6tHQgAmv9/ZT18xECMl+xiONA==} - engines: {node: '>=14.0.0'} + '@aws-sdk/middleware-recursion-detection@3.598.0': + resolution: {integrity: sha512-vjT9BeFY9FeN0f8hm2l6F53tI0N5bUq6RcDkQXKNabXBnQxKptJRad6oP2X5y3FoVfBLOuDkQgiC2940GIPxtQ==} + engines: {node: '>=16.0.0'} - '@aws-sdk/signature-v4-multi-region@3.412.0': - resolution: {integrity: sha512-ijxOeYpNDuk2T940S9HYcZ1C+wTP9vqp1Cw37zw9whVY2mKV3Vr7i+44D4FQ5HhWULgdwhjD7IctbNxPIPzUZQ==} - engines: {node: '>=14.0.0'} + '@aws-sdk/middleware-sdk-s3@3.598.0': + resolution: {integrity: sha512-5AGtLAh9wyK6ANPYfaKTqJY1IFJyePIxsEbxa7zS6REheAqyVmgJFaGu3oQ5XlxfGr5Uq59tFTRkyx26G1HkHA==} + engines: {node: '>=16.0.0'} - '@aws-sdk/token-providers@3.410.0': - resolution: {integrity: sha512-d5Nc0xydkH/X0LA1HDyhGY5sEv4LuADFk+QpDtT8ogLilcre+b1jpdY8Sih/gd1KoGS1H+d1tz2hSGwUHAbUbw==} - engines: {node: '>=14.0.0'} + '@aws-sdk/middleware-signing@3.598.0': + resolution: {integrity: sha512-XKb05DYx/aBPqz6iCapsCbIl8aD8EihTuPCs51p75QsVfbQoVr4TlFfIl5AooMSITzojdAQqxt021YtvxjtxIQ==} + engines: {node: '>=16.0.0'} - '@aws-sdk/types@3.410.0': - resolution: {integrity: sha512-D7iaUCszv/v04NDaZUmCmekamy6VD/lKozm/3gS9+dkfU6cC2CsNoUfPV8BlV6dPdw0oWgF91am3I1stdvfVrQ==} - engines: {node: '>=14.0.0'} + '@aws-sdk/middleware-ssec@3.598.0': + resolution: {integrity: sha512-f0p2xP8IC1uJ5e/tND1l81QxRtRFywEdnbtKCE0H6RSn4UIt2W3Dohe1qQDbnh27okF0PkNW6BJGdSAz3p7qbA==} + engines: {node: '>=16.0.0'} - '@aws-sdk/types@3.413.0': - resolution: {integrity: sha512-j1xib0f/TazIFc5ySIKOlT1ujntRbaoG4LJFeEezz4ji03/wSJMI8Vi4KjzpBp8J1tTu0oRDnsxRIGixsUBeYQ==} - engines: {node: '>=14.0.0'} + '@aws-sdk/middleware-user-agent@3.598.0': + resolution: {integrity: sha512-4tjESlHG5B5MdjUaLK7tQs/miUtHbb6deauQx8ryqSBYOhfHVgb1ZnzvQR0bTrhpqUg0WlybSkDaZAICf9xctg==} + engines: {node: '>=16.0.0'} - '@aws-sdk/util-arn-parser@3.310.0': - resolution: {integrity: sha512-jL8509owp/xB9+Or0pvn3Fe+b94qfklc2yPowZZIFAkFcCSIdkIglz18cPDWnYAcy9JGewpMS1COXKIUhZkJsA==} - engines: {node: '>=14.0.0'} + '@aws-sdk/region-config-resolver@3.598.0': + resolution: {integrity: sha512-oYXhmTokSav4ytmWleCr3rs/1nyvZW/S0tdi6X7u+dLNL5Jee+uMxWGzgOrWK6wrQOzucLVjS4E/wA11Kv2GTw==} + engines: {node: '>=16.0.0'} - '@aws-sdk/util-endpoints@3.410.0': - resolution: {integrity: sha512-iNiqJyC7N3+8zFwnXUqcWSxrZecVZLToo1iTQQdeYL2af1IcOtRgb7n8jpAI/hmXhBSx2+3RI+Y7pxyFo1vu+w==} - engines: {node: '>=14.0.0'} + '@aws-sdk/signature-v4-multi-region@3.598.0': + resolution: {integrity: sha512-1r/EyTrO1gSa1FirnR8V7mabr7gk+l+HkyTI0fcTSr8ucB7gmYyW6WjkY8JCz13VYHFK62usCEDS7yoJoJOzTA==} + engines: {node: '>=16.0.0'} + + '@aws-sdk/token-providers@3.598.0': + resolution: {integrity: sha512-TKY1EVdHVBnZqpyxyTHdpZpa1tUpb6nxVeRNn1zWG8QB5MvH4ALLd/jR+gtmWDNQbIG4cVuBOZFVL8hIYicKTA==} + engines: {node: '>=16.0.0'} + peerDependencies: + '@aws-sdk/client-sso-oidc': ^3.598.0 + + '@aws-sdk/types@3.598.0': + resolution: {integrity: sha512-742uRl6z7u0LFmZwDrFP6r1wlZcgVPw+/TilluDJmCAR8BgRw3IR+743kUXKBGd8QZDRW2n6v/PYsi/AWCDDMQ==} + engines: {node: '>=16.0.0'} + + '@aws-sdk/util-arn-parser@3.568.0': + resolution: {integrity: sha512-XUKJWWo+KOB7fbnPP0+g/o5Ulku/X53t7i/h+sPHr5xxYTJJ9CYnbToo95mzxe7xWvkLrsNtJ8L+MnNn9INs2w==} + engines: {node: '>=16.0.0'} + + '@aws-sdk/util-endpoints@3.598.0': + resolution: {integrity: sha512-Qo9UoiVVZxcOEdiOMZg3xb1mzkTxrhd4qSlg5QQrfWPJVx/QOg+Iy0NtGxPtHtVZNHZxohYwDwV/tfsnDSE2gQ==} + engines: {node: '>=16.0.0'} '@aws-sdk/util-locate-window@3.208.0': resolution: {integrity: sha512-iua1A2+P7JJEDHVgvXrRJSvsnzG7stYSGQnBVphIUlemwl6nN5D+QrgbjECtrbxRz8asYFHSzhdhECqN+tFiBg==} engines: {node: '>=14.0.0'} - '@aws-sdk/util-user-agent-browser@3.410.0': - resolution: {integrity: sha512-i1G/XGpXGMRT2zEiAhi1xucJsfCWk8nNYjk/LbC0sA+7B9Huri96YAzVib12wkHPsJQvZxZC6CpQDIHWm4lXMA==} + '@aws-sdk/util-user-agent-browser@3.598.0': + resolution: {integrity: sha512-36Sxo6F+ykElaL1mWzWjlg+1epMpSe8obwhCN1yGE7Js9ywy5U6k6l+A3q3YM9YRbm740sNxncbwLklMvuhTKw==} - '@aws-sdk/util-user-agent-node@3.410.0': - resolution: {integrity: sha512-bK70t1jHRl8HrJXd4hEIwc5PBZ7U0w+81AKFnanIVKZwZedd6nLibUXDTK14z/Jp2GFcBqd4zkt2YLGkRt/U4A==} - engines: {node: '>=14.0.0'} + '@aws-sdk/util-user-agent-node@3.598.0': + resolution: {integrity: sha512-oyWGcOlfTdzkC6SVplyr0AGh54IMrDxbhg5RxJ5P+V4BKfcDoDcZV9xenUk9NsOi9MuUjxMumb9UJGkDhM1m0A==} + engines: {node: '>=16.0.0'} peerDependencies: aws-crt: '>=1.0.0' peerDependenciesMeta: aws-crt: optional: true - '@aws-sdk/util-utf8-browser@3.259.0': - resolution: {integrity: sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==} - - '@aws-sdk/xml-builder@3.310.0': - resolution: {integrity: sha512-TqELu4mOuSIKQCqj63fGVs86Yh+vBx5nHRpWKNUNhB2nPTpfbziTs5c1X358be3peVWA4wPxW7Nt53KIg1tnNw==} - engines: {node: '>=14.0.0'} + '@aws-sdk/xml-builder@3.598.0': + resolution: {integrity: sha512-ZIa2RK7CHFTZ4gwK77WRtsZ6vF7xwRXxJ8KQIxK2duhoTVcn0xYxpFLdW9WZZZvdP9GIF3Loqvf8DRdeU5Jc7Q==} + engines: {node: '>=16.0.0'} '@babel/code-frame@7.23.5': resolution: {integrity: sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==} engines: {node: '>=6.9.0'} + '@babel/code-frame@7.24.7': + resolution: {integrity: sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==} + engines: {node: '>=6.9.0'} + '@babel/compat-data@7.23.5': resolution: {integrity: sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==} engines: {node: '>=6.9.0'} + '@babel/compat-data@7.24.7': + resolution: {integrity: sha512-qJzAIcv03PyaWqxRgO4mSU3lihncDT296vnyuE2O8uA4w3UHWI4S3hgeZd1L8W1Bft40w9JxJ2b412iDUFFRhw==} + engines: {node: '>=6.9.0'} + '@babel/core@7.23.5': resolution: {integrity: sha512-Cwc2XjUrG4ilcfOw4wBAK+enbdgwAcAJCfGUItPBKR7Mjw4aEfAFYrLxeRp4jWgtNIKn3n2AlBOfwwafl+42/g==} engines: {node: '>=6.9.0'} - '@babel/core@7.24.0': - resolution: {integrity: sha512-fQfkg0Gjkza3nf0c7/w6Xf34BW4YvzNfACRLmmb7XRLa6XHdR+K9AlJlxneFfWYf6uhOzuzZVTjF/8KfndZANw==} + '@babel/core@7.24.7': + resolution: {integrity: sha512-nykK+LEK86ahTkX/3TgauT0ikKoNCfKHEaZYTUVupJdTLzGNvrblu4u6fa7DhZONAltdf8e662t/abY8idrd/g==} engines: {node: '>=6.9.0'} '@babel/generator@7.23.5': resolution: {integrity: sha512-BPssCHrBD+0YrxviOa3QzpqwhNIXKEtOa2jQrm4FlmkC2apYgRnQcmPWiGZDlGxiNtltnUFolMe8497Esry+jA==} engines: {node: '>=6.9.0'} - '@babel/generator@7.23.6': - resolution: {integrity: sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==} + '@babel/generator@7.24.7': + resolution: {integrity: sha512-oipXieGC3i45Y1A41t4tAqpnEZWgB/lC6Ehh6+rOviR5XWpTtMmLN+fGjz9vOiNRt0p6RtO6DtD0pdU3vpqdSA==} engines: {node: '>=6.9.0'} - '@babel/helper-annotate-as-pure@7.22.5': - resolution: {integrity: sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==} + '@babel/helper-annotate-as-pure@7.24.7': + resolution: {integrity: sha512-BaDeOonYvhdKw+JoMVkAixAAJzG2jVPIwWoKBPdYuY9b452e2rPuI9QPYh3KpofZ3pW2akOmwZLOiOsHMiqRAg==} engines: {node: '>=6.9.0'} - '@babel/helper-builder-binary-assignment-operator-visitor@7.22.15': - resolution: {integrity: sha512-QkBXwGgaoC2GtGZRoma6kv7Szfv06khvhFav67ZExau2RaXzy8MpHSMO2PNoP2XtmQphJQRHFfg77Bq731Yizw==} + '@babel/helper-builder-binary-assignment-operator-visitor@7.24.7': + resolution: {integrity: sha512-xZeCVVdwb4MsDBkkyZ64tReWYrLRHlMN72vP7Bdm3OUOuyFZExhsHUUnuWnm2/XOlAJzR0LfPpB56WXZn0X/lA==} engines: {node: '>=6.9.0'} '@babel/helper-compilation-targets@7.22.15': resolution: {integrity: sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==} engines: {node: '>=6.9.0'} - '@babel/helper-compilation-targets@7.23.6': - resolution: {integrity: sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==} + '@babel/helper-compilation-targets@7.24.7': + resolution: {integrity: sha512-ctSdRHBi20qWOfy27RUb4Fhp07KSJ3sXcuSvTrXrc4aG8NSYDo1ici3Vhg9bg69y5bj0Mr1lh0aeEgTvc12rMg==} engines: {node: '>=6.9.0'} - '@babel/helper-create-class-features-plugin@7.23.5': - resolution: {integrity: sha512-QELlRWxSpgdwdJzSJn4WAhKC+hvw/AtHbbrIoncKHkhKKR/luAlKkgBDcri1EzWAo8f8VvYVryEHN4tax/V67A==} + '@babel/helper-create-class-features-plugin@7.24.7': + resolution: {integrity: sha512-kTkaDl7c9vO80zeX1rJxnuRpEsD5tA81yh11X1gQo+PhSti3JS+7qeZo9U4RHobKRiFPKaGK3svUAeb8D0Q7eg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/helper-create-regexp-features-plugin@7.22.15': - resolution: {integrity: sha512-29FkPLFjn4TPEa3RE7GpW+qbE8tlsu3jntNYNfcGsc49LphF1PQIiD+vMZ1z1xVOKt+93khA9tc2JBs3kBjA7w==} + '@babel/helper-create-regexp-features-plugin@7.24.7': + resolution: {integrity: sha512-03TCmXy2FtXJEZfbXDTSqq1fRJArk7lX9DOFC/47VthYcxyIOx+eXQmdo6DOQvrbpIix+KfXwvuXdFDZHxt+rA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/helper-define-polyfill-provider@0.4.3': - resolution: {integrity: sha512-WBrLmuPP47n7PNwsZ57pqam6G/RGo1vw/87b0Blc53tZNGZ4x7YvZ6HgQe2vo1W/FR20OgjeZuGXzudPiXHFug==} + '@babel/helper-define-polyfill-provider@0.6.2': + resolution: {integrity: sha512-LV76g+C502biUK6AyZ3LK10vDpDyCzZnhZFXkH1L75zHPj68+qc8Zfpx2th+gzwA2MzyK+1g/3EPl62yFnVttQ==} peerDependencies: '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 @@ -1521,44 +1506,70 @@ packages: resolution: {integrity: sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==} engines: {node: '>=6.9.0'} + '@babel/helper-environment-visitor@7.24.7': + resolution: {integrity: sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==} + engines: {node: '>=6.9.0'} + '@babel/helper-function-name@7.23.0': resolution: {integrity: sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==} engines: {node: '>=6.9.0'} + '@babel/helper-function-name@7.24.7': + resolution: {integrity: sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==} + engines: {node: '>=6.9.0'} + '@babel/helper-hoist-variables@7.22.5': resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==} engines: {node: '>=6.9.0'} - '@babel/helper-member-expression-to-functions@7.23.0': - resolution: {integrity: sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==} + '@babel/helper-hoist-variables@7.24.7': + resolution: {integrity: sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-member-expression-to-functions@7.24.7': + resolution: {integrity: sha512-LGeMaf5JN4hAT471eJdBs/GK1DoYIJ5GCtZN/EsL6KUiiDZOvO/eKE11AMZJa2zP4zk4qe9V2O/hxAmkRc8p6w==} engines: {node: '>=6.9.0'} '@babel/helper-module-imports@7.22.15': resolution: {integrity: sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==} engines: {node: '>=6.9.0'} + '@babel/helper-module-imports@7.24.7': + resolution: {integrity: sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==} + engines: {node: '>=6.9.0'} + '@babel/helper-module-transforms@7.23.3': resolution: {integrity: sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/helper-optimise-call-expression@7.22.5': - resolution: {integrity: sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==} + '@babel/helper-module-transforms@7.24.7': + resolution: {integrity: sha512-1fuJEwIrp+97rM4RWdO+qrRsZlAeL1lQJoPqtCYWv0NL115XM93hIH4CSRln2w52SqvmY5hqdtauB6QFCDiZNQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-optimise-call-expression@7.24.7': + resolution: {integrity: sha512-jKiTsW2xmWwxT1ixIdfXUZp+P5yURx2suzLZr5Hi64rURpDYdMW0pv+Uf17EYk2Rd428Lx4tLsnjGJzYKDM/6A==} engines: {node: '>=6.9.0'} '@babel/helper-plugin-utils@7.22.5': resolution: {integrity: sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==} engines: {node: '>=6.9.0'} - '@babel/helper-remap-async-to-generator@7.22.20': - resolution: {integrity: sha512-pBGyV4uBqOns+0UvhsTO8qgl8hO89PmiDYv+/COyp1aeMcmfrfruz+/nCMFiYyFF/Knn0yfrC85ZzNFjembFTw==} + '@babel/helper-plugin-utils@7.24.7': + resolution: {integrity: sha512-Rq76wjt7yz9AAc1KnlRKNAi/dMSVWgDRx43FHoJEbcYU6xOWaE2dVPwcdTukJrjxS65GITyfbvEYHvkirZ6uEg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-remap-async-to-generator@7.24.7': + resolution: {integrity: sha512-9pKLcTlZ92hNZMQfGCHImUpDOlAgkkpqalWEeftW5FBya75k8Li2ilerxkM/uBEj01iBZXcCIB/bwvDYgWyibA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/helper-replace-supers@7.22.20': - resolution: {integrity: sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw==} + '@babel/helper-replace-supers@7.24.7': + resolution: {integrity: sha512-qTAxxBM81VEyoAY0TtLrx1oAEJc09ZK67Q9ljQToqCnA+55eNwCORaxlKyu+rNfX86o8OXRUSNUnrtsAZXM9sg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 @@ -1567,71 +1578,101 @@ packages: resolution: {integrity: sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==} engines: {node: '>=6.9.0'} - '@babel/helper-skip-transparent-expression-wrappers@7.22.5': - resolution: {integrity: sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==} + '@babel/helper-simple-access@7.24.7': + resolution: {integrity: sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-skip-transparent-expression-wrappers@7.24.7': + resolution: {integrity: sha512-IO+DLT3LQUElMbpzlatRASEyQtfhSE0+m465v++3jyyXeBTBUjtVZg28/gHeV5mrTJqvEKhKroBGAvhW+qPHiQ==} engines: {node: '>=6.9.0'} '@babel/helper-split-export-declaration@7.22.6': resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==} engines: {node: '>=6.9.0'} + '@babel/helper-split-export-declaration@7.24.7': + resolution: {integrity: sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==} + engines: {node: '>=6.9.0'} + '@babel/helper-string-parser@7.23.4': resolution: {integrity: sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==} engines: {node: '>=6.9.0'} + '@babel/helper-string-parser@7.24.7': + resolution: {integrity: sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg==} + engines: {node: '>=6.9.0'} + '@babel/helper-validator-identifier@7.22.20': resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==} engines: {node: '>=6.9.0'} + '@babel/helper-validator-identifier@7.24.7': + resolution: {integrity: sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==} + engines: {node: '>=6.9.0'} + '@babel/helper-validator-option@7.23.5': resolution: {integrity: sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==} engines: {node: '>=6.9.0'} - '@babel/helper-wrap-function@7.22.20': - resolution: {integrity: sha512-pms/UwkOpnQe/PDAEdV/d7dVCoBbB+R4FvYoHGZz+4VPcg7RtYy2KP7S2lbuWM6FCSgob5wshfGESbC/hzNXZw==} + '@babel/helper-validator-option@7.24.7': + resolution: {integrity: sha512-yy1/KvjhV/ZCL+SM7hBrvnZJ3ZuT9OuZgIJAGpPEToANvc3iM6iDvBnRjtElWibHU6n8/LPR/EjX9EtIEYO3pw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-wrap-function@7.24.7': + resolution: {integrity: sha512-N9JIYk3TD+1vq/wn77YnJOqMtfWhNewNE+DJV4puD2X7Ew9J4JvrzrFDfTfyv5EgEXVy9/Wt8QiOErzEmv5Ifw==} engines: {node: '>=6.9.0'} '@babel/helpers@7.23.5': resolution: {integrity: sha512-oO7us8FzTEsG3U6ag9MfdF1iA/7Z6dz+MtFhifZk8C8o453rGJFFWUP1t+ULM9TUIAzC9uxXEiXjOiVMyd7QPg==} engines: {node: '>=6.9.0'} - '@babel/helpers@7.24.0': - resolution: {integrity: sha512-ulDZdc0Aj5uLc5nETsa7EPx2L7rM0YJM8r7ck7U73AXi7qOV44IHHRAYZHY6iU1rr3C5N4NtTmMRUJP6kwCWeA==} + '@babel/helpers@7.24.7': + resolution: {integrity: sha512-NlmJJtvcw72yRJRcnCmGvSi+3jDEg8qFu3z0AFoymmzLx5ERVWyzd9kVXr7Th9/8yIJi2Zc6av4Tqz3wFs8QWg==} engines: {node: '>=6.9.0'} '@babel/highlight@7.23.4': resolution: {integrity: sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==} engines: {node: '>=6.9.0'} + '@babel/highlight@7.24.7': + resolution: {integrity: sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==} + engines: {node: '>=6.9.0'} + '@babel/parser@7.23.9': resolution: {integrity: sha512-9tcKgqKbs3xGJ+NtKF2ndOBBLVwPjl1SHxPQkd36r3Dlirw3xWUeGaTbqr7uGZcTaxkVNwc+03SVP7aCdWrTlA==} engines: {node: '>=6.0.0'} hasBin: true - '@babel/parser@7.24.0': - resolution: {integrity: sha512-QuP/FxEAzMSjXygs8v4N9dvdXzEHN4W1oF3PxuWAtPo08UdM17u89RDMgjLn/mlc56iM0HlLmVkO/wgR+rDgHg==} - engines: {node: '>=6.0.0'} - hasBin: true - '@babel/parser@7.24.5': resolution: {integrity: sha512-EOv5IK8arwh3LI47dz1b0tKUb/1uhHAnHJOrjgtQMIpu1uXd9mlFrJg9IUgGUgZ41Ch0K8REPTYpO7B76b4vJg==} engines: {node: '>=6.0.0'} hasBin: true - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.23.3': - resolution: {integrity: sha512-iRkKcCqb7iGnq9+3G6rZ+Ciz5VywC4XNRHe57lKM+jOeYAoR0lVqdeeDRfh0tQcTfw/+vBhHn926FmQhLtlFLQ==} + '@babel/parser@7.24.7': + resolution: {integrity: sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.24.7': + resolution: {integrity: sha512-TiT1ss81W80eQsN+722OaeQMY/G4yTb4G9JrqeiDADs3N8lbPMGldWi9x8tyqCW5NLx1Jh2AvkE6r6QvEltMMQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.23.3': - resolution: {integrity: sha512-WwlxbfMNdVEpQjZmK5mhm7oSwD3dS6eU+Iwsi4Knl9wAletWem7kaRsGOG+8UEbRyqxY4SS5zvtfXwX+jMxUwQ==} + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.24.7': + resolution: {integrity: sha512-unaQgZ/iRu/By6tsjMZzpeBZjChYfLYry6HrEXPoz3KmfF0sVBQ1l8zKMQ4xRGLWVsjuvB8nQfjNP/DcfEOCsg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.24.7': + resolution: {integrity: sha512-+izXIbke1T33mY4MSNnrqhPXDz01WYhEf3yF5NbnUtkiNnm+XBZJl3kNfoK6NKmYlz/D07+l2GWVK/QfDkNCuQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.13.0 - '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.23.3': - resolution: {integrity: sha512-XaJak1qcityzrX0/IU5nKHb34VaibwP3saKqG6a/tppelgllOH13LUann4ZCIBcVOeE6H18K4Vx9QKkVww3z/w==} + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.24.7': + resolution: {integrity: sha512-utA4HuR6F4Vvcr+o4DnjL8fCOlgRFGbeeBEGNg3ZTrLFw6VWG5XmUrvcQ0FjIYMU2ST4XcR2Wsp7t9qOAPnxMg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 @@ -1679,14 +1720,14 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-import-assertions@7.23.3': - resolution: {integrity: sha512-lPgDSU+SJLK3xmFDTV2ZRQAiM7UuUjGidwBywFavObCiZc1BeAAcMtHJKUya92hPHO+at63JJPLygilZard8jw==} + '@babel/plugin-syntax-import-assertions@7.24.7': + resolution: {integrity: sha512-Ec3NRUMoi8gskrkBe3fNmEQfxDvY8bgfQpz6jlk/41kX9eUjvpyqWU7PBP/pLAvMaSQjbMNKJmvX57jP+M6bPg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-import-attributes@7.23.3': - resolution: {integrity: sha512-pawnE0P9g10xgoP7yKr6CK63K2FMsTE+FZidZO/1PwRdzmAPVs+HS1mAURUsgaoxammTJvULUdIkEK0gOcU2tA==} + '@babel/plugin-syntax-import-attributes@7.24.7': + resolution: {integrity: sha512-hbX+lKKeUMGihnK8nvKqmXBInriT3GVjzXKFriV3YC6APGxMbP8RZNFwy91+hocLXq90Mta+HshoB31802bb8A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1761,92 +1802,92 @@ packages: peerDependencies: '@babel/core': ^7.0.0 - '@babel/plugin-transform-arrow-functions@7.23.3': - resolution: {integrity: sha512-NzQcQrzaQPkaEwoTm4Mhyl8jI1huEL/WWIEvudjTCMJ9aBZNpsJbMASx7EQECtQQPS/DcnFpo0FIh3LvEO9cxQ==} + '@babel/plugin-transform-arrow-functions@7.24.7': + resolution: {integrity: sha512-Dt9LQs6iEY++gXUwY03DNFat5C2NbO48jj+j/bSAz6b3HgPs39qcPiYt77fDObIcFwj3/C2ICX9YMwGflUoSHQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-async-generator-functions@7.23.4': - resolution: {integrity: sha512-efdkfPhHYTtn0G6n2ddrESE91fgXxjlqLsnUtPWnJs4a4mZIbUaK7ffqKIIUKXSHwcDvaCVX6GXkaJJFqtX7jw==} + '@babel/plugin-transform-async-generator-functions@7.24.7': + resolution: {integrity: sha512-o+iF77e3u7ZS4AoAuJvapz9Fm001PuD2V3Lp6OSE4FYQke+cSewYtnek+THqGRWyQloRCyvWL1OkyfNEl9vr/g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-async-to-generator@7.23.3': - resolution: {integrity: sha512-A7LFsKi4U4fomjqXJlZg/u0ft/n8/7n7lpffUP/ZULx/DtV9SGlNKZolHH6PE8Xl1ngCc0M11OaeZptXVkfKSw==} + '@babel/plugin-transform-async-to-generator@7.24.7': + resolution: {integrity: sha512-SQY01PcJfmQ+4Ash7NE+rpbLFbmqA2GPIgqzxfFTL4t1FKRq4zTms/7htKpoCUI9OcFYgzqfmCdH53s6/jn5fA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-block-scoped-functions@7.23.3': - resolution: {integrity: sha512-vI+0sIaPIO6CNuM9Kk5VmXcMVRiOpDh7w2zZt9GXzmE/9KD70CUEVhvPR/etAeNK/FAEkhxQtXOzVF3EuRL41A==} + '@babel/plugin-transform-block-scoped-functions@7.24.7': + resolution: {integrity: sha512-yO7RAz6EsVQDaBH18IDJcMB1HnrUn2FJ/Jslc/WtPPWcjhpUJXU/rjbwmluzp7v/ZzWcEhTMXELnnsz8djWDwQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-block-scoping@7.23.4': - resolution: {integrity: sha512-0QqbP6B6HOh7/8iNR4CQU2Th/bbRtBp4KS9vcaZd1fZ0wSh5Fyssg0UCIHwxh+ka+pNDREbVLQnHCMHKZfPwfw==} + '@babel/plugin-transform-block-scoping@7.24.7': + resolution: {integrity: sha512-Nd5CvgMbWc+oWzBsuaMcbwjJWAcp5qzrbg69SZdHSP7AMY0AbWFqFO0WTFCA1jxhMCwodRwvRec8k0QUbZk7RQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-class-properties@7.23.3': - resolution: {integrity: sha512-uM+AN8yCIjDPccsKGlw271xjJtGii+xQIF/uMPS8H15L12jZTsLfF4o5vNO7d/oUguOyfdikHGc/yi9ge4SGIg==} + '@babel/plugin-transform-class-properties@7.24.7': + resolution: {integrity: sha512-vKbfawVYayKcSeSR5YYzzyXvsDFWU2mD8U5TFeXtbCPLFUqe7GyCgvO6XDHzje862ODrOwy6WCPmKeWHbCFJ4w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-class-static-block@7.23.4': - resolution: {integrity: sha512-nsWu/1M+ggti1SOALj3hfx5FXzAY06fwPJsUZD4/A5e1bWi46VUIWtD+kOX6/IdhXGsXBWllLFDSnqSCdUNydQ==} + '@babel/plugin-transform-class-static-block@7.24.7': + resolution: {integrity: sha512-HMXK3WbBPpZQufbMG4B46A90PkuuhN9vBCb5T8+VAHqvAqvcLi+2cKoukcpmUYkszLhScU3l1iudhrks3DggRQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.12.0 - '@babel/plugin-transform-classes@7.23.5': - resolution: {integrity: sha512-jvOTR4nicqYC9yzOHIhXG5emiFEOpappSJAl73SDSEDcybD+Puuze8Tnpb9p9qEyYup24tq891gkaygIFvWDqg==} + '@babel/plugin-transform-classes@7.24.7': + resolution: {integrity: sha512-CFbbBigp8ln4FU6Bpy6g7sE8B/WmCmzvivzUC6xDAdWVsjYTXijpuuGJmYkAaoWAzcItGKT3IOAbxRItZ5HTjw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-computed-properties@7.23.3': - resolution: {integrity: sha512-dTj83UVTLw/+nbiHqQSFdwO9CbTtwq1DsDqm3CUEtDrZNET5rT5E6bIdTlOftDTDLMYxvxHNEYO4B9SLl8SLZw==} + '@babel/plugin-transform-computed-properties@7.24.7': + resolution: {integrity: sha512-25cS7v+707Gu6Ds2oY6tCkUwsJ9YIDbggd9+cu9jzzDgiNq7hR/8dkzxWfKWnTic26vsI3EsCXNd4iEB6e8esQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-destructuring@7.23.3': - resolution: {integrity: sha512-n225npDqjDIr967cMScVKHXJs7rout1q+tt50inyBCPkyZ8KxeI6d+GIbSBTT/w/9WdlWDOej3V9HE5Lgk57gw==} + '@babel/plugin-transform-destructuring@7.24.7': + resolution: {integrity: sha512-19eJO/8kdCQ9zISOf+SEUJM/bAUIsvY3YDnXZTupUCQ8LgrWnsG/gFB9dvXqdXnRXMAM8fvt7b0CBKQHNGy1mw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-dotall-regex@7.23.3': - resolution: {integrity: sha512-vgnFYDHAKzFaTVp+mneDsIEbnJ2Np/9ng9iviHw3P/KVcgONxpNULEW/51Z/BaFojG2GI2GwwXck5uV1+1NOYQ==} + '@babel/plugin-transform-dotall-regex@7.24.7': + resolution: {integrity: sha512-ZOA3W+1RRTSWvyqcMJDLqbchh7U4NRGqwRfFSVbOLS/ePIP4vHB5e8T8eXcuqyN1QkgKyj5wuW0lcS85v4CrSw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-duplicate-keys@7.23.3': - resolution: {integrity: sha512-RrqQ+BQmU3Oyav3J+7/myfvRCq7Tbz+kKLLshUmMwNlDHExbGL7ARhajvoBJEvc+fCguPPu887N+3RRXBVKZUA==} + '@babel/plugin-transform-duplicate-keys@7.24.7': + resolution: {integrity: sha512-JdYfXyCRihAe46jUIliuL2/s0x0wObgwwiGxw/UbgJBr20gQBThrokO4nYKgWkD7uBaqM7+9x5TU7NkExZJyzw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-dynamic-import@7.23.4': - resolution: {integrity: sha512-V6jIbLhdJK86MaLh4Jpghi8ho5fGzt3imHOBu/x0jlBaPYqDoWz4RDXjmMOfnh+JWNaQleEAByZLV0QzBT4YQQ==} + '@babel/plugin-transform-dynamic-import@7.24.7': + resolution: {integrity: sha512-sc3X26PhZQDb3JhORmakcbvkeInvxz+A8oda99lj7J60QRuPZvNAk9wQlTBS1ZynelDrDmTU4pw1tyc5d5ZMUg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-exponentiation-operator@7.23.3': - resolution: {integrity: sha512-5fhCsl1odX96u7ILKHBj4/Y8vipoqwsJMh4csSA8qFfxrZDEA4Ssku2DyNvMJSmZNOEBT750LfFPbtrnTP90BQ==} + '@babel/plugin-transform-exponentiation-operator@7.24.7': + resolution: {integrity: sha512-Rqe/vSc9OYgDajNIK35u7ot+KeCoetqQYFXM4Epf7M7ez3lWlOjrDjrwMei6caCVhfdw+mIKD4cgdGNy5JQotQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-export-namespace-from@7.23.4': - resolution: {integrity: sha512-GzuSBcKkx62dGzZI1WVgTWvkkz84FZO5TC5T8dl/Tht/rAla6Dg/Mz9Yhypg+ezVACf/rgDuQt3kbWEv7LdUDQ==} + '@babel/plugin-transform-export-namespace-from@7.24.7': + resolution: {integrity: sha512-v0K9uNYsPL3oXZ/7F9NNIbAj2jv1whUEtyA6aujhekLs56R++JDQuzRcP2/z4WX5Vg/c5lE9uWZA0/iUoFhLTA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1857,176 +1898,176 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-for-of@7.23.3': - resolution: {integrity: sha512-X8jSm8X1CMwxmK878qsUGJRmbysKNbdpTv/O1/v0LuY/ZkZrng5WYiekYSdg9m09OTmDDUWeEDsTE+17WYbAZw==} + '@babel/plugin-transform-for-of@7.24.7': + resolution: {integrity: sha512-wo9ogrDG1ITTTBsy46oGiN1dS9A7MROBTcYsfS8DtsImMkHk9JXJ3EWQM6X2SUw4x80uGPlwj0o00Uoc6nEE3g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-function-name@7.23.3': - resolution: {integrity: sha512-I1QXp1LxIvt8yLaib49dRW5Okt7Q4oaxao6tFVKS/anCdEOMtYwWVKoiOA1p34GOWIZjUK0E+zCp7+l1pfQyiw==} + '@babel/plugin-transform-function-name@7.24.7': + resolution: {integrity: sha512-U9FcnA821YoILngSmYkW6FjyQe2TyZD5pHt4EVIhmcTkrJw/3KqcrRSxuOo5tFZJi7TE19iDyI1u+weTI7bn2w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-json-strings@7.23.4': - resolution: {integrity: sha512-81nTOqM1dMwZ/aRXQ59zVubN9wHGqk6UtqRK+/q+ciXmRy8fSolhGVvG09HHRGo4l6fr/c4ZhXUQH0uFW7PZbg==} + '@babel/plugin-transform-json-strings@7.24.7': + resolution: {integrity: sha512-2yFnBGDvRuxAaE/f0vfBKvtnvvqU8tGpMHqMNpTN2oWMKIR3NqFkjaAgGwawhqK/pIN2T3XdjGPdaG0vDhOBGw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-literals@7.23.3': - resolution: {integrity: sha512-wZ0PIXRxnwZvl9AYpqNUxpZ5BiTGrYt7kueGQ+N5FiQ7RCOD4cm8iShd6S6ggfVIWaJf2EMk8eRzAh52RfP4rQ==} + '@babel/plugin-transform-literals@7.24.7': + resolution: {integrity: sha512-vcwCbb4HDH+hWi8Pqenwnjy+UiklO4Kt1vfspcQYFhJdpthSnW8XvWGyDZWKNVrVbVViI/S7K9PDJZiUmP2fYQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-logical-assignment-operators@7.23.4': - resolution: {integrity: sha512-Mc/ALf1rmZTP4JKKEhUwiORU+vcfarFVLfcFiolKUo6sewoxSEgl36ak5t+4WamRsNr6nzjZXQjM35WsU+9vbg==} + '@babel/plugin-transform-logical-assignment-operators@7.24.7': + resolution: {integrity: sha512-4D2tpwlQ1odXmTEIFWy9ELJcZHqrStlzK/dAOWYyxX3zT0iXQB6banjgeOJQXzEc4S0E0a5A+hahxPaEFYftsw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-member-expression-literals@7.23.3': - resolution: {integrity: sha512-sC3LdDBDi5x96LA+Ytekz2ZPk8i/Ck+DEuDbRAll5rknJ5XRTSaPKEYwomLcs1AA8wg9b3KjIQRsnApj+q51Ag==} + '@babel/plugin-transform-member-expression-literals@7.24.7': + resolution: {integrity: sha512-T/hRC1uqrzXMKLQ6UCwMT85S3EvqaBXDGf0FaMf4446Qx9vKwlghvee0+uuZcDUCZU5RuNi4781UQ7R308zzBw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-modules-amd@7.23.3': - resolution: {integrity: sha512-vJYQGxeKM4t8hYCKVBlZX/gtIY2I7mRGFNcm85sgXGMTBcoV3QdVtdpbcWEbzbfUIUZKwvgFT82mRvaQIebZzw==} + '@babel/plugin-transform-modules-amd@7.24.7': + resolution: {integrity: sha512-9+pB1qxV3vs/8Hdmz/CulFB8w2tuu6EB94JZFsjdqxQokwGa9Unap7Bo2gGBGIvPmDIVvQrom7r5m/TCDMURhg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-modules-commonjs@7.23.3': - resolution: {integrity: sha512-aVS0F65LKsdNOtcz6FRCpE4OgsP2OFnW46qNxNIX9h3wuzaNcSQsJysuMwqSibC98HPrf2vCgtxKNwS0DAlgcA==} + '@babel/plugin-transform-modules-commonjs@7.24.7': + resolution: {integrity: sha512-iFI8GDxtevHJ/Z22J5xQpVqFLlMNstcLXh994xifFwxxGslr2ZXXLWgtBeLctOD63UFDArdvN6Tg8RFw+aEmjQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-modules-systemjs@7.23.3': - resolution: {integrity: sha512-ZxyKGTkF9xT9YJuKQRo19ewf3pXpopuYQd8cDXqNzc3mUNbOME0RKMoZxviQk74hwzfQsEe66dE92MaZbdHKNQ==} + '@babel/plugin-transform-modules-systemjs@7.24.7': + resolution: {integrity: sha512-GYQE0tW7YoaN13qFh3O1NCY4MPkUiAH3fiF7UcV/I3ajmDKEdG3l+UOcbAm4zUE3gnvUU+Eni7XrVKo9eO9auw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-modules-umd@7.23.3': - resolution: {integrity: sha512-zHsy9iXX2nIsCBFPud3jKn1IRPWg3Ing1qOZgeKV39m1ZgIdpJqvlWVeiHBZC6ITRG0MfskhYe9cLgntfSFPIg==} + '@babel/plugin-transform-modules-umd@7.24.7': + resolution: {integrity: sha512-3aytQvqJ/h9z4g8AsKPLvD4Zqi2qT+L3j7XoFFu1XBlZWEl2/1kWnhmAbxpLgPrHSY0M6UA02jyTiwUVtiKR6A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-named-capturing-groups-regex@7.22.5': - resolution: {integrity: sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ==} + '@babel/plugin-transform-named-capturing-groups-regex@7.24.7': + resolution: {integrity: sha512-/jr7h/EWeJtk1U/uz2jlsCioHkZk1JJZVcc8oQsJ1dUlaJD83f4/6Zeh2aHt9BIFokHIsSeDfhUmju0+1GPd6g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/plugin-transform-new-target@7.23.3': - resolution: {integrity: sha512-YJ3xKqtJMAT5/TIZnpAR3I+K+WaDowYbN3xyxI8zxx/Gsypwf9B9h0VB+1Nh6ACAAPRS5NSRje0uVv5i79HYGQ==} + '@babel/plugin-transform-new-target@7.24.7': + resolution: {integrity: sha512-RNKwfRIXg4Ls/8mMTza5oPF5RkOW8Wy/WgMAp1/F1yZ8mMbtwXW+HDoJiOsagWrAhI5f57Vncrmr9XeT4CVapA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-nullish-coalescing-operator@7.23.4': - resolution: {integrity: sha512-jHE9EVVqHKAQx+VePv5LLGHjmHSJR76vawFPTdlxR/LVJPfOEGxREQwQfjuZEOPTwG92X3LINSh3M40Rv4zpVA==} + '@babel/plugin-transform-nullish-coalescing-operator@7.24.7': + resolution: {integrity: sha512-Ts7xQVk1OEocqzm8rHMXHlxvsfZ0cEF2yomUqpKENHWMF4zKk175Y4q8H5knJes6PgYad50uuRmt3UJuhBw8pQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-numeric-separator@7.23.4': - resolution: {integrity: sha512-mps6auzgwjRrwKEZA05cOwuDc9FAzoyFS4ZsG/8F43bTLf/TgkJg7QXOrPO1JO599iA3qgK9MXdMGOEC8O1h6Q==} + '@babel/plugin-transform-numeric-separator@7.24.7': + resolution: {integrity: sha512-e6q1TiVUzvH9KRvicuxdBTUj4AdKSRwzIyFFnfnezpCfP2/7Qmbb8qbU2j7GODbl4JMkblitCQjKYUaX/qkkwA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-object-rest-spread@7.23.4': - resolution: {integrity: sha512-9x9K1YyeQVw0iOXJlIzwm8ltobIIv7j2iLyP2jIhEbqPRQ7ScNgwQufU2I0Gq11VjyG4gI4yMXt2VFags+1N3g==} + '@babel/plugin-transform-object-rest-spread@7.24.7': + resolution: {integrity: sha512-4QrHAr0aXQCEFni2q4DqKLD31n2DL+RxcwnNjDFkSG0eNQ/xCavnRkfCUjsyqGC2OviNJvZOF/mQqZBw7i2C5Q==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-object-super@7.23.3': - resolution: {integrity: sha512-BwQ8q0x2JG+3lxCVFohg+KbQM7plfpBwThdW9A6TMtWwLsbDA01Ek2Zb/AgDN39BiZsExm4qrXxjk+P1/fzGrA==} + '@babel/plugin-transform-object-super@7.24.7': + resolution: {integrity: sha512-A/vVLwN6lBrMFmMDmPPz0jnE6ZGx7Jq7d6sT/Ev4H65RER6pZ+kczlf1DthF5N0qaPHBsI7UXiE8Zy66nmAovg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-optional-catch-binding@7.23.4': - resolution: {integrity: sha512-XIq8t0rJPHf6Wvmbn9nFxU6ao4c7WhghTR5WyV8SrJfUFzyxhCm4nhC+iAp3HFhbAKLfYpgzhJ6t4XCtVwqO5A==} + '@babel/plugin-transform-optional-catch-binding@7.24.7': + resolution: {integrity: sha512-uLEndKqP5BfBbC/5jTwPxLh9kqPWWgzN/f8w6UwAIirAEqiIVJWWY312X72Eub09g5KF9+Zn7+hT7sDxmhRuKA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-optional-chaining@7.23.4': - resolution: {integrity: sha512-ZU8y5zWOfjM5vZ+asjgAPwDaBjJzgufjES89Rs4Lpq63O300R/kOz30WCLo6BxxX6QVEilwSlpClnG5cZaikTA==} + '@babel/plugin-transform-optional-chaining@7.24.7': + resolution: {integrity: sha512-tK+0N9yd4j+x/4hxF3F0e0fu/VdcxU18y5SevtyM/PCFlQvXbR0Zmlo2eBrKtVipGNFzpq56o8WsIIKcJFUCRQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-parameters@7.23.3': - resolution: {integrity: sha512-09lMt6UsUb3/34BbECKVbVwrT9bO6lILWln237z7sLaWnMsTi7Yc9fhX5DLpkJzAGfaReXI22wP41SZmnAA3Vw==} + '@babel/plugin-transform-parameters@7.24.7': + resolution: {integrity: sha512-yGWW5Rr+sQOhK0Ot8hjDJuxU3XLRQGflvT4lhlSY0DFvdb3TwKaY26CJzHtYllU0vT9j58hc37ndFPsqT1SrzA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-private-methods@7.23.3': - resolution: {integrity: sha512-UzqRcRtWsDMTLrRWFvUBDwmw06tCQH9Rl1uAjfh6ijMSmGYQ+fpdB+cnqRC8EMh5tuuxSv0/TejGL+7vyj+50g==} + '@babel/plugin-transform-private-methods@7.24.7': + resolution: {integrity: sha512-COTCOkG2hn4JKGEKBADkA8WNb35TGkkRbI5iT845dB+NyqgO8Hn+ajPbSnIQznneJTa3d30scb6iz/DhH8GsJQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-private-property-in-object@7.23.4': - resolution: {integrity: sha512-9G3K1YqTq3F4Vt88Djx1UZ79PDyj+yKRnUy7cZGSMe+a7jkwD259uKKuUzQlPkGam7R+8RJwh5z4xO27fA1o2A==} + '@babel/plugin-transform-private-property-in-object@7.24.7': + resolution: {integrity: sha512-9z76mxwnwFxMyxZWEgdgECQglF2Q7cFLm0kMf8pGwt+GSJsY0cONKj/UuO4bOH0w/uAel3ekS4ra5CEAyJRmDA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-property-literals@7.23.3': - resolution: {integrity: sha512-jR3Jn3y7cZp4oEWPFAlRsSWjxKe4PZILGBSd4nis1TsC5qeSpb+nrtihJuDhNI7QHiVbUaiXa0X2RZY3/TI6Nw==} + '@babel/plugin-transform-property-literals@7.24.7': + resolution: {integrity: sha512-EMi4MLQSHfd2nrCqQEWxFdha2gBCqU4ZcCng4WBGZ5CJL4bBRW0ptdqqDdeirGZcpALazVVNJqRmsO8/+oNCBA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-regenerator@7.23.3': - resolution: {integrity: sha512-KP+75h0KghBMcVpuKisx3XTu9Ncut8Q8TuvGO4IhY+9D5DFEckQefOuIsB/gQ2tG71lCke4NMrtIPS8pOj18BQ==} + '@babel/plugin-transform-regenerator@7.24.7': + resolution: {integrity: sha512-lq3fvXPdimDrlg6LWBoqj+r/DEWgONuwjuOuQCSYgRroXDH/IdM1C0IZf59fL5cHLpjEH/O6opIRBbqv7ELnuA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-reserved-words@7.23.3': - resolution: {integrity: sha512-QnNTazY54YqgGxwIexMZva9gqbPa15t/x9VS+0fsEFWplwVpXYZivtgl43Z1vMpc1bdPP2PP8siFeVcnFvA3Cg==} + '@babel/plugin-transform-reserved-words@7.24.7': + resolution: {integrity: sha512-0DUq0pHcPKbjFZCfTss/pGkYMfy3vFWydkUBd9r0GHpIyfs2eCDENvqadMycRS9wZCXR41wucAfJHJmwA0UmoQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-shorthand-properties@7.23.3': - resolution: {integrity: sha512-ED2fgqZLmexWiN+YNFX26fx4gh5qHDhn1O2gvEhreLW2iI63Sqm4llRLCXALKrCnbN4Jy0VcMQZl/SAzqug/jg==} + '@babel/plugin-transform-shorthand-properties@7.24.7': + resolution: {integrity: sha512-KsDsevZMDsigzbA09+vacnLpmPH4aWjcZjXdyFKGzpplxhbeB4wYtury3vglQkg6KM/xEPKt73eCjPPf1PgXBA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-spread@7.23.3': - resolution: {integrity: sha512-VvfVYlrlBVu+77xVTOAoxQ6mZbnIq5FM0aGBSFEcIh03qHf+zNqA4DC/3XMUozTg7bZV3e3mZQ0i13VB6v5yUg==} + '@babel/plugin-transform-spread@7.24.7': + resolution: {integrity: sha512-x96oO0I09dgMDxJaANcRyD4ellXFLLiWhuwDxKZX5g2rWP1bTPkBSwCYv96VDXVT1bD9aPj8tppr5ITIh8hBng==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-sticky-regex@7.23.3': - resolution: {integrity: sha512-HZOyN9g+rtvnOU3Yh7kSxXrKbzgrm5X4GncPY1QOquu7epga5MxKHVpYu2hvQnry/H+JjckSYRb93iNfsioAGg==} + '@babel/plugin-transform-sticky-regex@7.24.7': + resolution: {integrity: sha512-kHPSIJc9v24zEml5geKg9Mjx5ULpfncj0wRpYtxbvKyTtHCYDkVE3aHQ03FrpEo4gEe2vrJJS1Y9CJTaThA52g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-template-literals@7.23.3': - resolution: {integrity: sha512-Flok06AYNp7GV2oJPZZcP9vZdszev6vPBkHLwxwSpaIqx75wn6mUd3UFWsSsA0l8nXAKkyCmL/sR02m8RYGeHg==} + '@babel/plugin-transform-template-literals@7.24.7': + resolution: {integrity: sha512-AfDTQmClklHCOLxtGoP7HkeMw56k1/bTQjwsfhL6pppo/M4TOBSq+jjBUBLmV/4oeFg4GWMavIl44ZeCtmmZTw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-typeof-symbol@7.23.3': - resolution: {integrity: sha512-4t15ViVnaFdrPC74be1gXBSMzXk3B4Us9lP7uLRQHTFpV5Dvt33pn+2MyyNxmN3VTTm3oTrZVMUmuw3oBnQ2oQ==} + '@babel/plugin-transform-typeof-symbol@7.24.7': + resolution: {integrity: sha512-VtR8hDy7YLB7+Pet9IarXjg/zgCMSF+1mNS/EQEiEaUPoFXCVsHG64SIxcaaI2zJgRiv+YmgaQESUfWAdbjzgg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -2037,32 +2078,32 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-unicode-escapes@7.23.3': - resolution: {integrity: sha512-OMCUx/bU6ChE3r4+ZdylEqAjaQgHAgipgW8nsCfu5pGqDcFytVd91AwRvUJSBZDz0exPGgnjoqhgRYLRjFZc9Q==} + '@babel/plugin-transform-unicode-escapes@7.24.7': + resolution: {integrity: sha512-U3ap1gm5+4edc2Q/P+9VrBNhGkfnf+8ZqppY71Bo/pzZmXhhLdqgaUl6cuB07O1+AQJtCLfaOmswiNbSQ9ivhw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-unicode-property-regex@7.23.3': - resolution: {integrity: sha512-KcLIm+pDZkWZQAFJ9pdfmh89EwVfmNovFBcXko8szpBeF8z68kWIPeKlmSOkT9BXJxs2C0uk+5LxoxIv62MROA==} + '@babel/plugin-transform-unicode-property-regex@7.24.7': + resolution: {integrity: sha512-uH2O4OV5M9FZYQrwc7NdVmMxQJOCCzFeYudlZSzUAHRFeOujQefa92E74TQDVskNHCzOXoigEuoyzHDhaEaK5w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-unicode-regex@7.23.3': - resolution: {integrity: sha512-wMHpNA4x2cIA32b/ci3AfwNgheiva2W0WUKWTK7vBHBhDKfPsc5cFGNWm69WBqpwd86u1qwZ9PWevKqm1A3yAw==} + '@babel/plugin-transform-unicode-regex@7.24.7': + resolution: {integrity: sha512-hlQ96MBZSAXUq7ltkjtu3FJCCSMx/j629ns3hA3pXnBXjanNP0LHi+JpPeA81zaWgVK1VGH95Xuy7u0RyQ8kMg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-unicode-sets-regex@7.23.3': - resolution: {integrity: sha512-W7lliA/v9bNR83Qc3q1ip9CQMZ09CcHDbHfbLRDNuAhn1Mvkr1ZNF7hPmztMQvtTGVLJ9m8IZqWsTkXOml8dbw==} + '@babel/plugin-transform-unicode-sets-regex@7.24.7': + resolution: {integrity: sha512-2G8aAvF4wy1w/AGZkemprdGMRg5o6zPNhbHVImRz3lss55TYCBd6xStN19rt8XJHq20sqV0JbyWjOWwQRwV/wg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/preset-env@7.23.5': - resolution: {integrity: sha512-0d/uxVD6tFGWXGDSfyMD1p2otoaKmu6+GD+NfAx0tMaH+dxORnp7T9TaVQ6mKyya7iBtCIVxHjWT7MuzzM9z+A==} + '@babel/preset-env@7.24.7': + resolution: {integrity: sha512-1YZNsc+y6cTvWlDHidMBsQZrZfEFjRIo/BZCT906PMdzOyXtSLTgqGdrpcuTDCXyd11Am5uQULtDIcCfnTc8fQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -2105,12 +2146,16 @@ packages: resolution: {integrity: sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==} engines: {node: '>=6.9.0'} + '@babel/template@7.24.7': + resolution: {integrity: sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==} + engines: {node: '>=6.9.0'} + '@babel/traverse@7.23.5': resolution: {integrity: sha512-czx7Xy5a6sapWWRx61m1Ke1Ra4vczu1mCTtJam5zRTBOonfdJ+S/B6HYmGYu3fJtr8GGET3si6IhgWVBhJ/m8w==} engines: {node: '>=6.9.0'} - '@babel/traverse@7.24.0': - resolution: {integrity: sha512-HfuJlI8qq3dEDmNU5ChzzpZRWq+oxCZQyMzIMEqLho+AQnhMnKQUzH6ydo3RBl/YjPCuk68Y6s0Gx0AeyULiWw==} + '@babel/traverse@7.24.7': + resolution: {integrity: sha512-yb65Ed5S/QAcewNPh0nZczy9JdYXkkAbIsEo+P7BE7yO3txAY30Y/oPa3QkQ5It3xVG2kpKMg9MsdxZaO31uKA==} engines: {node: '>=6.9.0'} '@babel/types@7.23.5': @@ -2121,22 +2166,26 @@ packages: resolution: {integrity: sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==} engines: {node: '>=6.9.0'} + '@babel/types@7.24.7': + resolution: {integrity: sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==} + engines: {node: '>=6.9.0'} + '@base2/pretty-print-object@1.0.1': resolution: {integrity: sha512-4iri8i1AqYHJE2DstZYkyEprg6Pq6sKx3xn5FpySk9sNhH7qN2LLlHJCfDTZRILNwQNPD7mATWM0TBui7uC1pA==} '@bcoe/v8-coverage@0.2.3': resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} - '@bull-board/api@5.17.0': - resolution: {integrity: sha512-qU+AiZIaYa//rkt1x7jDowtYa8u7/dLsDfEWgenZMkgvUszZ1kxJszdCtGapsDTVyPmnXgTRxpOWcR6sAYwSNQ==} + '@bull-board/api@5.20.5': + resolution: {integrity: sha512-YI95JK5A4/K4KB5VWbQn/CYNB+AO5cZ/BnZ77LxAhsaJ3ssHBN3Au0n3Z4wD7O+78+W3ON9uqGjKnHV6rXBGcQ==} peerDependencies: - '@bull-board/ui': 5.17.0 + '@bull-board/ui': 5.20.5 - '@bull-board/fastify@5.17.0': - resolution: {integrity: sha512-73YrPc7ERTWSOQRgBP6a7BPscWfcHd8U+Zq0auMdL/KkjPhG9GxapbfnovGZDDahJL/p/4YQb6ULu03zdtOrEA==} + '@bull-board/fastify@5.20.5': + resolution: {integrity: sha512-tdMR97xbzEzBbMJiJQreJHGdhfOocQn61K/WqM9I038Dk1dBHM5phQJxRJhspvwEJV4jwAayNOZbzuETI7QKwA==} - '@bull-board/ui@5.17.0': - resolution: {integrity: sha512-Vj+yWPjrjx3Iqh2N/ZBDhK2d2yJD44dfvIxm+SnXQb4ne312j117TpViInceysxGtbbAOlAW6hq6JvsDoRl7KQ==} + '@bull-board/ui@5.20.5': + resolution: {integrity: sha512-RV9VlW4qVL1A0Dewpsor4z7ZL9D56OW9LcRYjvXrIU5FSzvTvYKofmrUYoVrNQDs6jGMwJic+dMiW9K8GUU15A==} '@bundled-es-modules/cookie@2.0.0': resolution: {integrity: sha512-Or6YHg/kamKHpxULAdSqhGqnWFneIXu1NKvvfBBzKGwpVsYuFIQ5aBPHDnnoR3ghW1nvSkALd+EF9iMtY7Vjxw==} @@ -2216,12 +2265,18 @@ packages: cpu: [ppc64] os: [aix] - '@esbuild/aix-ppc64@0.20.2': - resolution: {integrity: sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==} + '@esbuild/aix-ppc64@0.21.5': + resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} engines: {node: '>=12'} cpu: [ppc64] os: [aix] + '@esbuild/aix-ppc64@0.22.0': + resolution: {integrity: sha512-uvQR2crZ/zgzSHDvdygHyNI+ze9zwS8mqz0YtGXotSqvEE0UkYE9s+FZKQNTt1VtT719mfP3vHrUdCpxBNQZhQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + '@esbuild/android-arm64@0.18.20': resolution: {integrity: sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==} engines: {node: '>=12'} @@ -2234,12 +2289,18 @@ packages: cpu: [arm64] os: [android] - '@esbuild/android-arm64@0.20.2': - resolution: {integrity: sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==} + '@esbuild/android-arm64@0.21.5': + resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} engines: {node: '>=12'} cpu: [arm64] os: [android] + '@esbuild/android-arm64@0.22.0': + resolution: {integrity: sha512-UKhPb3o2gAB/bfXcl58ZXTn1q2oVu1rEu/bKrCtmm+Nj5MKUbrOwR5WAixE2v+lk0amWuwPvhnPpBRLIGiq7ig==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + '@esbuild/android-arm@0.18.20': resolution: {integrity: sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==} engines: {node: '>=12'} @@ -2252,12 +2313,18 @@ packages: cpu: [arm] os: [android] - '@esbuild/android-arm@0.20.2': - resolution: {integrity: sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==} + '@esbuild/android-arm@0.21.5': + resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} engines: {node: '>=12'} cpu: [arm] os: [android] + '@esbuild/android-arm@0.22.0': + resolution: {integrity: sha512-PBnyP+r8vJE4ifxsWys9l+Mc2UY/yYZOpX82eoyGISXXb3dRr0M21v+s4fgRKWMFPMSf/iyowqPW/u7ScSUkjQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + '@esbuild/android-x64@0.18.20': resolution: {integrity: sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==} engines: {node: '>=12'} @@ -2270,12 +2337,18 @@ packages: cpu: [x64] os: [android] - '@esbuild/android-x64@0.20.2': - resolution: {integrity: sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==} + '@esbuild/android-x64@0.21.5': + resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} engines: {node: '>=12'} cpu: [x64] os: [android] + '@esbuild/android-x64@0.22.0': + resolution: {integrity: sha512-IjTYtvIrjhR41Ijy2dDPgYjQHWG/x/A4KXYbs1fiU3efpRdoxMChK3oEZV6GPzVEzJqxFgcuBaiX1kwEvWUxSw==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + '@esbuild/darwin-arm64@0.18.20': resolution: {integrity: sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==} engines: {node: '>=12'} @@ -2288,12 +2361,18 @@ packages: cpu: [arm64] os: [darwin] - '@esbuild/darwin-arm64@0.20.2': - resolution: {integrity: sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==} + '@esbuild/darwin-arm64@0.21.5': + resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} engines: {node: '>=12'} cpu: [arm64] os: [darwin] + '@esbuild/darwin-arm64@0.22.0': + resolution: {integrity: sha512-mqt+Go4y9wRvEz81bhKd9RpHsQR1LwU8Xm6jZRUV/xpM7cIQFbFH6wBCLPTNsdELBvfoHeumud7X78jQQJv2TA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + '@esbuild/darwin-x64@0.18.20': resolution: {integrity: sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==} engines: {node: '>=12'} @@ -2306,12 +2385,18 @@ packages: cpu: [x64] os: [darwin] - '@esbuild/darwin-x64@0.20.2': - resolution: {integrity: sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==} + '@esbuild/darwin-x64@0.21.5': + resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} engines: {node: '>=12'} cpu: [x64] os: [darwin] + '@esbuild/darwin-x64@0.22.0': + resolution: {integrity: sha512-vTaTQ9OgYc3VTaWtOE5pSuDT6H3d/qSRFRfSBbnxFfzAvYoB3pqKXA0LEbi/oT8GUOEAutspfRMqPj2ezdFaMw==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + '@esbuild/freebsd-arm64@0.18.20': resolution: {integrity: sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==} engines: {node: '>=12'} @@ -2324,12 +2409,18 @@ packages: cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-arm64@0.20.2': - resolution: {integrity: sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==} + '@esbuild/freebsd-arm64@0.21.5': + resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} engines: {node: '>=12'} cpu: [arm64] os: [freebsd] + '@esbuild/freebsd-arm64@0.22.0': + resolution: {integrity: sha512-0e1ZgoobJzaGnR4reD7I9rYZ7ttqdh1KPvJWnquUoDJhL0rYwdneeLailBzd2/4g/U5p4e5TIHEWa68NF2hFpQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + '@esbuild/freebsd-x64@0.18.20': resolution: {integrity: sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==} engines: {node: '>=12'} @@ -2342,12 +2433,18 @@ packages: cpu: [x64] os: [freebsd] - '@esbuild/freebsd-x64@0.20.2': - resolution: {integrity: sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==} + '@esbuild/freebsd-x64@0.21.5': + resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} engines: {node: '>=12'} cpu: [x64] os: [freebsd] + '@esbuild/freebsd-x64@0.22.0': + resolution: {integrity: sha512-BFgyYwlCwRWyPQJtkzqq2p6pJbiiWgp0P9PNf7a5FQ1itKY4czPuOMAlFVItirSmEpRPCeImuwePNScZS0pL5Q==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + '@esbuild/linux-arm64@0.18.20': resolution: {integrity: sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==} engines: {node: '>=12'} @@ -2360,12 +2457,18 @@ packages: cpu: [arm64] os: [linux] - '@esbuild/linux-arm64@0.20.2': - resolution: {integrity: sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==} + '@esbuild/linux-arm64@0.21.5': + resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} engines: {node: '>=12'} cpu: [arm64] os: [linux] + '@esbuild/linux-arm64@0.22.0': + resolution: {integrity: sha512-V/K2rctCUgC0PCXpN7AqT4hoazXKgIYugFGu/myk2+pfe6jTW2guz/TBwq4cZ7ESqusR/IzkcQaBkcjquuBWsw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + '@esbuild/linux-arm@0.18.20': resolution: {integrity: sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==} engines: {node: '>=12'} @@ -2378,12 +2481,18 @@ packages: cpu: [arm] os: [linux] - '@esbuild/linux-arm@0.20.2': - resolution: {integrity: sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==} + '@esbuild/linux-arm@0.21.5': + resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} engines: {node: '>=12'} cpu: [arm] os: [linux] + '@esbuild/linux-arm@0.22.0': + resolution: {integrity: sha512-KEMWiA9aGuPUD4BH5yjlhElLgaRXe+Eri6gKBoDazoPBTo1BXc/e6IW5FcJO9DoL19FBeCxgONyh95hLDNepIg==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + '@esbuild/linux-ia32@0.18.20': resolution: {integrity: sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==} engines: {node: '>=12'} @@ -2396,12 +2505,18 @@ packages: cpu: [ia32] os: [linux] - '@esbuild/linux-ia32@0.20.2': - resolution: {integrity: sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==} + '@esbuild/linux-ia32@0.21.5': + resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} engines: {node: '>=12'} cpu: [ia32] os: [linux] + '@esbuild/linux-ia32@0.22.0': + resolution: {integrity: sha512-r2ZZqkOMOrpUhzNwxI7uLAHIDwkfeqmTnrv1cjpL/rjllPWszgqmprd/om9oviKXUBpMqHbXmppvjAYgISb26Q==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + '@esbuild/linux-loong64@0.18.20': resolution: {integrity: sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==} engines: {node: '>=12'} @@ -2414,12 +2529,18 @@ packages: cpu: [loong64] os: [linux] - '@esbuild/linux-loong64@0.20.2': - resolution: {integrity: sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==} + '@esbuild/linux-loong64@0.21.5': + resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} engines: {node: '>=12'} cpu: [loong64] os: [linux] + '@esbuild/linux-loong64@0.22.0': + resolution: {integrity: sha512-qaowLrV/YOMAL2RfKQ4C/VaDzAuLDuylM2sd/LH+4OFirMl6CuDpRlCq4u49ZBaVV8pkI/Y+hTdiibvQRhojCA==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + '@esbuild/linux-mips64el@0.18.20': resolution: {integrity: sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==} engines: {node: '>=12'} @@ -2432,12 +2553,18 @@ packages: cpu: [mips64el] os: [linux] - '@esbuild/linux-mips64el@0.20.2': - resolution: {integrity: sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==} + '@esbuild/linux-mips64el@0.21.5': + resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} engines: {node: '>=12'} cpu: [mips64el] os: [linux] + '@esbuild/linux-mips64el@0.22.0': + resolution: {integrity: sha512-hgrezzjQTRxjkQ5k08J6rtZN5PNnkWx/Rz6Kmj9gnsdCAX1I4Dn4ZPqvFRkXo55Q3pnVQJBwbdtrTO7tMGtyVA==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + '@esbuild/linux-ppc64@0.18.20': resolution: {integrity: sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==} engines: {node: '>=12'} @@ -2450,12 +2577,18 @@ packages: cpu: [ppc64] os: [linux] - '@esbuild/linux-ppc64@0.20.2': - resolution: {integrity: sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==} + '@esbuild/linux-ppc64@0.21.5': + resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} engines: {node: '>=12'} cpu: [ppc64] os: [linux] + '@esbuild/linux-ppc64@0.22.0': + resolution: {integrity: sha512-ewxg6FLLUio883XgSjfULEmDl3VPv/TYNnRprVAS3QeGFLdCYdx1tIudBcd7n9jIdk82v1Ajov4jx87qW7h9+g==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + '@esbuild/linux-riscv64@0.18.20': resolution: {integrity: sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==} engines: {node: '>=12'} @@ -2468,12 +2601,18 @@ packages: cpu: [riscv64] os: [linux] - '@esbuild/linux-riscv64@0.20.2': - resolution: {integrity: sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==} + '@esbuild/linux-riscv64@0.21.5': + resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} engines: {node: '>=12'} cpu: [riscv64] os: [linux] + '@esbuild/linux-riscv64@0.22.0': + resolution: {integrity: sha512-Az5XbgSJC2lE8XK8pdcutsf9RgdafWdTpUK/+6uaDdfkviw/B4JCwAfh1qVeRWwOohwdsl4ywZrWBNWxwrPLFg==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + '@esbuild/linux-s390x@0.18.20': resolution: {integrity: sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==} engines: {node: '>=12'} @@ -2486,12 +2625,18 @@ packages: cpu: [s390x] os: [linux] - '@esbuild/linux-s390x@0.20.2': - resolution: {integrity: sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==} + '@esbuild/linux-s390x@0.21.5': + resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} engines: {node: '>=12'} cpu: [s390x] os: [linux] + '@esbuild/linux-s390x@0.22.0': + resolution: {integrity: sha512-8j4a2ChT9+V34NNNY9c/gMldutaJFmfMacTPq4KfNKwv2fitBCLYjee7c+Vxaha2nUhPK7cXcZpJtJ3+Y7ZdVQ==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + '@esbuild/linux-x64@0.18.20': resolution: {integrity: sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==} engines: {node: '>=12'} @@ -2504,12 +2649,18 @@ packages: cpu: [x64] os: [linux] - '@esbuild/linux-x64@0.20.2': - resolution: {integrity: sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==} + '@esbuild/linux-x64@0.21.5': + resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} engines: {node: '>=12'} cpu: [x64] os: [linux] + '@esbuild/linux-x64@0.22.0': + resolution: {integrity: sha512-JUQyOnpbAkkRFOk/AhsEemz5TfWN4FJZxVObUlnlNCbe7QBl61ZNfM4cwBXayQA6laMJMUcqLHaYQHAB6YQ95Q==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + '@esbuild/netbsd-x64@0.18.20': resolution: {integrity: sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==} engines: {node: '>=12'} @@ -2522,12 +2673,24 @@ packages: cpu: [x64] os: [netbsd] - '@esbuild/netbsd-x64@0.20.2': - resolution: {integrity: sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==} + '@esbuild/netbsd-x64@0.21.5': + resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} engines: {node: '>=12'} cpu: [x64] os: [netbsd] + '@esbuild/netbsd-x64@0.22.0': + resolution: {integrity: sha512-11PoCoHXo4HFNbLsXuMB6bpMPWGDiw7xETji6COdJss4SQZLvcgNoeSqWtATRm10Jj1uEHiaIk4N0PiN6x4Fcg==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.22.0': + resolution: {integrity: sha512-Ezlhu/YyITmXwKSB+Zu/QqD7cxrjrpiw85cc0Rbd3AWr2wsgp+dWbWOE8MqHaLW9NKMZvuL0DhbJbvzR7F6Zvg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + '@esbuild/openbsd-x64@0.18.20': resolution: {integrity: sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==} engines: {node: '>=12'} @@ -2540,12 +2703,18 @@ packages: cpu: [x64] os: [openbsd] - '@esbuild/openbsd-x64@0.20.2': - resolution: {integrity: sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==} + '@esbuild/openbsd-x64@0.21.5': + resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} engines: {node: '>=12'} cpu: [x64] os: [openbsd] + '@esbuild/openbsd-x64@0.22.0': + resolution: {integrity: sha512-ufjdW5tFJGUjlH9j/5cCE9lrwRffyZh+T4vYvoDKoYsC6IXbwaFeV/ENxeNXcxotF0P8CDzoICXVSbJaGBhkrw==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + '@esbuild/sunos-x64@0.18.20': resolution: {integrity: sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==} engines: {node: '>=12'} @@ -2558,12 +2727,18 @@ packages: cpu: [x64] os: [sunos] - '@esbuild/sunos-x64@0.20.2': - resolution: {integrity: sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==} + '@esbuild/sunos-x64@0.21.5': + resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} engines: {node: '>=12'} cpu: [x64] os: [sunos] + '@esbuild/sunos-x64@0.22.0': + resolution: {integrity: sha512-zY6ly/AoSmKnmNTowDJsK5ehra153/5ZhqxNLfq9NRsTTltetr+yHHcQ4RW7QDqw4JC8A1uC1YmeSfK9NRcK1w==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + '@esbuild/win32-arm64@0.18.20': resolution: {integrity: sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==} engines: {node: '>=12'} @@ -2576,12 +2751,18 @@ packages: cpu: [arm64] os: [win32] - '@esbuild/win32-arm64@0.20.2': - resolution: {integrity: sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==} + '@esbuild/win32-arm64@0.21.5': + resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} engines: {node: '>=12'} cpu: [arm64] os: [win32] + '@esbuild/win32-arm64@0.22.0': + resolution: {integrity: sha512-Kml5F7tv/1Maam0pbbCrvkk9vj046dPej30kFzlhXnhuCtYYBP6FGy/cLbc5yUT1lkZznGLf2OvuvmLjscO5rw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + '@esbuild/win32-ia32@0.18.20': resolution: {integrity: sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==} engines: {node: '>=12'} @@ -2594,12 +2775,18 @@ packages: cpu: [ia32] os: [win32] - '@esbuild/win32-ia32@0.20.2': - resolution: {integrity: sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==} + '@esbuild/win32-ia32@0.21.5': + resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} engines: {node: '>=12'} cpu: [ia32] os: [win32] + '@esbuild/win32-ia32@0.22.0': + resolution: {integrity: sha512-IOgwn+mYTM3RrcydP4Og5IpXh+ftN8oF+HELTXSmbWBlujuci4Qa3DTeO+LEErceisI7KUSfEIiX+WOUlpELkw==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + '@esbuild/win32-x64@0.18.20': resolution: {integrity: sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==} engines: {node: '>=12'} @@ -2612,12 +2799,18 @@ packages: cpu: [x64] os: [win32] - '@esbuild/win32-x64@0.20.2': - resolution: {integrity: sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==} + '@esbuild/win32-x64@0.21.5': + resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} engines: {node: '>=12'} cpu: [x64] os: [win32] + '@esbuild/win32-x64@0.22.0': + resolution: {integrity: sha512-4bDHJrk2WHBXJPhy1y80X7/5b5iZTZP3LGcKIlAP1J+KqZ4zQAPMLEzftGyjjfcKbA4JDlPt/+2R/F1ZTeRgrw==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + '@eslint-community/eslint-utils@4.4.0': resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -2628,21 +2821,37 @@ packages: resolution: {integrity: sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + '@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} + '@eslint-community/regexpp@4.6.2': resolution: {integrity: sha512-pPTNuaAG3QMH+buKyBIGJs3g/S5y0caxw0ygM3YyE6yJFySwiGGSzA+mM3KJ8QQvzeLh3blwgSonkFjgQdxzMw==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - '@eslint/eslintrc@2.1.4': - resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + '@eslint/compat@1.1.1': + resolution: {integrity: sha512-lpHyRyplhGPL5mGEh6M9O5nnKk0Gz4bFI+Zu6tKlPpDUN7XshWvH9C/px4UVm87IAANE0W81CEsNGbS1KlzXpA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/js@8.53.0': - resolution: {integrity: sha512-Kn7K8dx/5U6+cT1yEhpX1w4PCSg0M+XyRILPgvwcEBjerFWCwQj5sbr3/VmxqV0JGHCBCzyd6LxypEuehypY1w==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + '@eslint/config-array@0.17.0': + resolution: {integrity: sha512-A68TBu6/1mHHuc5YJL0U0VVeGNiklLAL6rRmhTCP2B5XjWLMnrX+HkO+IAXyHvks5cyyY1jjK5ITPQ1HGS2EVA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/js@8.57.0': - resolution: {integrity: sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + '@eslint/eslintrc@3.1.0': + resolution: {integrity: sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/js@9.6.0': + resolution: {integrity: sha512-D9B0/3vNg44ZeWbYMpBoXqNP4j6eQD5vNwIlGAuFRRzK/WtT/jvDQW3Bi9kkf3PMDMlM7Yi+73VLUsn5bJcl8A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/js@9.7.0': + resolution: {integrity: sha512-ChuWDQenef8OSFnvuxv0TCVxEwmu3+hPNKvM9B34qpM0rDRbjL8t5QkQeHHeAfsKQjuH9wS82WeCi1J/owatng==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/object-schema@2.1.4': + resolution: {integrity: sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@fal-works/esbuild-plugin-global-externals@2.1.2': resolution: {integrity: sha512-cEee/Z+I12mZcFJshKcCqC8tuX5hG3s+d+9nZ3LabqKF1vKdF41B92pJVCBggjAGORAeOzyyDDKrZwIkLffeOQ==} @@ -2682,8 +2891,8 @@ packages: '@fastify/http-proxy@9.5.0': resolution: {integrity: sha512-1iqIdV10d5k9YtfHq9ylX5zt1NiM50fG+rIX40qt00R694sqWso3ukyTFZVk33SDoSiBW8roB7n11RUVUoN+Ag==} - '@fastify/multipart@8.2.0': - resolution: {integrity: sha512-OZ8nsyyoS2TV7Yeu3ZdrdDGsKUTAbfjrKC9jSxGgT2qdgek+BxpWX31ZubTrWMNZyU5xwk4ox6AvTjAbYWjrWg==} + '@fastify/multipart@8.3.0': + resolution: {integrity: sha512-A8h80TTyqUzaMVH0Cr9Qcm6RxSkVqmhK/MVBYHYeRRSUbUYv08WecjWKSlG2aSnD4aGI841pVxAjC+G1GafUeQ==} '@fastify/reply-from@9.0.1': resolution: {integrity: sha512-q9vFNUiXZTY1x8omDPe59os2MYq+3y7KgO/kZoXpZlnud+45Nd8Ot/svEvrUATzjkizIggfS4K8LR9zXDyZZKg==} @@ -2694,8 +2903,8 @@ packages: '@fastify/static@6.12.0': resolution: {integrity: sha512-KK1B84E6QD/FcQWxDI2aiUCwHxMJBI1KeCUzm1BwYpPY1b742+jeKruGHP2uOluuM6OkBPI8CIANrXcCRtC2oQ==} - '@fastify/static@7.0.3': - resolution: {integrity: sha512-2tmTdF+uFCykasutaO6k4/wOt7eXyi7m3dGuCPo5micXzv0qt6ttb/nWnDYL/BlXjYGfp1JI4a1gyluTIylvQA==} + '@fastify/static@7.0.4': + resolution: {integrity: sha512-p2uKtaf8BMOZWLs6wu+Ihg7bWNBdjNgCwDza4MJtTqg+5ovKmcbgbR9Xs5/smZ1YISfzKOCNYmZV8LaCj+eJ1Q==} '@fastify/view@8.2.0': resolution: {integrity: sha512-hBSiBofCnJNlPHEMZWpO1SL84eqOaqujJ1hR3jntFyZZCkweH5jMs12DKYyGesjVll7SJFRRxPUBB8kmUmneRQ==} @@ -2713,11 +2922,8 @@ packages: '@hapi/bourne@3.0.0': resolution: {integrity: sha512-Waj1cwPXJDucOib4a3bAISsKJVb15MKi9IvmTI/7ssVEm6sywXGjVJDhl6/umt1pK1ZS7PacXU3A1PmFKHEZ2w==} - '@hapi/hoek@10.0.1': - resolution: {integrity: sha512-CvlW7jmOhWzuqOqiJQ3rQVLMcREh0eel4IBnxDx2FAcK8g7qoJRQK4L1CPBASoCY6y8e6zuCy3f2g+HWdkzcMw==} - - '@hapi/hoek@11.0.2': - resolution: {integrity: sha512-aKmlCO57XFZ26wso4rJsW4oTUnrgTFw2jh3io7CAtO9w4UltBNwRXvXIVzzyfkaaLRo3nluP/19msA8vDUUuKw==} + '@hapi/hoek@11.0.4': + resolution: {integrity: sha512-PnsP5d4q7289pS2T2EgGz147BFJ2Jpb4yrEdkpz2IhgEUzos1S7HTl7ezWh1yfYzYlj89KzLdCRkqsP6SIryeQ==} '@hapi/hoek@9.3.0': resolution: {integrity: sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==} @@ -2731,14 +2937,6 @@ packages: '@hexagon/base64@1.1.27': resolution: {integrity: sha512-PdUmzpvcUM3Rh39kvz9RdbPVYhMjBjdV7Suw7ZduP7urRLsZR8l5tzgSWKm7TExwBYDFwTnYrZbnE0rQ3N5NLQ==} - '@humanwhocodes/config-array@0.11.13': - resolution: {integrity: sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==} - engines: {node: '>=10.10.0'} - - '@humanwhocodes/config-array@0.11.14': - resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} - engines: {node: '>=10.10.0'} - '@humanwhocodes/module-importer@1.0.1': resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} engines: {node: '>=12.22'} @@ -2747,20 +2945,18 @@ packages: resolution: {integrity: sha512-RE815I4arJFtt+FVeU1Tgp9/Xvecacji8w/V6XtXsWWH/wz/eNkNbhb+ny/+PlVZjV0rxQpRSQKNKE3lcktHEA==} engines: {node: '>=10.10.0'} - '@humanwhocodes/object-schema@2.0.1': - resolution: {integrity: sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==} + '@humanwhocodes/retry@0.3.0': + resolution: {integrity: sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew==} + engines: {node: '>=18.18'} - '@humanwhocodes/object-schema@2.0.2': - resolution: {integrity: sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==} - - '@img/sharp-darwin-arm64@0.33.3': - resolution: {integrity: sha512-FaNiGX1MrOuJ3hxuNzWgsT/mg5OHG/Izh59WW2mk1UwYHUwtfbhk5QNKYZgxf0pLOhx9ctGiGa2OykD71vOnSw==} + '@img/sharp-darwin-arm64@0.33.4': + resolution: {integrity: sha512-p0suNqXufJs9t3RqLBO6vvrgr5OhgbWp76s5gTRvdmxmuv9E1rcaqGUsl3l4mKVmXPkTkTErXediAui4x+8PSA==} engines: {glibc: '>=2.26', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} cpu: [arm64] os: [darwin] - '@img/sharp-darwin-x64@0.33.3': - resolution: {integrity: sha512-2QeSl7QDK9ru//YBT4sQkoq7L0EAJZA3rtV+v9p8xTKl4U1bUqTIaCnoC7Ctx2kCjQgwFXDasOtPTCT8eCTXvw==} + '@img/sharp-darwin-x64@0.33.4': + resolution: {integrity: sha512-0l7yRObwtTi82Z6ebVI2PnHT8EB2NxBgpK2MiKJZJ7cz32R4lxd001ecMhzzsZig3Yv9oclvqqdV93jo9hy+Dw==} engines: {glibc: '>=2.26', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} cpu: [x64] os: [darwin] @@ -2813,55 +3009,55 @@ packages: cpu: [x64] os: [linux] - '@img/sharp-linux-arm64@0.33.3': - resolution: {integrity: sha512-Zf+sF1jHZJKA6Gor9hoYG2ljr4wo9cY4twaxgFDvlG0Xz9V7sinsPp8pFd1XtlhTzYo0IhDbl3rK7P6MzHpnYA==} + '@img/sharp-linux-arm64@0.33.4': + resolution: {integrity: sha512-2800clwVg1ZQtxwSoTlHvtm9ObgAax7V6MTAB/hDT945Tfyy3hVkmiHpeLPCKYqYR1Gcmv1uDZ3a4OFwkdBL7Q==} engines: {glibc: '>=2.26', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} cpu: [arm64] os: [linux] - '@img/sharp-linux-arm@0.33.3': - resolution: {integrity: sha512-Q7Ee3fFSC9P7vUSqVEF0zccJsZ8GiiCJYGWDdhEjdlOeS9/jdkyJ6sUSPj+bL8VuOYFSbofrW0t/86ceVhx32w==} + '@img/sharp-linux-arm@0.33.4': + resolution: {integrity: sha512-RUgBD1c0+gCYZGCCe6mMdTiOFS0Zc/XrN0fYd6hISIKcDUbAW5NtSQW9g/powkrXYm6Vzwd6y+fqmExDuCdHNQ==} engines: {glibc: '>=2.28', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} cpu: [arm] os: [linux] - '@img/sharp-linux-s390x@0.33.3': - resolution: {integrity: sha512-vFk441DKRFepjhTEH20oBlFrHcLjPfI8B0pMIxGm3+yilKyYeHEVvrZhYFdqIseSclIqbQ3SnZMwEMWonY5XFA==} - engines: {glibc: '>=2.28', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} + '@img/sharp-linux-s390x@0.33.4': + resolution: {integrity: sha512-h3RAL3siQoyzSoH36tUeS0PDmb5wINKGYzcLB5C6DIiAn2F3udeFAum+gj8IbA/82+8RGCTn7XW8WTFnqag4tQ==} + engines: {glibc: '>=2.31', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} cpu: [s390x] os: [linux] - '@img/sharp-linux-x64@0.33.3': - resolution: {integrity: sha512-Q4I++herIJxJi+qmbySd072oDPRkCg/SClLEIDh5IL9h1zjhqjv82H0Seupd+q2m0yOfD+/fJnjSoDFtKiHu2g==} + '@img/sharp-linux-x64@0.33.4': + resolution: {integrity: sha512-GoR++s0XW9DGVi8SUGQ/U4AeIzLdNjHka6jidVwapQ/JebGVQIpi52OdyxCNVRE++n1FCLzjDovJNozif7w/Aw==} engines: {glibc: '>=2.26', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} cpu: [x64] os: [linux] - '@img/sharp-linuxmusl-arm64@0.33.3': - resolution: {integrity: sha512-qnDccehRDXadhM9PM5hLvcPRYqyFCBN31kq+ErBSZtZlsAc1U4Z85xf/RXv1qolkdu+ibw64fUDaRdktxTNP9A==} + '@img/sharp-linuxmusl-arm64@0.33.4': + resolution: {integrity: sha512-nhr1yC3BlVrKDTl6cO12gTpXMl4ITBUZieehFvMntlCXFzH2bvKG76tBL2Y/OqhupZt81pR7R+Q5YhJxW0rGgQ==} engines: {musl: '>=1.2.2', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} cpu: [arm64] os: [linux] - '@img/sharp-linuxmusl-x64@0.33.3': - resolution: {integrity: sha512-Jhchim8kHWIU/GZ+9poHMWRcefeaxFIs9EBqf9KtcC14Ojk6qua7ghKiPs0sbeLbLj/2IGBtDcxHyjCdYWkk2w==} + '@img/sharp-linuxmusl-x64@0.33.4': + resolution: {integrity: sha512-uCPTku0zwqDmZEOi4ILyGdmW76tH7dm8kKlOIV1XC5cLyJ71ENAAqarOHQh0RLfpIpbV5KOpXzdU6XkJtS0daw==} engines: {musl: '>=1.2.2', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} cpu: [x64] os: [linux] - '@img/sharp-wasm32@0.33.3': - resolution: {integrity: sha512-68zivsdJ0koE96stdUfM+gmyaK/NcoSZK5dV5CAjES0FUXS9lchYt8LAB5rTbM7nlWtxaU/2GON0HVN6/ZYJAQ==} + '@img/sharp-wasm32@0.33.4': + resolution: {integrity: sha512-Bmmauh4sXUsUqkleQahpdNXKvo+wa1V9KhT2pDA4VJGKwnKMJXiSTGphn0gnJrlooda0QxCtXc6RX1XAU6hMnQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} cpu: [wasm32] - '@img/sharp-win32-ia32@0.33.3': - resolution: {integrity: sha512-CyimAduT2whQD8ER4Ux7exKrtfoaUiVr7HG0zZvO0XTFn2idUWljjxv58GxNTkFb8/J9Ub9AqITGkJD6ZginxQ==} + '@img/sharp-win32-ia32@0.33.4': + resolution: {integrity: sha512-99SJ91XzUhYHbx7uhK3+9Lf7+LjwMGQZMDlO/E/YVJ7Nc3lyDFZPGhjwiYdctoH2BOzW9+TnfqcaMKt0jHLdqw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} cpu: [ia32] os: [win32] - '@img/sharp-win32-x64@0.33.3': - resolution: {integrity: sha512-viT4fUIDKnli3IfOephGnolMzhz5VaTvDRkYqtZxOMIoMQ4MrAziO7pT1nVnOt2FAm7qW5aa+CCc13aEY6Le0g==} + '@img/sharp-win32-x64@0.33.4': + resolution: {integrity: sha512-3QLocdTRVIrFNye5YocZl+KKpYKP+fksi1QhmOArgx7GyhIbQp/WrJRu176jm8IxromS7RIkzMiMINVdBtC8Aw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} cpu: [x64] os: [win32] @@ -2979,8 +3175,8 @@ packages: resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - '@joshwooding/vite-plugin-react-docgen-typescript@0.3.0': - resolution: {integrity: sha512-2D6y7fNvFmsLmRt6UCOFJPvFoPMJGT0Uh1Wg0RaigUp7kdQPs6yYn8Dmx6GZkOH/NW0yMTwRz/p0SRMMRo50vA==} + '@joshwooding/vite-plugin-react-docgen-typescript@0.3.1': + resolution: {integrity: sha512-pdoMZ9QaPnVlSM+SdU/wgg0nyD/8wQ7y90ttO2CMCyrrm7RxveYIJ5eNfjPaoMFqW41LZra7QO9j+xV4Y18Glw==} peerDependencies: typescript: '>= 4.3.x' vite: ^3.0.0 || ^4.0.0 || ^5.0.0 @@ -2992,6 +3188,10 @@ packages: resolution: {integrity: sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==} engines: {node: '>=6.0.0'} + '@jridgewell/gen-mapping@0.3.5': + resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} + engines: {node: '>=6.0.0'} + '@jridgewell/resolve-uri@3.1.0': resolution: {integrity: sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==} engines: {node: '>=6.0.0'} @@ -3000,9 +3200,16 @@ packages: resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} engines: {node: '>=6.0.0'} + '@jridgewell/set-array@1.2.1': + resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} + engines: {node: '>=6.0.0'} + '@jridgewell/source-map@0.3.5': resolution: {integrity: sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==} + '@jridgewell/source-map@0.3.6': + resolution: {integrity: sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==} + '@jridgewell/sourcemap-codec@1.4.14': resolution: {integrity: sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==} @@ -3012,12 +3219,20 @@ packages: '@jridgewell/trace-mapping@0.3.18': resolution: {integrity: sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==} + '@jridgewell/trace-mapping@0.3.25': + resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + '@jsdevtools/ono@7.1.3': resolution: {integrity: sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==} '@kurkle/color@0.3.2': resolution: {integrity: sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw==} + '@lapo/asn1js@2.0.4': + resolution: {integrity: sha512-KJD3wQAZxozcraJdWp3utDU6DEZgAVBGp9INCdptUpZaXCEYkpwNb7h7wyYh5y6DxtpvIud8k0suhWJ/z2rKvw==} + engines: {node: '>=12.20.0'} + hasBin: true + '@levischuck/tiny-cbor@0.2.2': resolution: {integrity: sha512-f5CnPw997Y2GQ8FAvtuVVC19FX8mwNNC+1XJcIi16n/LTJifKO6QBgGLgN3YEmqtGMk17SKSuoWES3imJVxAVw==} @@ -3045,29 +3260,35 @@ packages: '@types/react': '>=16' react: '>=16' - '@microsoft/api-extractor-model@7.28.14': - resolution: {integrity: sha512-Bery/c8A8SsKPSvA82cTTuy/+OcxZbLRmKhPkk91/AJOQzxZsShcrmHFAGeiEqSIrv1nPZ3tKq9kfMLdCHmsqg==} + '@microsoft/api-extractor-model@7.29.2': + resolution: {integrity: sha512-hAYajOjQan3uslhKJRwvvHIdLJ+ZByKqdSsJ/dgHFxPtEbdKpzMDO8zuW4K5gkSMYl5D0LbNwxkhxr51P2zsmw==} - '@microsoft/api-extractor@7.43.1': - resolution: {integrity: sha512-ohg40SsvFFgzHFAtYq5wKJc8ZDyY46bphjtnSvhSSlXpPTG7GHwyyXkn48UZiUCBwr2WC7TRC1Jfwz7nreuiyQ==} + '@microsoft/api-extractor@7.47.0': + resolution: {integrity: sha512-LT8yvcWNf76EpDC+8/ArTVSYePvuDQ+YbAUrsTcpg3ptiZ93HIcMCozP/JOxDt+rrsFfFHcpfoselKfPyRI0GQ==} hasBin: true - '@microsoft/tsdoc-config@0.16.2': - resolution: {integrity: sha512-OGiIzzoBLgWWR0UdRJX98oYO+XKGf7tiK4Zk6tQ/E4IJqGCe7dvkTvgDZV5cFJUzLGDOjeAXrnZoA6QkVySuxw==} + '@microsoft/tsdoc-config@0.17.0': + resolution: {integrity: sha512-v/EYRXnCAIHxOHW+Plb6OWuUoMotxTN0GLatnpOb1xq0KuTNw/WI3pamJx/UbsoJP5k9MCw1QxvvhPcF9pH3Zg==} - '@microsoft/tsdoc@0.14.2': - resolution: {integrity: sha512-9b8mPpKrfeGRuhFH5iO1iwCLeIIsV6+H1sRfxbkoGXIyQE2BTsPd9zqSqQJ+pv5sJ/hT5M1zvOFL02MnEezFug==} + '@microsoft/tsdoc@0.15.0': + resolution: {integrity: sha512-HZpPoABogPvjeJOdzCOSJsXeL/SMCBgBZMVC3X3d7YYp2gf31MfxhUoYUNwf1ERPJOnQc0wkFn9trqI6ZEdZuA==} '@misskey-dev/browser-image-resizer@2024.1.0': resolution: {integrity: sha512-4EnO0zLW5NDtng3Gaz5MuT761uiuoOuplwX18wBqgj8w56LTU5BjLn/vbHwDIIe0j2gwqDYhMb7bDjmr1/Fomg==} - '@misskey-dev/eslint-plugin@1.0.0': - resolution: {integrity: sha512-dh6UbcrNDVg5DD8k8Qh4ab30OPpuEYIlJCqaBV/lkIV8wNN/AfCJ2V7iTP8V8KjryM4t+sf5IqzQLQnT0mWI4A==} + '@misskey-dev/eslint-plugin@2.0.2': + resolution: {integrity: sha512-bnTqxCSP0CIN0xSpIGib13bz+K8/3e4h8OlQjuCPlhZF7oFwtn339EZM8yJkHg6gdfciV8KOr3gzlLyG3jiVEQ==} peerDependencies: - '@typescript-eslint/eslint-plugin': '>= 6' - '@typescript-eslint/parser': '>= 6' - eslint: '>= 3' + '@eslint/compat': '>= 1' + '@typescript-eslint/eslint-plugin': '>= 7' + '@typescript-eslint/parser': '>= 7' + eslint: '>= 8' eslint-plugin-import: '>= 2' + globals: '>= 15' + + '@misskey-dev/node-http-message-signatures@0.0.10': + resolution: {integrity: sha512-HiAuc//tOU077KFUJhHYLAPWku9enTpOFIqQiK6l2i2mIizRvv7HhV7Y+yuav5quDOAz+WZGK/i5C9OR5fkKIg==} + engines: {node: '>=18.4.0'} '@misskey-dev/sharp-read-bmp@1.2.0': resolution: {integrity: sha512-er4pRakXzHYfEgOFAFfQagqDouG+wLm+kwNq1I30oSdIHDa0wM3KjFpfIGQ25Fks4GcmOl1s7Zh6xoQu5dNjTw==} @@ -3113,73 +3334,73 @@ packages: resolution: {integrity: sha512-0ZcCVQxifZmhwNBoQIrystCb+2sWBY2Zw8lpfJBPCHGCA/HWqehITeCRVIv4VMy8MPlaHo2w2pTHFV2pFfqKPw==} engines: {node: '>=18'} - '@mswjs/interceptors@0.26.15': - resolution: {integrity: sha512-HM47Lu1YFmnYHKMBynFfjCp0U/yRskHj/8QEJW0CBEPOlw8Gkmjfll+S9b8M7V5CNDw2/ciRxjjnWeaCiblSIQ==} + '@mswjs/interceptors@0.29.1': + resolution: {integrity: sha512-3rDakgJZ77+RiQUuSK69t1F0m8BQKA8Vh5DCS5V0DWvNY67zob2JhhQrhCO0AKLGINTRSFd1tBaHcJTkhefoSw==} engines: {node: '>=18'} - '@napi-rs/canvas-android-arm64@0.1.52': - resolution: {integrity: sha512-x/K471KbASPVh5mfBUxokza66J0FNIlOgMNANWAf5C8HiATb487KecEhSkUQvvTS3WLYC9uSqIPHFgwF+tir3w==} + '@napi-rs/canvas-android-arm64@0.1.53': + resolution: {integrity: sha512-2YhxfVsZguATlRWE0fZdTx35SE9+r5D7HV5GPNDataZOKmHf+zZ5//dspuuBSbOriQdoicaFrgXKCUqI0pK3WQ==} engines: {node: '>= 10'} cpu: [arm64] os: [android] - '@napi-rs/canvas-darwin-arm64@0.1.52': - resolution: {integrity: sha512-4OgVRD7TW02q5Q7lWLLjT+pYJ9ZHkQUTBOuXbPQ5wB0Wnh3RIq/aMY6thoXDZDzdR5vV3a5TUtbZUJ0aqLq3NA==} + '@napi-rs/canvas-darwin-arm64@0.1.53': + resolution: {integrity: sha512-ls+CWLMusf4RAGo5BvIIzA6dNcc0elwVp6LKjHfQECHA8KKmvdB58YuE5BQcTlb2rzk0SEKtBC/Th3NI2oNdfg==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@napi-rs/canvas-darwin-x64@0.1.52': - resolution: {integrity: sha512-3fgeGJ3j2X6Mtmn0QYf3iA+A6y1ePnsayakc2emEokzf03ErrPczONw3vjnTQo53JLPMzEnfPGAffdktU/ssPA==} + '@napi-rs/canvas-darwin-x64@0.1.53': + resolution: {integrity: sha512-ZAgcoCH5+5OKS2P8Lxx+jbkAPKkyLD2x6OvSrHg1U6ppdxmLA+CkJlRl8w45HCXwuyIiP7OeymECRtiNYTwznQ==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@napi-rs/canvas-linux-arm-gnueabihf@0.1.52': - resolution: {integrity: sha512-aaDEEK5XwHUrPt0q4SR8l7Va0vtn50KmSs+itxP+o7RNk3Nuch8fINHOXyhMyhwNYgv1tfiJVyHsJhD0E6lXGA==} + '@napi-rs/canvas-linux-arm-gnueabihf@0.1.53': + resolution: {integrity: sha512-p9km/3C/loDxu3AvA8/vtpIS1BGMd/Ehkl2Iu/v/Gw8N/KUIt3HUvTS7AKApyVE28bxTfq96wJQjtcT8jzDncw==} engines: {node: '>= 10'} cpu: [arm] os: [linux] - '@napi-rs/canvas-linux-arm64-gnu@0.1.52': - resolution: {integrity: sha512-tzuwM7Amt5mkrp4csQjYWkFzwFdiCm7RNdJ5usX8syzKSXmozqWzLHjzo/2ozdSQNUy6wyzRrxkG4Rh6g0OpOA==} + '@napi-rs/canvas-linux-arm64-gnu@0.1.53': + resolution: {integrity: sha512-QKK+sykEiYwjwd+ogyLcpcnH38DNZ8KViBlnfEpoGA2Wa+21/cWQKfMxnbgb/rbvm5tazJinZcihFvH577WQ5g==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@napi-rs/canvas-linux-arm64-musl@0.1.52': - resolution: {integrity: sha512-HQCtJlDT0dFp3uUZVzZOZ1VLMO7lbLRc548MjMxPpojit2ZdGopFzJ8jDSr4iszHrTO1SM1AxPaCM3pRvCAtjw==} + '@napi-rs/canvas-linux-arm64-musl@0.1.53': + resolution: {integrity: sha512-2N41U0X8RnrTKzpTtPv1ozlYkJtPsUdbfF3uP/KEd/BsULGd8Y8ghkGMS6CM+821au4ex0dPrWOOdT9wC1rSqQ==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@napi-rs/canvas-linux-x64-gnu@0.1.52': - resolution: {integrity: sha512-z5sBEw0PVWPH/MIQL8hOR8C3YYVlu8lqtRUcYajigMfXAhbMiNqDWTjuIWGMz3nIydDjZmn8KTxw/D4a0HFPqQ==} + '@napi-rs/canvas-linux-x64-gnu@0.1.53': + resolution: {integrity: sha512-7XjuTvDKCODtf/vMwF43VGDrjfgwYKgS91ggdcX3UrJaBYWyWu/+eqNvNj+zdXSe/0x+YOjf5jG4m8xIXdBMQA==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@napi-rs/canvas-linux-x64-musl@0.1.52': - resolution: {integrity: sha512-G1+JdWFhHLyHhULJS51xTEhB7EL0ZiAUQwQaRi4/w75OOYDQ91O+o4miaxDHiV0hZuxBhHtZU6ftV2Zl3RMguw==} + '@napi-rs/canvas-linux-x64-musl@0.1.53': + resolution: {integrity: sha512-970WEvB8vmj+uxvgdBZ+AGFV7uq9GJhXrqG5PGQ5lWciHX0P0d/OhS2F7TITgFR0LsKDQZ7XQgzMxsYOfwZ0FQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@napi-rs/canvas-win32-x64-msvc@0.1.52': - resolution: {integrity: sha512-hMI626VsCC/wv29qHF78N7TSG+auatOp08DHln0Zdif5y1NJ14NU/rNUhzlTW8Zc6ssw+AMDJ3KKYYWYYg1aoA==} + '@napi-rs/canvas-win32-x64-msvc@0.1.53': + resolution: {integrity: sha512-rLFQCSJaWg/sv54Aap9nAhaodi4Vyb4un50EgW+PNkk8icMziU6KLRKirGBdQr9ZdxnshAPeQXD1g2ArStujKA==} engines: {node: '>= 10'} cpu: [x64] os: [win32] - '@napi-rs/canvas@0.1.52': - resolution: {integrity: sha512-xeW9EghZLDPZuqWJ4l1+eG3ld0i9J7SpV2zlgi34MPt/FE9K2XWGCfnLr0gHGOBkcI3YOVhI13I0HqRAkMPdVw==} + '@napi-rs/canvas@0.1.53': + resolution: {integrity: sha512-XsEZi97+kKykmAiPpY+IpZoHxJY1srqFZp8jDt1/RySzC0kB0iZYt/VMIFqQKpLCARZjD7SOAz2AULtwYlesCA==} engines: {node: '>= 10'} '@ndelangen/get-tarball@3.0.7': resolution: {integrity: sha512-NqGfTZIZpRFef1GoVaShSSRwDC3vde3ThtTeqFdcYd6ipKqnfEVhjK2hUeHjCQUcptyZr2TONqcloFXM+5QBrQ==} - '@nestjs/common@10.3.8': - resolution: {integrity: sha512-P+vPEIvqx2e+fonsYVlFXKvoChyJ8Tq+lfpqdVFqblovHbFr3kZ/nYX0cPs+XuW6bnRT8tz0SSR9XBGU43kJhw==} + '@nestjs/common@10.3.10': + resolution: {integrity: sha512-H8k0jZtxk1IdtErGDmxFRy0PfcOAUg41Prrqpx76DQusGGJjsaovs1zjXVD1rZWaVYchfT1uczJ6L4Kio10VNg==} peerDependencies: class-transformer: '*' class-validator: '*' @@ -3191,8 +3412,8 @@ packages: class-validator: optional: true - '@nestjs/core@10.3.8': - resolution: {integrity: sha512-AxF4tpYLDNn5Wfb3C4bNaaHJ4pREH5FJrSisR2A5zkYpQFORFs0Tc36lOFPMwBTy8Iv2wUwWLUVc5ftBnxEv4w==} + '@nestjs/core@10.3.10': + resolution: {integrity: sha512-ZbQ4jovQyzHtCGCrzK5NdtW1SYO2fHSsgSY1+/9WdruYCUra+JDkWEXgZ4M3Hv480Dl3OXehAmY1wCOojeMyMQ==} peerDependencies: '@nestjs/common': ^10.0.0 '@nestjs/microservices': ^10.0.0 @@ -3208,14 +3429,14 @@ packages: '@nestjs/websockets': optional: true - '@nestjs/platform-express@10.3.8': - resolution: {integrity: sha512-sifLoxgEJvAgbim1UuW6wyScMfkS9SVQRH+lN33N/9ZvZSjO6NSDLOe+wxqsnZkia+QrjFC0qy0ITRAsggfqbg==} + '@nestjs/platform-express@10.3.10': + resolution: {integrity: sha512-wK2ow3CZI2KFqWeEpPmoR300OB6BcBLxARV1EiClJLCj4S1mZsoCmS0YWgpk3j1j6mo0SI8vNLi/cC2iZPEPQA==} peerDependencies: '@nestjs/common': ^10.0.0 '@nestjs/core': ^10.0.0 - '@nestjs/testing@10.3.8': - resolution: {integrity: sha512-hpX9das2TdFTKQ4/2ojhjI6YgXtCfXRKui3A4Qaj54VVzc5+mtK502Jj18Vzji98o9MVS6skmYu+S/UvW3U6Fw==} + '@nestjs/testing@10.3.10': + resolution: {integrity: sha512-i3HAtVQJijxNxJq1k39aelyJlyEIBRONys7IipH/4r8W0J+M1V+y5EKDOyi4j1SdNSb/vmNyWpZ2/ewZjl3kRA==} peerDependencies: '@nestjs/common': ^10.0.0 '@nestjs/core': ^10.0.0 @@ -3227,6 +3448,10 @@ packages: '@nestjs/platform-express': optional: true + '@noble/hashes@1.4.0': + resolution: {integrity: sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==} + engines: {node: '>= 16'} + '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -3270,19 +3495,19 @@ packages: '@open-draft/until@2.1.0': resolution: {integrity: sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==} - '@opentelemetry/api-logs@0.51.1': - resolution: {integrity: sha512-E3skn949Pk1z2XtXu/lxf6QAZpawuTM/IUEXcAzpiUkTd73Hmvw26FiN3cJuTmkpM5hZzHwkomVdtrh/n/zzwA==} + '@opentelemetry/api-logs@0.52.1': + resolution: {integrity: sha512-qnSqB2DQ9TPP96dl8cDubDvrUyWc0/sK81xHTK8eSUspzDM3bsewX903qclQFvVhgStjRWdC5bLb3kQqMkfV5A==} engines: {node: '>=14'} - '@opentelemetry/api@1.8.0': - resolution: {integrity: sha512-I/s6F7yKUDdtMsoBWXJe8Qz40Tui5vsuKCWJEWVL+5q9sSWRzzx6v2KeNsOBEwd94j0eWkpWCH4yB6rZg9Mf0w==} + '@opentelemetry/api@1.9.0': + resolution: {integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==} engines: {node: '>=8.0.0'} - '@opentelemetry/context-async-hooks@1.24.1': - resolution: {integrity: sha512-R5r6DO4kgEOVBxFXhXjwospLQkv+sYxwCfjvoZBe7Zm6KKXAV9kDSJhi/D1BweowdZmO+sdbENLs374gER8hpQ==} + '@opentelemetry/context-async-hooks@1.25.1': + resolution: {integrity: sha512-UW/ge9zjvAEmRWVapOP0qyCvPulWU6cQxGxDbWEFfGOj1VBBZAuOqTo3X6yWmDTD3Xe15ysCZChHncr2xFMIfQ==} engines: {node: '>=14'} peerDependencies: - '@opentelemetry/api': '>=1.0.0 <1.9.0' + '@opentelemetry/api': '>=1.0.0 <1.10.0' '@opentelemetry/core@1.24.1': resolution: {integrity: sha512-wMSGfsdmibI88K9wB498zXY04yThPexo8jvwNNlm542HZB7XrrMRBbAyKJqG8qDRJwIBdBrPMi4V9ZPW/sqrcg==} @@ -3290,86 +3515,98 @@ packages: peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.9.0' - '@opentelemetry/instrumentation-connect@0.36.0': - resolution: {integrity: sha512-k9++bmJZ9zDEs3u3DnKTn2l7QTiNFg3gPx7G9rW0TPnP+xZoBSBTrEcGYBaqflQlrFG23Q58+X1sM2ayWPv5Fg==} + '@opentelemetry/core@1.25.1': + resolution: {integrity: sha512-GeT/l6rBYWVQ4XArluLVB6WWQ8flHbdb6r2FCHC3smtdOAbrJBIv35tpV/yp9bmYUJf+xmZpu9DRTIeJVhFbEQ==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.10.0' + + '@opentelemetry/instrumentation-connect@0.37.0': + resolution: {integrity: sha512-SeQktDIH5rNzjiEiazWiJAIXkmnLOnNV7wwHpahrqE0Ph+Z3heqMfxRtoMtbdJSIYLfcNZYO51AjxZ00IXufdw==} engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation-express@0.39.0': - resolution: {integrity: sha512-AG8U7z7D0JcBu/7dDcwb47UMEzj9/FMiJV2iQZqrsZnxR3FjB9J9oIH2iszJYci2eUdp2WbdvtpD9RV/zmME5A==} + '@opentelemetry/instrumentation-express@0.40.1': + resolution: {integrity: sha512-+RKMvVe2zw3kIXRup9c1jFu3T4d0fs5aKy015TpiMyoCKX1UMu3Z0lfgYtuyiSTANvg5hZnDbWmQmqSPj9VTvg==} engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation-fastify@0.36.1': - resolution: {integrity: sha512-3Nfm43PI0I+3EX+1YbSy6xbDu276R1Dh1tqAk68yd4yirnIh52Kd5B+nJ8CgHA7o3UKakpBjj6vSzi5vNCzJIA==} + '@opentelemetry/instrumentation-fastify@0.37.0': + resolution: {integrity: sha512-WRjwzNZgupSzbEYvo9s+QuHJRqZJjVdNxSEpGBwWK8RKLlHGwGVAu0gcc2gPamJWUJsGqPGvahAPWM18ZkWj6A==} engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation-graphql@0.40.0': - resolution: {integrity: sha512-LVRdEHWACWOczv2imD+mhUrLMxsEjPPi32vIZJT57zygR5aUiA4em8X3aiGOCycgbMWkIu8xOSGSxdx3JmzN+w==} + '@opentelemetry/instrumentation-graphql@0.41.0': + resolution: {integrity: sha512-R/gXeljgIhaRDKquVkKYT5QHPnFouM8ooyePZEP0kqyaVAedtR1V7NfAUJbxfTG5fBQa5wdmLjvu63+tzRXZCA==} engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation-hapi@0.38.0': - resolution: {integrity: sha512-ZcOqEuwuutTDYIjhDIStix22ECblG/i9pHje23QGs4Q4YS4RMaZ5hKCoQJxW88Z4K7T53rQkdISmoXFKDV8xMg==} + '@opentelemetry/instrumentation-hapi@0.39.0': + resolution: {integrity: sha512-ik2nA9Yj2s2ay+aNY+tJsKCsEx6Tsc2g/MK0iWBW5tibwrWKTy1pdVt5sB3kd5Gkimqj23UV5+FH2JFcQLeKug==} engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation-http@0.51.1': - resolution: {integrity: sha512-6b3nZnFFEz/3xZ6w8bVxctPUWIPWiXuPQ725530JgxnN1cvYFd8CJ75PrHZNjynmzSSnqBkN3ef4R9N+RpMh8Q==} + '@opentelemetry/instrumentation-http@0.52.1': + resolution: {integrity: sha512-dG/aevWhaP+7OLv4BQQSEKMJv8GyeOp3Wxl31NHqE8xo9/fYMfEljiZphUHIfyg4gnZ9swMyWjfOQs5GUQe54Q==} engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation-ioredis@0.40.0': - resolution: {integrity: sha512-Jv/fH7KhpWe4KBirsiqeUJIYrsdR2iu2l4nWhfOlRvaZ+zYIiLEzTQR6QhBbyRoAbU4OuYJzjWusOmmpGBnwng==} + '@opentelemetry/instrumentation-ioredis@0.41.0': + resolution: {integrity: sha512-rxiLloU8VyeJGm5j2fZS8ShVdB82n7VNP8wTwfUQqDwRfHCnkzGr+buKoxuhGD91gtwJ91RHkjHA1Eg6RqsUTg==} engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation-koa@0.40.0': - resolution: {integrity: sha512-dJc3H/bKMcgUYcQpLF+1IbmUKus0e5Fnn/+ru/3voIRHwMADT3rFSUcGLWSczkg68BCgz0vFWGDTvPtcWIFr7A==} + '@opentelemetry/instrumentation-koa@0.41.0': + resolution: {integrity: sha512-mbPnDt7ELvpM2S0vixYUsde7122lgegLOJQxx8iJQbB8YHal/xnTh9v7IfArSVzIDo+E+080hxZyUZD4boOWkw==} engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation-mongodb@0.43.0': - resolution: {integrity: sha512-bMKej7Y76QVUD3l55Q9YqizXybHUzF3pujsBFjqbZrRn2WYqtsDtTUlbCK7fvXNPwFInqZ2KhnTqd0gwo8MzaQ==} + '@opentelemetry/instrumentation-mongodb@0.45.0': + resolution: {integrity: sha512-xnZP9+ayeB1JJyNE9cIiwhOJTzNEsRhXVdLgfzmrs48Chhhk026mQdM5CITfyXSCfN73FGAIB8d91+pflJEfWQ==} engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation-mongoose@0.38.1': - resolution: {integrity: sha512-zaeiasdnRjXe6VhYCBMdkmAVh1S5MmXC/0spet+yqoaViGnYst/DOxPvhwg3yT4Yag5crZNWsVXnA538UjP6Ow==} + '@opentelemetry/instrumentation-mongoose@0.39.0': + resolution: {integrity: sha512-J1r66A7zJklPPhMtrFOO7/Ud2p0Pv5u8+r23Cd1JUH6fYPmftNJVsLp2urAt6PHK4jVqpP/YegN8wzjJ2mZNPQ==} engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation-mysql2@0.38.1': - resolution: {integrity: sha512-qkpHMgWSDTYVB1vlZ9sspf7l2wdS5DDq/rbIepDwX5BA0N0068JTQqh0CgAh34tdFqSCnWXIhcyOXC2TtRb0sg==} + '@opentelemetry/instrumentation-mysql2@0.39.0': + resolution: {integrity: sha512-Iypuq2z6TCfriAXCIZjRq8GTFCKhQv5SpXbmI+e60rYdXw8NHtMH4NXcGF0eKTuoCsC59IYSTUvDQYDKReaszA==} engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation-mysql@0.38.1': - resolution: {integrity: sha512-+iBAawUaTfX/HAlvySwozx0C2B6LBfNPXX1W8Z2On1Uva33AGkw2UjL9XgIg1Pj4eLZ9R4EoJ/aFz+Xj4E/7Fw==} + '@opentelemetry/instrumentation-mysql@0.39.0': + resolution: {integrity: sha512-8snHPh83rhrDf31v9Kq0Nf+ts8hdr7NguuszRqZomZBHgE0+UyXZSkXHAAFZoBPPRMGyM68uaFE5hVtFl+wOcA==} engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation-nestjs-core@0.37.1': - resolution: {integrity: sha512-ebYQjHZEmGHWEALwwDGhSQVLBaurFnuLIkZD5igPXrt7ohfF4lc5/4al1LO+vKc0NHk8SJWStuRueT86ISA8Vg==} + '@opentelemetry/instrumentation-nestjs-core@0.38.0': + resolution: {integrity: sha512-M381Df1dM8aqihZz2yK+ugvMFK5vlHG/835dc67Sx2hH4pQEQYDA2PpFPTgc9AYYOydQaj7ClFQunESimjXDgg==} engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation-pg@0.41.0': - resolution: {integrity: sha512-BSlhpivzBD77meQNZY9fS4aKgydA8AJBzv2dqvxXFy/Hq64b7HURgw/ztbmwFeYwdF5raZZUifiiNSMLpOJoSA==} + '@opentelemetry/instrumentation-pg@0.42.0': + resolution: {integrity: sha512-sjgcM8CswYy8zxHgXv4RAZ09DlYhQ+9TdlourUs63Df/ek5RrB1ZbjznqW7PB6c3TyJJmX6AVtPTjAsROovEjA==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation-redis-4@0.40.0': + resolution: {integrity: sha512-0ieQYJb6yl35kXA75LQUPhHtGjtQU9L85KlWa7d4ohBbk/iQKZ3X3CFl5jC5vNMq/GGPB3+w3IxNvALlHtrp7A==} engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': ^1.3.0 @@ -3380,8 +3617,8 @@ packages: peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation@0.51.1': - resolution: {integrity: sha512-JIrvhpgqY6437QIqToyozrUG1h5UhwHkaGK/WAX+fkrpyPtc+RO5FkRtUd9BH0MibabHHvqsnBGKfKVijbmp8w==} + '@opentelemetry/instrumentation@0.52.1': + resolution: {integrity: sha512-uXJbYU/5/MBHjMp1FqrILLRuiJCs3Ofk0MeRDk8g1S1gD47U8X3JnSwcMO1rtRo1x1a7zKaQHaoYu49p/4eSKw==} engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': ^1.3.0 @@ -3396,22 +3633,32 @@ packages: peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.9.0' + '@opentelemetry/resources@1.25.1': + resolution: {integrity: sha512-pkZT+iFYIZsVn6+GzM0kSX+u3MSLCY9md+lIJOoKl/P+gJFfxJte/60Usdp8Ce4rOs8GduUpSPNe1ddGyDT1sQ==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.10.0' + '@opentelemetry/sdk-metrics@1.24.1': resolution: {integrity: sha512-FrAqCbbGao9iKI+Mgh+OsC9+U2YMoXnlDHe06yH7dvavCKzE3S892dGtX54+WhSFVxHR/TMRVJiK/CV93GR0TQ==} engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': '>=1.3.0 <1.9.0' - '@opentelemetry/sdk-trace-base@1.24.1': - resolution: {integrity: sha512-zz+N423IcySgjihl2NfjBf0qw1RWe11XIAWVrTNOSSI6dtSPJiVom2zipFB2AEEtJWpv0Iz6DY6+TjnyTV5pWg==} + '@opentelemetry/sdk-trace-base@1.25.1': + resolution: {integrity: sha512-C8k4hnEbc5FamuZQ92nTOp8X/diCY56XUTnMiv9UTuJitCzaNNHAVsdm5+HLCdI8SLQsLWIrG38tddMxLVoftw==} engines: {node: '>=14'} peerDependencies: - '@opentelemetry/api': '>=1.0.0 <1.9.0' + '@opentelemetry/api': '>=1.0.0 <1.10.0' '@opentelemetry/semantic-conventions@1.24.1': resolution: {integrity: sha512-VkliWlS4/+GHLLW7J/rVBA00uXus1SWvwFvcUDxDwmFxYfg/2VI6ekwdXS28cjI8Qz2ky2BzG8OUHo+WeYIWqw==} engines: {node: '>=14'} + '@opentelemetry/semantic-conventions@1.25.1': + resolution: {integrity: sha512-ZDjMJJQRlyk8A1KZFCc+bCbsyrn1wTwdNt56F7twdfUfnHUZUq77/WfONCj8p72NZOyP7pNTdUWSTYC3GTbuuQ==} + engines: {node: '>=14'} + '@opentelemetry/sql-common@0.40.1': resolution: {integrity: sha512-nSDlnHSqzC3pXn/wZEZVLuAuJ1MYMXPBwtv2qAbCa3847SaHItdE7SzUq/Jtb0KZmh1zfAbNi3AAMjztTT4Ugg==} engines: {node: '>=14'} @@ -3433,31 +3680,171 @@ packages: '@peculiar/asn1-x509@2.3.8': resolution: {integrity: sha512-voKxGfDU1c6r9mKiN5ZUsZWh3Dy1BABvTM3cimf0tztNwyMJPhiXY94eRTgsMQe6ViLfT6EoXxkWVzcm3mFAFw==} - '@peertube/http-signature@1.7.0': - resolution: {integrity: sha512-aGQIwo6/sWtyyqhVK4e1MtxYz4N1X8CNt6SOtCc+Wnczs5S5ONaLHDDR8LYaGn0MgOwvGgXyuZ5sJIfd7iyoUw==} - engines: {node: '>=0.10'} - '@pkgjs/parseargs@0.11.0': resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} - '@prisma/instrumentation@5.14.0': - resolution: {integrity: sha512-DeybWvIZzu/mUsOYP9MVd6AyBj+MP7xIMrcuIn25MX8FiQX39QBnET5KhszTAip/ToctUuDwSJ46QkIoyo3RFA==} + '@prisma/instrumentation@5.16.0': + resolution: {integrity: sha512-MVzNRW2ikWvVNnMIEgQMcwWxpFD+XF2U2h0Qz7MjutRqJxrhWexWV2aSi2OXRaU8UL5wzWw7pnjdKUzYhWauLg==} - '@radix-ui/react-compose-refs@1.0.1': - resolution: {integrity: sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw==} + '@radix-ui/primitive@1.1.0': + resolution: {integrity: sha512-4Z8dn6Upk0qk4P74xBhZ6Hd/w0mPEzOOLxy4xiPXOXqjF7jZS0VAKk7/x/H6FyY2zCkYJqePf1G5KmkmNJ4RBA==} + + '@radix-ui/react-compose-refs@1.1.0': + resolution: {integrity: sha512-b4inOtiaOnYf9KWyO3jAeeCG6FeyfY6ldiEPanbUjWd+xIk5wZeHa8yVwmrJ2vderhu/BQvzCrJI0lHd+wIiqw==} peerDependencies: '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true - '@radix-ui/react-slot@1.0.2': - resolution: {integrity: sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg==} + '@radix-ui/react-context@1.1.0': + resolution: {integrity: sha512-OKrckBy+sMEgYM/sMmqmErVn0kZqrHPJze+Ql3DzYsDDp0hl0L62nx/2122/Bvps1qz645jlcu2tD9lrRSdf8A==} peerDependencies: '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-dialog@1.1.1': + resolution: {integrity: sha512-zysS+iU4YP3STKNS6USvFVqI4qqx8EpiwmT5TuCApVEBca+eRCbONi4EgzfNSuVnOXvC5UPHHMjs8RXO6DH9Bg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-dismissable-layer@1.1.0': + resolution: {integrity: sha512-/UovfmmXGptwGcBQawLzvn2jOfM0t4z3/uKffoBlj724+n3FvBbZ7M0aaBOmkp6pqFYpO4yx8tSVJjx3Fl2jig==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-focus-guards@1.1.0': + resolution: {integrity: sha512-w6XZNUPVv6xCpZUqb/yN9DL6auvpGX3C/ee6Hdi16v2UUy25HV2Q5bcflsiDyT/g5RwbPQ/GIT1vLkeRb+ITBw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-focus-scope@1.1.0': + resolution: {integrity: sha512-200UD8zylvEyL8Bx+z76RJnASR2gRMuxlgFCPAe/Q/679a/r0eK3MBVYMb7vZODZcffZBdob1EGnky78xmVvcA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-id@1.1.0': + resolution: {integrity: sha512-EJUrI8yYh7WOjNOqpoJaf1jlFIH2LvtgAl+YcFqNCa+4hj64ZXmPkAKOFs/ukjz3byN6bdb/AVUqHkI8/uWWMA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-portal@1.1.1': + resolution: {integrity: sha512-A3UtLk85UtqhzFqtoC8Q0KvR2GbXF3mtPgACSazajqq6A41mEQgo53iPzY4i6BwDxlIFqWIhiQ2G729n+2aw/g==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-presence@1.1.0': + resolution: {integrity: sha512-Gq6wuRN/asf9H/E/VzdKoUtT8GC9PQc9z40/vEr0VCJ4u5XvvhWIrSsCB6vD2/cH7ugTdSfYq9fLJCcM00acrQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-primitive@2.0.0': + resolution: {integrity: sha512-ZSpFm0/uHa8zTvKBDjLFWLo8dkr4MBsiDLz0g3gMUwqgLHz9rTaRRGYDgvZPtBJgYCBKXkS9fzmoySgr8CO6Cw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-slot@1.1.0': + resolution: {integrity: sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-callback-ref@1.1.0': + resolution: {integrity: sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-controllable-state@1.1.0': + resolution: {integrity: sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-escape-keydown@1.1.0': + resolution: {integrity: sha512-L7vwWlR1kTTQ3oh7g1O0CBF3YCyyTj8NmhLR+phShpyA50HCfBFKVJTpshm9PzLiKmehsrQzTYTpX9HvmC9rhw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-layout-effect@1.1.0': + resolution: {integrity: sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true @@ -3486,8 +3873,8 @@ packages: rollup: optional: true - '@rollup/plugin-replace@5.0.5': - resolution: {integrity: sha512-rYO4fOi8lMaTg/z5Jb+hKnrHHVn8j2lwkqwyS4kTRhKyWOLf2wST2sWXr4WzWiTcoHTp2sTjqUbqIj2E39slKQ==} + '@rollup/plugin-replace@5.0.7': + resolution: {integrity: sha512-PqxSfuorkHz/SPpyngLyg5GCEkOcee9M1bkxiVDr41Pd61mqP1PLOoDPbpl44SB2mQGKwV/In74gqQmGITOhEQ==} engines: {node: '>=14.0.0'} peerDependencies: rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 @@ -3504,88 +3891,88 @@ packages: rollup: optional: true - '@rollup/rollup-android-arm-eabi@4.17.2': - resolution: {integrity: sha512-NM0jFxY8bB8QLkoKxIQeObCaDlJKewVlIEkuyYKm5An1tdVZ966w2+MPQ2l8LBZLjR+SgyV+nRkTIunzOYBMLQ==} + '@rollup/rollup-android-arm-eabi@4.18.0': + resolution: {integrity: sha512-Tya6xypR10giZV1XzxmH5wr25VcZSncG0pZIjfePT0OVBvqNEurzValetGNarVrGiq66EBVAFn15iYX4w6FKgQ==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.17.2': - resolution: {integrity: sha512-yeX/Usk7daNIVwkq2uGoq2BYJKZY1JfyLTaHO/jaiSwi/lsf8fTFoQW/n6IdAsx5tx+iotu2zCJwz8MxI6D/Bw==} + '@rollup/rollup-android-arm64@4.18.0': + resolution: {integrity: sha512-avCea0RAP03lTsDhEyfy+hpfr85KfyTctMADqHVhLAF3MlIkq83CP8UfAHUssgXTYd+6er6PaAhx/QGv4L1EiA==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.17.2': - resolution: {integrity: sha512-kcMLpE6uCwls023+kknm71ug7MZOrtXo+y5p/tsg6jltpDtgQY1Eq5sGfHcQfb+lfuKwhBmEURDga9N0ol4YPw==} + '@rollup/rollup-darwin-arm64@4.18.0': + resolution: {integrity: sha512-IWfdwU7KDSm07Ty0PuA/W2JYoZ4iTj3TUQjkVsO/6U+4I1jN5lcR71ZEvRh52sDOERdnNhhHU57UITXz5jC1/w==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.17.2': - resolution: {integrity: sha512-AtKwD0VEx0zWkL0ZjixEkp5tbNLzX+FCqGG1SvOu993HnSz4qDI6S4kGzubrEJAljpVkhRSlg5bzpV//E6ysTQ==} + '@rollup/rollup-darwin-x64@4.18.0': + resolution: {integrity: sha512-n2LMsUz7Ynu7DoQrSQkBf8iNrjOGyPLrdSg802vk6XT3FtsgX6JbE8IHRvposskFm9SNxzkLYGSq9QdpLYpRNA==} cpu: [x64] os: [darwin] - '@rollup/rollup-linux-arm-gnueabihf@4.17.2': - resolution: {integrity: sha512-3reX2fUHqN7sffBNqmEyMQVj/CKhIHZd4y631duy0hZqI8Qoqf6lTtmAKvJFYa6bhU95B1D0WgzHkmTg33In0A==} + '@rollup/rollup-linux-arm-gnueabihf@4.18.0': + resolution: {integrity: sha512-C/zbRYRXFjWvz9Z4haRxcTdnkPt1BtCkz+7RtBSuNmKzMzp3ZxdM28Mpccn6pt28/UWUCTXa+b0Mx1k3g6NOMA==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm-musleabihf@4.17.2': - resolution: {integrity: sha512-uSqpsp91mheRgw96xtyAGP9FW5ChctTFEoXP0r5FAzj/3ZRv3Uxjtc7taRQSaQM/q85KEKjKsZuiZM3GyUivRg==} + '@rollup/rollup-linux-arm-musleabihf@4.18.0': + resolution: {integrity: sha512-l3m9ewPgjQSXrUMHg93vt0hYCGnrMOcUpTz6FLtbwljo2HluS4zTXFy2571YQbisTnfTKPZ01u/ukJdQTLGh9A==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm64-gnu@4.17.2': - resolution: {integrity: sha512-EMMPHkiCRtE8Wdk3Qhtciq6BndLtstqZIroHiiGzB3C5LDJmIZcSzVtLRbwuXuUft1Cnv+9fxuDtDxz3k3EW2A==} + '@rollup/rollup-linux-arm64-gnu@4.18.0': + resolution: {integrity: sha512-rJ5D47d8WD7J+7STKdCUAgmQk49xuFrRi9pZkWoRD1UeSMakbcepWXPF8ycChBoAqs1pb2wzvbY6Q33WmN2ftw==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-arm64-musl@4.17.2': - resolution: {integrity: sha512-NMPylUUZ1i0z/xJUIx6VUhISZDRT+uTWpBcjdv0/zkp7b/bQDF+NfnfdzuTiB1G6HTodgoFa93hp0O1xl+/UbA==} + '@rollup/rollup-linux-arm64-musl@4.18.0': + resolution: {integrity: sha512-be6Yx37b24ZwxQ+wOQXXLZqpq4jTckJhtGlWGZs68TgdKXJgw54lUUoFYrg6Zs/kjzAQwEwYbp8JxZVzZLRepQ==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-powerpc64le-gnu@4.17.2': - resolution: {integrity: sha512-T19My13y8uYXPw/L/k0JYaX1fJKFT/PWdXiHr8mTbXWxjVF1t+8Xl31DgBBvEKclw+1b00Chg0hxE2O7bTG7GQ==} + '@rollup/rollup-linux-powerpc64le-gnu@4.18.0': + resolution: {integrity: sha512-hNVMQK+qrA9Todu9+wqrXOHxFiD5YmdEi3paj6vP02Kx1hjd2LLYR2eaN7DsEshg09+9uzWi2W18MJDlG0cxJA==} cpu: [ppc64] os: [linux] - '@rollup/rollup-linux-riscv64-gnu@4.17.2': - resolution: {integrity: sha512-BOaNfthf3X3fOWAB+IJ9kxTgPmMqPPH5f5k2DcCsRrBIbWnaJCgX2ll77dV1TdSy9SaXTR5iDXRL8n7AnoP5cg==} + '@rollup/rollup-linux-riscv64-gnu@4.18.0': + resolution: {integrity: sha512-ROCM7i+m1NfdrsmvwSzoxp9HFtmKGHEqu5NNDiZWQtXLA8S5HBCkVvKAxJ8U+CVctHwV2Gb5VUaK7UAkzhDjlg==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-s390x-gnu@4.17.2': - resolution: {integrity: sha512-W0UP/x7bnn3xN2eYMql2T/+wpASLE5SjObXILTMPUBDB/Fg/FxC+gX4nvCfPBCbNhz51C+HcqQp2qQ4u25ok6g==} + '@rollup/rollup-linux-s390x-gnu@4.18.0': + resolution: {integrity: sha512-0UyyRHyDN42QL+NbqevXIIUnKA47A+45WyasO+y2bGJ1mhQrfrtXUpTxCOrfxCR4esV3/RLYyucGVPiUsO8xjg==} cpu: [s390x] os: [linux] - '@rollup/rollup-linux-x64-gnu@4.17.2': - resolution: {integrity: sha512-Hy7pLwByUOuyaFC6mAr7m+oMC+V7qyifzs/nW2OJfC8H4hbCzOX07Ov0VFk/zP3kBsELWNFi7rJtgbKYsav9QQ==} + '@rollup/rollup-linux-x64-gnu@4.18.0': + resolution: {integrity: sha512-xuglR2rBVHA5UsI8h8UbX4VJ470PtGCf5Vpswh7p2ukaqBGFTnsfzxUBetoWBWymHMxbIG0Cmx7Y9qDZzr648w==} cpu: [x64] os: [linux] - '@rollup/rollup-linux-x64-musl@4.17.2': - resolution: {integrity: sha512-h1+yTWeYbRdAyJ/jMiVw0l6fOOm/0D1vNLui9iPuqgRGnXA0u21gAqOyB5iHjlM9MMfNOm9RHCQ7zLIzT0x11Q==} + '@rollup/rollup-linux-x64-musl@4.18.0': + resolution: {integrity: sha512-LKaqQL9osY/ir2geuLVvRRs+utWUNilzdE90TpyoX0eNqPzWjRm14oMEE+YLve4k/NAqCdPkGYDaDF5Sw+xBfg==} cpu: [x64] os: [linux] - '@rollup/rollup-win32-arm64-msvc@4.17.2': - resolution: {integrity: sha512-tmdtXMfKAjy5+IQsVtDiCfqbynAQE/TQRpWdVataHmhMb9DCoJxp9vLcCBjEQWMiUYxO1QprH/HbY9ragCEFLA==} + '@rollup/rollup-win32-arm64-msvc@4.18.0': + resolution: {integrity: sha512-7J6TkZQFGo9qBKH0pk2cEVSRhJbL6MtfWxth7Y5YmZs57Pi+4x6c2dStAUvaQkHQLnEQv1jzBUW43GvZW8OFqA==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.17.2': - resolution: {integrity: sha512-7II/QCSTAHuE5vdZaQEwJq2ZACkBpQDOmQsE6D6XUbnBHW8IAhm4eTufL6msLJorzrHDFv3CF8oCA/hSIRuZeQ==} + '@rollup/rollup-win32-ia32-msvc@4.18.0': + resolution: {integrity: sha512-Txjh+IxBPbkUB9+SXZMpv+b/vnTEtFyfWZgJ6iyCmt2tdx0OF5WhFowLmnh8ENGNpfUlUZkdI//4IEmhwPieNg==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.17.2': - resolution: {integrity: sha512-TGGO7v7qOq4CYmSBVEYpI1Y5xDuCEnbVC5Vth8mOsW0gDSzxNrVERPc790IGHsrT2dQSimgMr9Ub3Y1Jci5/8w==} + '@rollup/rollup-win32-x64-msvc@4.18.0': + resolution: {integrity: sha512-UOo5FdvOL0+eIVTgS4tIdbW+TtnBLWg1YBCcU2KWM7nuNwRz9bksDX1bekJJCpu25N1DVWaCwnT39dVQxzqS8g==} cpu: [x64] os: [win32] - '@rushstack/node-core-library@4.1.0': - resolution: {integrity: sha512-qz4JFBZJCf1YN5cAXa1dP6Mki/HrsQxc/oYGAGx29dF2cwF2YMxHoly0FBhMw3IEnxo5fMj0boVfoHVBkpkx/w==} + '@rushstack/node-core-library@5.4.1': + resolution: {integrity: sha512-WNnwdS8r9NZ/2K3u29tNoSRldscFa7SxU0RT+82B6Dy2I4Hl2MeCSKm4EXLXPKeNzLGvJ1cqbUhTLviSF8E6iA==} peerDependencies: '@types/node': '*' peerDependenciesMeta: @@ -3595,50 +3982,53 @@ packages: '@rushstack/rig-package@0.5.2': resolution: {integrity: sha512-mUDecIJeH3yYGZs2a48k+pbhM6JYwWlgjs2Ca5f2n1G2/kgdgP9D/07oglEGf6mRyXEnazhEENeYTSNDRCwdqA==} - '@rushstack/terminal@0.10.1': - resolution: {integrity: sha512-C6Vi/m/84IYJTkfzmXr1+W8Wi3MmBjVF/q3za91Gb3VYjKbpALHVxY6FgH625AnDe5Z0Kh4MHKWA3Z7bqgAezA==} + '@rushstack/terminal@0.13.0': + resolution: {integrity: sha512-Ou44Q2s81BqJu3dpYedAX54am9vn245F0HzqVrfJCMQk5pGgoKKOBOjkbfZC9QKcGNaECh6pwH2s5noJt7X6ew==} peerDependencies: '@types/node': '*' peerDependenciesMeta: '@types/node': optional: true - '@rushstack/ts-command-line@4.19.2': - resolution: {integrity: sha512-cqmXXmBEBlzo9WtyUrHtF9e6kl0LvBY7aTSVX4jfnBfXWZQWnPq9JTFPlQZ+L/ZwjZ4HrNwQsOVvhe9oOucZkw==} + '@rushstack/ts-command-line@4.22.0': + resolution: {integrity: sha512-Qj28t6MO3HRgAZ72FDeFsrpdE6wBWxF3VENgvrXh7JF2qIT+CrXiOJIesW80VFZB9QwObSpkB1ilx794fGQg6g==} - '@sentry/core@8.5.0': - resolution: {integrity: sha512-SO3ddBzGdha+Oflp+IKwBxj+7ds1q69OAT3VsypTd+WUFQdI9DIhR92Bjf+QQZCIzUNOi79VWOh3aOi3f6hMnw==} + '@sec-ant/readable-stream@0.4.1': + resolution: {integrity: sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==} + + '@sentry/core@8.13.0': + resolution: {integrity: sha512-N9Qg4ZGxZWp8eb2eUUHVVKgjBLtFIjS805nG92s6yJmkvOpKm6mLtcUaT/iDf3Hta6nG+xRkhbE3r+Z4cbXG8w==} engines: {node: '>=14.18'} - '@sentry/node@8.5.0': - resolution: {integrity: sha512-t9cHAx/wLJYtdVf2XlzKlRJGvwdAp1wjzG0tC4E1Znx74OuUS1cFNo5WrGuOi0/YcWSxiJaxBvtUcsWK86fIgw==} + '@sentry/node@8.13.0': + resolution: {integrity: sha512-OeZ7K90RhyxfwfreerIi4cszzHrPRRH36STJno2+p3sIGbG5VScOccqXzYEOAqHpByxnti4KQN34BLAT2BFOEA==} engines: {node: '>=14.18'} - '@sentry/opentelemetry@8.5.0': - resolution: {integrity: sha512-AbxFUNjuTKQ9ugZrssmGtPxWkBr4USNoP7GjaaGCNwNzvIVYCa+i8dv7BROJiW2lsxNAremULEbh+nbVmhGxDA==} + '@sentry/opentelemetry@8.13.0': + resolution: {integrity: sha512-NYn/HNE/SxFXe8pfnxJknhrrRzYRMHNssCoi5M1CeR5G7F2BGxxVmaGsd8j0WyTCpUS4i97G4vhYtDGxHvWN6w==} engines: {node: '>=14.18'} peerDependencies: - '@opentelemetry/api': ^1.8.0 - '@opentelemetry/core': ^1.24.1 - '@opentelemetry/instrumentation': ^0.51.1 - '@opentelemetry/sdk-trace-base': ^1.23.0 - '@opentelemetry/semantic-conventions': ^1.23.0 + '@opentelemetry/api': ^1.9.0 + '@opentelemetry/core': ^1.25.1 + '@opentelemetry/instrumentation': ^0.52.1 + '@opentelemetry/sdk-trace-base': ^1.25.1 + '@opentelemetry/semantic-conventions': ^1.25.1 - '@sentry/profiling-node@8.5.0': - resolution: {integrity: sha512-nEXJqVNfZWYi4PakQXBZCJeH59UlnBv+zaYftDNUUXttCmzRXpL1ujNm5mJrJHlWjV7tgIFw02HW3nh2yyKOkw==} + '@sentry/profiling-node@8.13.0': + resolution: {integrity: sha512-6qirN71xlMahcm4m25XZLnjQdvs0EaFym/9MdLqcsAa3gAHZtw6h+IDapUzBWRXVOrU1OR5oQdh2tlFthsDtew==} engines: {node: '>=14.18'} hasBin: true - '@sentry/types@8.5.0': - resolution: {integrity: sha512-eDgkSmKI4+XL0QZm4H3j/n1RgnrbnjXZmjj+LsfccRZQwbPu9bWlc8q7Y7Ty1gOsoUpX+TecNLp2a8CRID4KHA==} + '@sentry/types@8.13.0': + resolution: {integrity: sha512-r63s/H5gvQnQM9tTGBXz2xErUbxZALh4e2Lg/1aHj4zIvGLBjA2z5qWsh6TEZYbpmgAyGShLDr6+rWeUVf9yBQ==} engines: {node: '>=14.18'} - '@sentry/utils@8.5.0': - resolution: {integrity: sha512-fdrCzo8SAYiw9JBhkJPqYqJkDXZ/wICzN7+zcXIuzKNhE1hdoFjeKcPnpUI3bKZCG6e3hT1PTYQXhVw7GIZV9w==} + '@sentry/utils@8.13.0': + resolution: {integrity: sha512-PxV0v9VbGWH9zP37P5w2msLUFDr287nYjoY2XVF+RSolyiTs1CQNI5ZMUO3o4MsSac/dpXxjyrZXQd72t/jRYA==} engines: {node: '>=14.18'} - '@shikijs/core@1.4.0': - resolution: {integrity: sha512-CxpKLntAi64h3j+TwWqVIQObPTED0FyXLHTTh3MKXtqiQNn2JGcMQQ362LftDbc9kYbDtrksNMNoVmVXzKFYUQ==} + '@shikijs/core@1.10.0': + resolution: {integrity: sha512-BZcr6FCmPfP6TXaekvujZcnkFmJHZ/Yglu97r/9VjzVndQA56/F4WjUKtJRQUnK59Wi7p/UTAOekMfCJv7jnYg==} '@sideway/address@4.1.4': resolution: {integrity: sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw==} @@ -3667,10 +4057,18 @@ packages: resolution: {integrity: sha512-CX6t4SYQ37lzxicAqsBtxA3OseeoVrh9cSJ5PFYam0GksYlupRfy1A+Q4aYD3zvcfECLc0zO2u+ZnR2UYKvCrw==} engines: {node: '>=14.16'} - '@sindresorhus/is@6.1.0': - resolution: {integrity: sha512-BuvU07zq3tQ/2SIgBsEuxKYDyDjC0n7Zir52bpHy2xnBbW81+po43aLFPLbeV3HRAheFbGud1qgcqSYfhtHMAg==} + '@sindresorhus/is@6.3.1': + resolution: {integrity: sha512-FX4MfcifwJyFOI2lPoX7PQxCqx8BG1HCho7WdiXwpEQx1Ycij0JxkfYtGK7yqNScrZGSlt6RE6sw8QYoH7eKnQ==} engines: {node: '>=16'} + '@sindresorhus/merge-streams@2.3.0': + resolution: {integrity: sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==} + engines: {node: '>=18'} + + '@sindresorhus/merge-streams@4.0.0': + resolution: {integrity: sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==} + engines: {node: '>=18'} + '@sinonjs/commons@2.0.0': resolution: {integrity: sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==} @@ -3689,275 +4087,299 @@ packages: '@sinonjs/text-encoding@0.7.2': resolution: {integrity: sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ==} - '@smithy/abort-controller@2.0.14': - resolution: {integrity: sha512-zXtteuYLWbSXnzI3O6xq3FYvigYZFW8mdytGibfarLL2lxHto9L3ILtGVnVGmFZa7SDh62l39EnU5hesLN87Fw==} - engines: {node: '>=14.0.0'} - '@smithy/abort-controller@2.2.0': resolution: {integrity: sha512-wRlta7GuLWpTqtFfGo+nZyOO1vEvewdNR1R4rTxpC8XU6vG/NDyrFBhwLZsqg1NUoR1noVaXJPC/7ZK47QCySw==} engines: {node: '>=14.0.0'} - '@smithy/chunked-blob-reader-native@2.0.0': - resolution: {integrity: sha512-HM8V2Rp1y8+1343tkZUKZllFhEQPNmpNdgFAncbTsxkZ18/gqjk23XXv3qGyXWp412f3o43ZZ1UZHVcHrpRnCQ==} + '@smithy/abort-controller@3.1.1': + resolution: {integrity: sha512-MBJBiidoe+0cTFhyxT8g+9g7CeVccLM0IOKKUMCNQ1CNMJ/eIfoo0RTfVrXOONEI1UCN1W+zkiHSbzUNE9dZtQ==} + engines: {node: '>=16.0.0'} - '@smithy/chunked-blob-reader@2.0.0': - resolution: {integrity: sha512-k+J4GHJsMSAIQPChGBrjEmGS+WbPonCXesoqP9fynIqjn7rdOThdH8FAeCmokP9mxTYKQAKoHCLPzNlm6gh7Wg==} + '@smithy/chunked-blob-reader-native@3.0.0': + resolution: {integrity: sha512-VDkpCYW+peSuM4zJip5WDfqvg2Mo/e8yxOv3VF1m11y7B8KKMKVFtmZWDe36Fvk8rGuWrPZHHXZ7rR7uM5yWyg==} - '@smithy/config-resolver@2.0.9': - resolution: {integrity: sha512-QBkGPLUqyPmis9Erz8v4q5lo/ErnF7+GD5WZHa6JZiXopUPfaaM+B21n8gzS5xCkIXZmnwzNQhObP9xQPu8oqQ==} - engines: {node: '>=14.0.0'} + '@smithy/chunked-blob-reader@3.0.0': + resolution: {integrity: sha512-sbnURCwjF0gSToGlsBiAmd1lRCmSn72nu9axfJu5lIx6RUEgHu6GwTMbqCdhQSi0Pumcm5vFxsi9XWXb2mTaoA==} - '@smithy/credential-provider-imds@2.0.11': - resolution: {integrity: sha512-uJJs8dnM5iXkn8a2GaKvlKMhcOJ+oJPYqY9gY3CM/EieCVObIDjxUtR/g8lU/k/A+OauA78GzScAfulmFjPOYA==} - engines: {node: '>=14.0.0'} + '@smithy/config-resolver@3.0.4': + resolution: {integrity: sha512-VwiOk7TwXoE7NlNguV/aPq1hFH72tqkHCw8eWXbr2xHspRyyv9DLpLXhq+Ieje+NwoqXrY0xyQjPXdOE6cGcHA==} + engines: {node: '>=16.0.0'} - '@smithy/eventstream-codec@2.0.8': - resolution: {integrity: sha512-onO4to8ujCKn4m5XagReT9Nc6FlNG5vveuvjp1H7AtaG7njdet1LOl6/jmUOkskF2C/w+9jNw3r9Ak+ghOvN0A==} + '@smithy/core@2.2.4': + resolution: {integrity: sha512-qdY3LpMOUyLM/gfjjMQZui+UTNS7kBRDWlvyIhVOql5dn2J3isk9qUTBtQ1CbDH8MTugHis1zu3h4rH+Qmmh4g==} + engines: {node: '>=16.0.0'} - '@smithy/eventstream-serde-browser@2.0.8': - resolution: {integrity: sha512-/RGlkKUnC0sd+xKBKH/2APSBRmVMZTeLOKZMhrZmrO+ONoU+DwyMr/RLJ6WnmBKN+2ebjffM4pcIJTKLNNDD8g==} - engines: {node: '>=14.0.0'} + '@smithy/credential-provider-imds@3.1.3': + resolution: {integrity: sha512-U1Yrv6hx/mRK6k8AncuI6jLUx9rn0VVSd9NPEX6pyYFBfkSkChOc/n4zUb8alHUVg83TbI4OdZVo1X0Zfj3ijA==} + engines: {node: '>=16.0.0'} - '@smithy/eventstream-serde-config-resolver@2.0.8': - resolution: {integrity: sha512-EyAEj258eMUv9zcMvBbqrInh2eHRYuiwQAjXDMxZFCyP+JePzQB6O++3wFwjQeRKMFFgZipNgnEXfReII4+NAw==} - engines: {node: '>=14.0.0'} + '@smithy/eventstream-codec@3.1.2': + resolution: {integrity: sha512-0mBcu49JWt4MXhrhRAlxASNy0IjDRFU+aWNDRal9OtUJvJNiwDuyKMUONSOjLjSCeGwZaE0wOErdqULer8r7yw==} - '@smithy/eventstream-serde-node@2.0.8': - resolution: {integrity: sha512-FMBatSUSKwh6aguKVJokXfJaV8nqsuCkCZHb9MP9zah0ZF+ohbTLeeed7DQGeTVBueVIVWEzIsShPxtxBv7MMQ==} - engines: {node: '>=14.0.0'} + '@smithy/eventstream-serde-browser@3.0.4': + resolution: {integrity: sha512-Eo4anLZX6ltGJTZ5yJMc80gZPYYwBn44g0h7oFq6et+TYr5dUsTpIcDbz2evsOKIZhZ7zBoFWHtBXQ4QQeb5xA==} + engines: {node: '>=16.0.0'} - '@smithy/eventstream-serde-universal@2.0.8': - resolution: {integrity: sha512-6InMXH8BUKoEDa6CAuxR4Gn8Gf2vBfVtjA9A6zDKZClYHT+ANUJS+2EtOBc5wECJJGk4KLn5ajQyrt9MBv5lcw==} - engines: {node: '>=14.0.0'} + '@smithy/eventstream-serde-config-resolver@3.0.3': + resolution: {integrity: sha512-NVTYjOuYpGfrN/VbRQgn31x73KDLfCXCsFdad8DiIc3IcdxL+dYA9zEQPyOP7Fy2QL8CPy2WE4WCUD+ZsLNfaQ==} + engines: {node: '>=16.0.0'} - '@smithy/fetch-http-handler@2.1.4': - resolution: {integrity: sha512-SL24M9W5ERByoXaVicRx+bj9GJVujDnPn+QO7GY7adhY0mPGa6DSF58pVKsgIh4r5Tx/k3SWCPlH4BxxSxA/fQ==} + '@smithy/eventstream-serde-node@3.0.4': + resolution: {integrity: sha512-mjlG0OzGAYuUpdUpflfb9zyLrBGgmQmrobNT8b42ZTsGv/J03+t24uhhtVEKG/b2jFtPIHF74Bq+VUtbzEKOKg==} + engines: {node: '>=16.0.0'} - '@smithy/hash-blob-browser@2.0.8': - resolution: {integrity: sha512-IgvRlBMfg/qLg321a59T1yTdEEbaizLrEVsU3DHj65DAO4lFRMF5f+l7vuV+je6m1G9wSD5GQXLturX8qlGb4g==} + '@smithy/eventstream-serde-universal@3.0.4': + resolution: {integrity: sha512-Od9dv8zh3PgOD7Vj4T3HSuox16n0VG8jJIM2gvKASL6aCtcS8CfHZDWe1Ik3ZXW6xBouU+45Q5wgoliWDZiJ0A==} + engines: {node: '>=16.0.0'} - '@smithy/hash-node@2.0.8': - resolution: {integrity: sha512-yZL/nmxZzjZV5/QX5JWSgXlt0HxuMTwFO89CS++jOMMPiCMZngf6VYmtNdccs8IIIAMmfQeTzwu07XgUE/Zd3Q==} - engines: {node: '>=14.0.0'} + '@smithy/fetch-http-handler@3.2.0': + resolution: {integrity: sha512-vFvDxMrc6sO5Atec8PaISckMcAwsCrRhYxwUylg97bRT2KZoumOF7qk5+6EVUtuM1IG9AJV5aqXnHln9ZdXHpg==} - '@smithy/hash-stream-node@2.0.8': - resolution: {integrity: sha512-82zC6I9ZJycbEZH8TVyXyBx9c2ZIPQDgBvM0x5AFPUl/i1AxwKKX+lwYRnzgkF//cYhIIoJaCfJ9mjSMPRGvCQ==} - engines: {node: '>=14.0.0'} + '@smithy/hash-blob-browser@3.1.2': + resolution: {integrity: sha512-hAbfqN2UbISltakCC2TP0kx4LqXBttEv2MqSPE98gVuDFMf05lU+TpC41QtqGP3Ff5A3GwZMPfKnEy0VmEUpmg==} - '@smithy/invalid-dependency@2.0.8': - resolution: {integrity: sha512-88VOS7W3KzUz/bNRc+Sl/F/CDIasFspEE4G39YZRHIh9YmsXF7GUyVaAKURfMNulTie62ayk6BHC9O0nOBAVgQ==} + '@smithy/hash-node@3.0.3': + resolution: {integrity: sha512-2ctBXpPMG+B3BtWSGNnKELJ7SH9e4TNefJS0cd2eSkOOROeBnnVBnAy9LtJ8tY4vUEoe55N4CNPxzbWvR39iBw==} + engines: {node: '>=16.0.0'} + + '@smithy/hash-stream-node@3.1.2': + resolution: {integrity: sha512-PBgDMeEdDzi6JxKwbfBtwQG9eT9cVwsf0dZzLXoJF4sHKHs5HEo/3lJWpn6jibfJwT34I1EBXpBnZE8AxAft6g==} + engines: {node: '>=16.0.0'} + + '@smithy/invalid-dependency@3.0.3': + resolution: {integrity: sha512-ID1eL/zpDULmHJbflb864k72/SNOZCADRc9i7Exq3RUNJw6raWUSlFEQ+3PX3EYs++bTxZB2dE9mEHTQLv61tw==} '@smithy/is-array-buffer@2.0.0': resolution: {integrity: sha512-z3PjFjMyZNI98JFRJi/U0nGoLWMSJlDjAW4QUX2WNZLas5C0CmVV6LJ01JI0k90l7FvpmixjWxPFmENSClQ7ug==} engines: {node: '>=14.0.0'} - '@smithy/md5-js@2.0.8': - resolution: {integrity: sha512-1VVECXEiuJvjXv+mudiaUFKYwgDLOWz5MTTy8RzbrPiU3GiOb3/o5/urdkYpqmgoMfxdvxxOw/Adjv2dV2q2Yg==} + '@smithy/is-array-buffer@3.0.0': + resolution: {integrity: sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==} + engines: {node: '>=16.0.0'} - '@smithy/middleware-content-length@2.0.10': - resolution: {integrity: sha512-EGSbysyA4jH0p3xI6G0jdXoj9Iz9GUnAta6aEaHtXm3wVWtenRf80y2TeVvNkVSr5jwKOdSCjKIRI2l1A/oZLA==} - engines: {node: '>=14.0.0'} + '@smithy/md5-js@3.0.3': + resolution: {integrity: sha512-O/SAkGVwpWmelpj/8yDtsaVe6sINHLB1q8YE/+ZQbDxIw3SRLbTZuRaI10K12sVoENdnHqzPp5i3/H+BcZ3m3Q==} - '@smithy/middleware-endpoint@2.0.8': - resolution: {integrity: sha512-yOpogfG2d2V0cbJdAJ6GLAWkNOc9pVsL5hZUfXcxJu408N3CUCsXzIAFF6+70ZKSE+lCfG3GFErcSXv/UfUbjw==} - engines: {node: '>=14.0.0'} + '@smithy/middleware-content-length@3.0.3': + resolution: {integrity: sha512-Dbz2bzexReYIQDWMr+gZhpwBetNXzbhnEMhYKA6urqmojO14CsXjnsoPYO8UL/xxcawn8ZsuVU61ElkLSltIUQ==} + engines: {node: '>=16.0.0'} - '@smithy/middleware-retry@2.0.11': - resolution: {integrity: sha512-pknfokumZ+wvBERSuKAI2vVr+aK3ZgPiWRg6+0ZG4kKJogBRpPmDGWw+Jht0izS9ZaEbIobNzueIb4wD33JJVg==} - engines: {node: '>=14.0.0'} + '@smithy/middleware-endpoint@3.0.4': + resolution: {integrity: sha512-whUJMEPwl3ANIbXjBXZVdJNgfV2ZU8ayln7xUM47rXL2txuenI7jQ/VFFwCzy5lCmXScjp6zYtptW5Evud8e9g==} + engines: {node: '>=16.0.0'} - '@smithy/middleware-serde@2.0.8': - resolution: {integrity: sha512-Is0sm+LiNlgsc0QpstDzifugzL9ehno1wXp109GgBgpnKTK3j+KphiparBDI4hWTtH9/7OUsxuspNqai2yyhcg==} - engines: {node: '>=14.0.0'} + '@smithy/middleware-retry@3.0.7': + resolution: {integrity: sha512-f5q7Y09G+2h5ivkSx5CHvlAT4qRR3jBFEsfXyQ9nFNiWQlr8c48blnu5cmbTQ+p1xmIO14UXzKoF8d7Tm0Gsjw==} + engines: {node: '>=16.0.0'} - '@smithy/middleware-stack@2.0.1': - resolution: {integrity: sha512-UexsfY6/oQZRjTQL56s9AKtMcR60tBNibSgNYX1I2WXaUaXg97W9JCkFyth85TzBWKDBTyhLfenrukS/kyu54A==} - engines: {node: '>=14.0.0'} + '@smithy/middleware-serde@3.0.3': + resolution: {integrity: sha512-puUbyJQBcg9eSErFXjKNiGILJGtiqmuuNKEYNYfUD57fUl4i9+mfmThtQhvFXU0hCVG0iEJhvQUipUf+/SsFdA==} + engines: {node: '>=16.0.0'} - '@smithy/node-config-provider@2.0.11': - resolution: {integrity: sha512-CaR1dciSSGKttjhcefpytYjsfI/Yd5mqL8am4wfmyFCDxSiPsvnEWHl8UjM/RbcAjX0klt+CeIKPSHEc0wGvJA==} - engines: {node: '>=14.0.0'} + '@smithy/middleware-stack@3.0.3': + resolution: {integrity: sha512-r4klY9nFudB0r9UdSMaGSyjyQK5adUyPnQN/ZM6M75phTxOdnc/AhpvGD1fQUvgmqjQEBGCwpnPbDm8pH5PapA==} + engines: {node: '>=16.0.0'} + + '@smithy/node-config-provider@3.1.3': + resolution: {integrity: sha512-rxdpAZczzholz6CYZxtqDu/aKTxATD5DAUDVj7HoEulq+pDSQVWzbg0btZDlxeFfa6bb2b5tUvgdX5+k8jUqcg==} + engines: {node: '>=16.0.0'} '@smithy/node-http-handler@2.5.0': resolution: {integrity: sha512-mVGyPBzkkGQsPoxQUbxlEfRjrj6FPyA3u3u2VXGr9hT8wilsoQdZdvKpMBFMB8Crfhv5dNkKHIW0Yyuc7eABqA==} engines: {node: '>=14.0.0'} - '@smithy/property-provider@2.0.9': - resolution: {integrity: sha512-25pPZ8f8DeRwYI5wbPRZaoMoR+3vrw8DwbA0TjP+GsdiB2KxScndr4HQehiJ5+WJ0giOTWhLz0bd+7Djv1qpUQ==} - engines: {node: '>=14.0.0'} + '@smithy/node-http-handler@3.1.1': + resolution: {integrity: sha512-L71NLyPeP450r2J/mfu1jMc//Z1YnqJt2eSNw7uhiItaONnBLDA68J5jgxq8+MBDsYnFwNAIc7dBG1ImiWBiwg==} + engines: {node: '>=16.0.0'} - '@smithy/protocol-http@3.0.10': - resolution: {integrity: sha512-6+tjNk7rXW7YTeGo9qwxXj/2BFpJTe37kTj3EnZCoX/nH+NP/WLA7O83fz8XhkGqsaAhLUPo/bB12vvd47nsmg==} - engines: {node: '>=14.0.0'} + '@smithy/property-provider@3.1.3': + resolution: {integrity: sha512-zahyOVR9Q4PEoguJ/NrFP4O7SMAfYO1HLhB18M+q+Z4KFd4V2obiMnlVoUFzFLSPeVt1POyNWneHHrZaTMoc/g==} + engines: {node: '>=16.0.0'} '@smithy/protocol-http@3.3.0': resolution: {integrity: sha512-Xy5XK1AFWW2nlY/biWZXu6/krgbaf2dg0q492D8M5qthsnU2H+UgFeZLbM76FnH7s6RO/xhQRkj+T6KBO3JzgQ==} engines: {node: '>=14.0.0'} - '@smithy/querystring-builder@2.0.14': - resolution: {integrity: sha512-lQ4pm9vTv9nIhl5jt6uVMPludr6syE2FyJmHsIJJuOD7QPIJnrf9HhUGf1iHh9KJ4CUv21tpOU3X6s0rB6uJ0g==} - engines: {node: '>=14.0.0'} + '@smithy/protocol-http@4.0.3': + resolution: {integrity: sha512-x5jmrCWwQlx+Zv4jAtc33ijJ+vqqYN+c/ZkrnpvEe/uDas7AT7A/4Rc2CdfxgWv4WFGmEqODIrrUToPN6DDkGw==} + engines: {node: '>=16.0.0'} '@smithy/querystring-builder@2.2.0': resolution: {integrity: sha512-L1kSeviUWL+emq3CUVSgdogoM/D9QMFaqxL/dd0X7PCNWmPXqt+ExtrBjqT0V7HLN03Vs9SuiLrG3zy3JGnE5A==} engines: {node: '>=14.0.0'} - '@smithy/querystring-parser@2.0.8': - resolution: {integrity: sha512-ArbanNuR7O/MmTd90ZqhDqGOPPDYmxx3huHxD+R3cuCnazcK/1tGQA+SnnR5307T7ZRb5WTpB6qBggERuibVSA==} - engines: {node: '>=14.0.0'} + '@smithy/querystring-builder@3.0.3': + resolution: {integrity: sha512-vyWckeUeesFKzCDaRwWLUA1Xym9McaA6XpFfAK5qI9DKJ4M33ooQGqvM4J+LalH4u/Dq9nFiC8U6Qn1qi0+9zw==} + engines: {node: '>=16.0.0'} - '@smithy/service-error-classification@2.0.1': - resolution: {integrity: sha512-QHa9+t+v4s0cMuDCcbjIJN67mNZ42/+fc3jKe8P6ZMPXZl5ksKk6a8vhZ/m494GZng5eFTc3OePv+NF9cG83yg==} - engines: {node: '>=14.0.0'} + '@smithy/querystring-parser@3.0.3': + resolution: {integrity: sha512-zahM1lQv2YjmznnfQsWbYojFe55l0SLG/988brlLv1i8z3dubloLF+75ATRsqPBboUXsW6I9CPGE5rQgLfY0vQ==} + engines: {node: '>=16.0.0'} - '@smithy/shared-ini-file-loader@2.0.10': - resolution: {integrity: sha512-jWASteSezRKohJ7GdA7pHDvmr7Q7tw3b5mu3xLHIkZy/ICftJ+O7aqNaF8wklhI7UNFoQ7flFRM3Rd0KA+1BbQ==} - engines: {node: '>=14.0.0'} + '@smithy/service-error-classification@3.0.3': + resolution: {integrity: sha512-Jn39sSl8cim/VlkLsUhRFq/dKDnRUFlfRkvhOJaUbLBXUsLRLNf9WaxDv/z9BjuQ3A6k/qE8af1lsqcwm7+DaQ==} + engines: {node: '>=16.0.0'} - '@smithy/signature-v4@2.0.5': - resolution: {integrity: sha512-ABIzXmUDXK4n2c9cXjQLELgH2RdtABpYKT+U131e2I6RbCypFZmxIHmIBufJzU2kdMCQ3+thBGDWorAITFW04A==} - engines: {node: '>=14.0.0'} + '@smithy/shared-ini-file-loader@3.1.3': + resolution: {integrity: sha512-Z8Y3+08vgoDgl4HENqNnnzSISAaGrF2RoKupoC47u2wiMp+Z8P/8mDh1CL8+8ujfi2U5naNvopSBmP/BUj8b5w==} + engines: {node: '>=16.0.0'} - '@smithy/smithy-client@2.1.5': - resolution: {integrity: sha512-7S865uKzsxApM8W8Q6zkij7tcUFgaG8PuADMFdMt1yL/ku3d0+s6Zwrg3N7iXCPM08Gu/mf0BIfTXIu/9i450Q==} - engines: {node: '>=14.0.0'} + '@smithy/signature-v4@3.1.2': + resolution: {integrity: sha512-3BcPylEsYtD0esM4Hoyml/+s7WP2LFhcM3J2AGdcL2vx9O60TtfpDOL72gjb4lU8NeRPeKAwR77YNyyGvMbuEA==} + engines: {node: '>=16.0.0'} + + '@smithy/smithy-client@3.1.5': + resolution: {integrity: sha512-x9bL9Mx2CT2P1OiUlHM+ZNpbVU6TgT32f9CmTRzqIHA7M4vYrROCWEoC3o4xHNJASoGd4Opos3cXYPgh+/m4Ww==} + engines: {node: '>=16.0.0'} '@smithy/types@2.12.0': resolution: {integrity: sha512-QwYgloJ0sVNBeBuBs65cIkTbfzV/Q6ZNPCJ99EICFEdJYG50nGIY/uYXp+TbsdJReIuPr0a0kXmCvren3MbRRw==} engines: {node: '>=14.0.0'} - '@smithy/types@2.6.0': - resolution: {integrity: sha512-PgqxJq2IcdMF9iAasxcqZqqoOXBHufEfmbEUdN1pmJrJltT42b0Sc8UiYSWWzKkciIp9/mZDpzYi4qYG1qqg6g==} - engines: {node: '>=14.0.0'} + '@smithy/types@3.3.0': + resolution: {integrity: sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==} + engines: {node: '>=16.0.0'} - '@smithy/url-parser@2.0.8': - resolution: {integrity: sha512-wQw7j004ScCrBRJ+oNPXlLE9mtofxyadSZ9D8ov/rHkyurS7z1HTNuyaGRj6OvKsEk0SVQsuY0C9+EfM75XTkw==} + '@smithy/url-parser@3.0.3': + resolution: {integrity: sha512-pw3VtZtX2rg+s6HMs6/+u9+hu6oY6U7IohGhVNnjbgKy86wcIsSZwgHrFR+t67Uyxvp4Xz3p3kGXXIpTNisq8A==} - '@smithy/util-base64@2.0.0': - resolution: {integrity: sha512-Zb1E4xx+m5Lud8bbeYi5FkcMJMnn+1WUnJF3qD7rAdXpaL7UjkFQLdmW5fHadoKbdHpwH9vSR8EyTJFHJs++tA==} - engines: {node: '>=14.0.0'} + '@smithy/util-base64@3.0.0': + resolution: {integrity: sha512-Kxvoh5Qtt0CDsfajiZOCpJxgtPHXOKwmM+Zy4waD43UoEMA+qPxxa98aE/7ZhdnBFZFXMOiBR5xbcaMhLtznQQ==} + engines: {node: '>=16.0.0'} - '@smithy/util-body-length-browser@2.0.0': - resolution: {integrity: sha512-JdDuS4ircJt+FDnaQj88TzZY3+njZ6O+D3uakS32f2VNnDo3vyEuNdBOh/oFd8Df1zSZOuH1HEChk2AOYDezZg==} + '@smithy/util-body-length-browser@3.0.0': + resolution: {integrity: sha512-cbjJs2A1mLYmqmyVl80uoLTJhAcfzMOyPgjwAYusWKMdLeNtzmMz9YxNl3/jRLoxSS3wkqkf0jwNdtXWtyEBaQ==} - '@smithy/util-body-length-node@2.1.0': - resolution: {integrity: sha512-/li0/kj/y3fQ3vyzn36NTLGmUwAICb7Jbe/CsWCktW363gh1MOcpEcSO3mJ344Gv2dqz8YJCLQpb6hju/0qOWw==} - engines: {node: '>=14.0.0'} + '@smithy/util-body-length-node@3.0.0': + resolution: {integrity: sha512-Tj7pZ4bUloNUP6PzwhN7K386tmSmEET9QtQg0TgdNOnxhZvCssHji+oZTUIuzxECRfG8rdm2PMw2WCFs6eIYkA==} + engines: {node: '>=16.0.0'} '@smithy/util-buffer-from@2.0.0': resolution: {integrity: sha512-/YNnLoHsR+4W4Vf2wL5lGv0ksg8Bmk3GEGxn2vEQt52AQaPSCuaO5PM5VM7lP1K9qHRKHwrPGktqVoAHKWHxzw==} engines: {node: '>=14.0.0'} - '@smithy/util-config-provider@2.0.0': - resolution: {integrity: sha512-xCQ6UapcIWKxXHEU4Mcs2s7LcFQRiU3XEluM2WcCjjBtQkUN71Tb+ydGmJFPxMUrW/GWMgQEEGipLym4XG0jZg==} - engines: {node: '>=14.0.0'} + '@smithy/util-buffer-from@3.0.0': + resolution: {integrity: sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==} + engines: {node: '>=16.0.0'} - '@smithy/util-defaults-mode-browser@2.0.9': - resolution: {integrity: sha512-JONLJVQWT8165XoSV36ERn3SVlZLJJ4D6IeGsCSePv65Uxa93pzSLE0UMSR9Jwm4zix7rst9AS8W5QIypZWP8Q==} + '@smithy/util-config-provider@3.0.0': + resolution: {integrity: sha512-pbjk4s0fwq3Di/ANL+rCvJMKM5bzAQdE5S/6RL5NXgMExFAi6UgQMPOm5yPaIWPpr+EOXKXRonJ3FoxKf4mCJQ==} + engines: {node: '>=16.0.0'} + + '@smithy/util-defaults-mode-browser@3.0.7': + resolution: {integrity: sha512-Q2txLyvQyGfmjsaDbVV7Sg8psefpFcrnlGapDzXGFRPFKRBeEg6OvFK8FljqjeHSaCZ6/UuzQExUPqBR/2qlDA==} engines: {node: '>= 10.0.0'} - '@smithy/util-defaults-mode-node@2.0.11': - resolution: {integrity: sha512-tmqjNsfj+bgZN6jXBe6efZnukzILA7BUytHkzqikuRLNtR+0VVchQHvawD0w6vManh76rO81ydhioe7i4oBzuA==} + '@smithy/util-defaults-mode-node@3.0.7': + resolution: {integrity: sha512-F4Qcj1fG6MGi2BSWCslfsMSwllws/WzYONBGtLybyY+halAcXdWhcew+mej8M5SKd5hqPYp4f7b+ABQEaeytgg==} engines: {node: '>= 10.0.0'} - '@smithy/util-hex-encoding@2.0.0': - resolution: {integrity: sha512-c5xY+NUnFqG6d7HFh1IFfrm3mGl29lC+vF+geHv4ToiuJCBmIfzx6IeHLg+OgRdPFKDXIw6pvi+p3CsscaMcMA==} - engines: {node: '>=14.0.0'} + '@smithy/util-endpoints@2.0.4': + resolution: {integrity: sha512-ZAtNf+vXAsgzgRutDDiklU09ZzZiiV/nATyqde4Um4priTmasDH+eLpp3tspL0hS2dEootyFMhu1Y6Y+tzpWBQ==} + engines: {node: '>=16.0.0'} - '@smithy/util-middleware@2.0.1': - resolution: {integrity: sha512-LnsBMi0Mg3gfz/TpNGLv2Jjcz2ra1OX5HR/4IaCepIYmtPQzqMWDdhX/XTW1LS8OZ0xbQuyQPcHkQ+2XkhWOVQ==} - engines: {node: '>=14.0.0'} + '@smithy/util-hex-encoding@3.0.0': + resolution: {integrity: sha512-eFndh1WEK5YMUYvy3lPlVmYY/fZcQE1D8oSf41Id2vCeIkKJXPcYDCZD+4+xViI6b1XSd7tE+s5AmXzz5ilabQ==} + engines: {node: '>=16.0.0'} - '@smithy/util-retry@2.0.1': - resolution: {integrity: sha512-naj4X0IafJ9yJnVJ58QgSMkCNLjyQOnyrnKh/T0f+0UOUxJiT8vuFn/hS7B/pNqbo2STY7PyJ4J4f+5YqxwNtA==} - engines: {node: '>= 14.0.0'} + '@smithy/util-middleware@3.0.3': + resolution: {integrity: sha512-l+StyYYK/eO3DlVPbU+4Bi06Jjal+PFLSMmlWM1BEwyLxZ3aKkf1ROnoIakfaA7mC6uw3ny7JBkau4Yc+5zfWw==} + engines: {node: '>=16.0.0'} - '@smithy/util-stream@2.0.11': - resolution: {integrity: sha512-2MeWfqSpZKdmEJ+tH8CJQSgzLWhH5cmdE24X7JB0hiamXrOmswWGGuPvyj/9sQCTclo57pNxLR2p7KrP8Ahiyg==} - engines: {node: '>=14.0.0'} + '@smithy/util-retry@3.0.3': + resolution: {integrity: sha512-AFw+hjpbtVApzpNDhbjNG5NA3kyoMs7vx0gsgmlJF4s+yz1Zlepde7J58zpIRIsdjc+emhpAITxA88qLkPF26w==} + engines: {node: '>=16.0.0'} - '@smithy/util-uri-escape@2.0.0': - resolution: {integrity: sha512-ebkxsqinSdEooQduuk9CbKcI+wheijxEb3utGXkCoYQkJnwTnLbH1JXGimJtUkQwNQbsbuYwG2+aFVyZf5TLaw==} - engines: {node: '>=14.0.0'} + '@smithy/util-stream@3.0.5': + resolution: {integrity: sha512-xC3L5PKMAT/Bh8fmHNXP9sdQ4+4aKVUU3EEJ2CF/lLk7R+wtMJM+v/1B4en7jO++Wa5spGzFDBCl0QxgbUc5Ug==} + engines: {node: '>=16.0.0'} '@smithy/util-uri-escape@2.2.0': resolution: {integrity: sha512-jtmJMyt1xMD/d8OtbVJ2gFZOSKc+ueYJZPW20ULW1GOp/q/YIM0wNh+u8ZFao9UaIGz4WoPW8hC64qlWLIfoDA==} engines: {node: '>=14.0.0'} + '@smithy/util-uri-escape@3.0.0': + resolution: {integrity: sha512-LqR7qYLgZTD7nWLBecUi4aqolw8Mhza9ArpNEQ881MJJIU2sE5iHCK6TdyqqzcDLy0OPe10IY4T8ctVdtynubg==} + engines: {node: '>=16.0.0'} + '@smithy/util-utf8@2.0.0': resolution: {integrity: sha512-rctU1VkziY84n5OXe3bPNpKR001ZCME2JCaBBFgtiM2hfKbHFudc/BkMuPab8hRbLd0j3vbnBTTZ1igBf0wgiQ==} engines: {node: '>=14.0.0'} - '@smithy/util-waiter@2.0.8': - resolution: {integrity: sha512-t9yaoofNhdEhNlyDeV5al/JJEFJ62HIQBGktgCUE63MvKn6imnbkh1qISsYMyMYVLwhWCpZ3Xa3R1LA+SnWcng==} - engines: {node: '>=14.0.0'} + '@smithy/util-utf8@3.0.0': + resolution: {integrity: sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==} + engines: {node: '>=16.0.0'} + + '@smithy/util-waiter@3.1.2': + resolution: {integrity: sha512-4pP0EV3iTsexDx+8PPGAKCQpd/6hsQBaQhqWzU4hqKPHN5epPsxKbvUTIiYIHTxaKt6/kEaqPBpu/ufvfbrRzw==} + engines: {node: '>=16.0.0'} '@sqltools/formatter@1.2.5': resolution: {integrity: sha512-Uy0+khmZqUrUGm5dmMqVlnvufZRSK0FbYzVgp0UMstm+F5+W2/jnEEQyc9vo1ZR/E5ZI/B1WjjoTqBqwJL6Krw==} - '@storybook/addon-actions@8.0.9': - resolution: {integrity: sha512-+I3VTvlKdj8puHeS2tyaOVv9syDiNLneVZbTfqN+UDOK2i42NwvZr8PVwjTzMlEj9eePJdCZgiipz55xwts5bw==} + '@storybook/addon-actions@8.1.11': + resolution: {integrity: sha512-jqYXgBgOVInStOCk//AA+dGkrfN8R7rDXA4lyu82zM59kvICtG9iqgmkSRDn0Z3zUkM+lIHZGoz0aLVQ8pxsgw==} - '@storybook/addon-backgrounds@8.0.9': - resolution: {integrity: sha512-pCDecACrVyxPaJKEWS0sHsRb8xw+IPCSxDM1TkjaAQ6zZ468A/dcUnqW+LVK8bSXgQwWzn23wqnqPFSy5yptuQ==} + '@storybook/addon-backgrounds@8.1.11': + resolution: {integrity: sha512-naGf1ovmsU2pSWb270yRO1IidnO+0YCZ5Tcb8I4rPhZ0vsdXNURYKS1LPSk1OZkvaUXdeB4Im9HhHfUBJOW9oQ==} - '@storybook/addon-controls@8.0.9': - resolution: {integrity: sha512-wWdmd62UP/sfPm8M7aJjEA+kEXTUIR/QsYi9PoYBhBZcXiikZ4kNan7oD7GfsnzGGKHrBVfwQhO+TqaENGYytA==} + '@storybook/addon-controls@8.1.11': + resolution: {integrity: sha512-q/Vt4meNVlFlBWIMCJhx6r+bqiiYocCta2RoUK5nyIZUiLzHncKHX6JnCU36EmJzRyah9zkwjfCb2G1r9cjnoQ==} - '@storybook/addon-docs@8.0.9': - resolution: {integrity: sha512-x7hX7UuzJtClu6XwU3SfpyFhuckVcgqgD6BU6Ihxl0zs+i4xp6iKVXYSnHFMRM1sgoeT8TjPxab35Ke8w8BVRw==} + '@storybook/addon-docs@8.1.11': + resolution: {integrity: sha512-69dv+CE4R5wFU7xnJmhuyEbLN2PEVDV3N/BbgJqeucIYPmm6zDV83Q66teCHKYtRln3BFUqPH5mxsjiHobxfJQ==} - '@storybook/addon-essentials@8.0.9': - resolution: {integrity: sha512-mwAgdfrOsTuTDcagvM7veBh+iayZIWmKOazzkhrIWbhYcrXOsweigD2UOVeHgAiAzJK49znr4FXTCKcE1hOWcw==} + '@storybook/addon-essentials@8.1.11': + resolution: {integrity: sha512-uRTpcIZQnflML8H+2onicUNIIssKfuviW8Lyrs/KFwSZ1rMcYzhwzCNbGlIbAv04tgHe5NqEyNhb+DVQcZQBzg==} - '@storybook/addon-highlight@8.0.9': - resolution: {integrity: sha512-vaRHGDbx7dpNpQECAHk5wczlZO3ntstprGlqnZt0o7ylz6xB5+pTQwTuIFty0hwKv+3TPcskzzifATUyEOEmyg==} + '@storybook/addon-highlight@8.1.11': + resolution: {integrity: sha512-Iu8FCAd4ETsB6QF4xDE/OLLZY3HOFopuLM5KE0f58jnccF5zAVGr1Rj/54p6TeK0PEou0tLRPFuZs+LPlEzrSw==} - '@storybook/addon-interactions@8.0.9': - resolution: {integrity: sha512-AMIdNcyM6DDAWvMitBJMqp1iPZND8AXB4QT4VZHGMKG2ngHNKktriEKpTfcRkfKPGTJs9T+71dWfm6/R4tticw==} + '@storybook/addon-interactions@8.1.11': + resolution: {integrity: sha512-nkc01z61mYM1kxf0ncBQLlFnnwW4RAVPfRSxK9BdbFN3AAvFiHCwVZdn71mi+C3L8oTqYR6o32e0RlXk+AjhHA==} - '@storybook/addon-links@8.0.9': - resolution: {integrity: sha512-FVt+AdW3JFSqbJzkKiqKsMRWqHXqEvCBqFs7lNfk3OW0w0jfv1iREtrxE0dVdJoUFQC9V/2Im/EpJ7UB3C2bNQ==} + '@storybook/addon-links@8.1.11': + resolution: {integrity: sha512-HlV2RQSrZyi+55W1B1a9eWNuJdNpWx0g3j7s2arNlNmbd6/kfWAp84axBstI1tL0nW4svut7bWlCsMSOIden+A==} peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta peerDependenciesMeta: react: optional: true - '@storybook/addon-mdx-gfm@8.0.9': - resolution: {integrity: sha512-AoEx+OGKANtVZgKyWKrQhGpMpDuc2S7PnOlNLUiDYzmj8ABAGPmEJmqeb/VHVgqLQSjhOW1fMsQ4fYsecvMxTQ==} + '@storybook/addon-mdx-gfm@8.1.11': + resolution: {integrity: sha512-0/4Xaisvmoi26iK1ezTOB9dN2b0JbgWKzO2PO6att2Jh7lplLCf1QeoE8Y4SgCh0brage+mA8mKI8NrT7d18pg==} - '@storybook/addon-measure@8.0.9': - resolution: {integrity: sha512-91svOOGEXmGG4USglwXLE3wtlUVgtbKJVxTKX7xRI+AC5JEEaKByVzP17/X8Qn/8HilUL7AfSQ0kCoqtPSJ5cA==} + '@storybook/addon-measure@8.1.11': + resolution: {integrity: sha512-LkQD3SiLWaWt53aLB3EnmhD9Im8EOO+HKSUE+XGnIJRUcHHRqHfvDkN9KX7T1DCWbfRE5WzMHF5o23b3UiAANw==} - '@storybook/addon-outline@8.0.9': - resolution: {integrity: sha512-fQ+jm356TgUnz81IxsC99/aOesbLw3N5OQRJpo/A6kqbLMzlq3ybVzuXYCKC3f0ArgQRNh4NoMeJBMRFMtaWRw==} + '@storybook/addon-outline@8.1.11': + resolution: {integrity: sha512-vco3RLVjkcS25dNtj1lxmjq4fC0Nq08KNLMS5cbNPVJWNTuSUi/2EthSTQQCdpfMV/p6u+D5uF20A9Pl0xJFXw==} - '@storybook/addon-storysource@8.0.9': - resolution: {integrity: sha512-5m3K2Rs4fQtKtqwrq4CDS1jK2wzWOlnxhE2ArX5XTWytb1am65CEPxfYTEQkvZH9oPGwX3cXytPCziynqysFMQ==} + '@storybook/addon-storysource@8.1.11': + resolution: {integrity: sha512-b2K3+ZzfANDTTeN1jnqNgAQ5ZIhnhIAv89gC/36cOhSK5NLyKmyVKLGQmR3fVqX3URpnz9xccst2JNXopvtccw==} - '@storybook/addon-toolbars@8.0.9': - resolution: {integrity: sha512-nNSBnnBOhQ+EJwkrIkK4ZBYPcozNmEH770CZ/6NK85SUJ6WEBZapE6ru33jIUokFGEvlOlNCeai0GUc++cQP8w==} + '@storybook/addon-toolbars@8.1.11': + resolution: {integrity: sha512-reIKB0+JTiP+GNzynlDcRf4xmv9+j/DQ94qiXl2ZG5+ufKilH8DiRZpVA/i0x+4+TxdGdOJr1/pOf8tAmhNEoQ==} - '@storybook/addon-viewport@8.0.9': - resolution: {integrity: sha512-Ao4+D56cO7biaw+iTlMU1FBec1idX0cmdosDeCFZin06MSawcPkeBlRBeruaSQYdLes8TBMdZPFgfuqI5yIk6g==} + '@storybook/addon-viewport@8.1.11': + resolution: {integrity: sha512-qk4IcGnAgiAUQxt8l5PIQ293Za+w6wxlJQIpxr7+QM8OVkADPzXY0MmQfYWU9EQplrxAC2MSx3/C1gZeq+MDOQ==} - '@storybook/blocks@8.0.9': - resolution: {integrity: sha512-F2zSrfSwzTFN7qW3zB80tG+EXtmfmCDC6Ird0F7tolszb6tOqJcAcBOwQbE2O0wI63sLu21qxzXgaKBMkiWvJg==} + '@storybook/blocks@8.1.11': + resolution: {integrity: sha512-eMed7PpL/hAVM6tBS7h70bEAyzbiSU9I/kye4jZ7DkCbAsrX6OKmC7pcHSDn712WTcf3vVqxy5jOKUmOXpc0eg==} peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta peerDependenciesMeta: react: optional: true react-dom: optional: true - '@storybook/builder-manager@8.0.9': - resolution: {integrity: sha512-/PxDwZIfMc/PSRZcasb6SIdGr3azIlenzx7dBF7Imt8i4jLHiAf1t00GvghlfJsvsrn4DNp95rbRbXTDyTj7tQ==} + '@storybook/builder-manager@8.1.11': + resolution: {integrity: sha512-U7bmed4Ayg+OlJ8HPmLeGxLTHzDY7rxmxM4aAs4YL01fufYfBcjkIP9kFhJm+GJOvGm+YJEUAPe5mbM1P/bn0Q==} - '@storybook/builder-vite@8.0.9': - resolution: {integrity: sha512-7hEQFZIIz7VvxdySDpPE96iMvZxQvRZcRdhaNGeE+8Y2pyc3DgYE4WY3sjr+LUoB0a6TYLpAIKqbXwtLz0R+PQ==} + '@storybook/builder-vite@8.1.11': + resolution: {integrity: sha512-hG4eoNMCPgjZ2Ai+zSmk69zjsyEihe75XbJXtYfGRqjMWtz2+SAUFO54fLc2BD5svcUiTeN+ukWcTrwApyPsKg==} peerDependencies: '@preact/preset-vite': '*' typescript: '>= 4.3.x' @@ -3971,48 +4393,53 @@ packages: vite-plugin-glimmerx: optional: true - '@storybook/channels@8.0.9': - resolution: {integrity: sha512-7Lcfyy5CsLWWGhMPO9WG4jZ/Alzp0AjepFhEreYHRPtQrfttp6qMAjE/g1aHgun0qHCYWxwqIG4NLR/hqDNrXQ==} + '@storybook/channels@8.1.11': + resolution: {integrity: sha512-fu5FTqo6duOqtJFa6gFzKbiSLJoia+8Tibn3xFfB6BeifWrH81hc+AZq0lTmHo5qax2G5t8ZN8JooHjMw6k2RA==} - '@storybook/cli@8.0.9': - resolution: {integrity: sha512-lilYTKn8F5YOePijqfRYFa5v2mHVIJxPCIgTn+OXAmAFbcizZ6P8P6niU4J/NXulgx68Ln1M7hYhFtTP25hVTw==} + '@storybook/cli@8.1.11': + resolution: {integrity: sha512-4U48w9C7mVEKrykcPcfHwJkRyCqJ28XipbElACbjIIkQEqaHaOVtP3GeKIrgkoOXe/HK3O4zKWRP2SqlVS0r4A==} hasBin: true - '@storybook/client-logger@8.0.9': - resolution: {integrity: sha512-LzV/RHkbf07sRc1Jc0ff36RlapKf9Ul7/+9VMvVbI3hshH1CpmrZK4t/tsIdpX/EVOdJ1Gg5cES06PnleOAIPA==} + '@storybook/client-logger@8.1.11': + resolution: {integrity: sha512-DVMh2usz3yYmlqCLCiCKy5fT8/UR9aTh+gSqwyNFkGZrIM4otC5A8eMXajXifzotQLT5SaOEnM3WzHwmpvMIEA==} - '@storybook/codemod@8.0.9': - resolution: {integrity: sha512-VBeGpSZSQpL6iyLLqceJSNGhdCqcNwv+xC/aWdDFOkmuE1YfbmNNwpa9QYv4ZFJ2QjUsm4iTWG60qK+9NXeSKA==} + '@storybook/codemod@8.1.11': + resolution: {integrity: sha512-/LCozjH1IQ1TOs9UQV59BE0X6UZ9q+C0NEUz7qmJZPrwAii3FkW4l7D/fwxblpMExaoxv0oE8NQfUz49U/5Ymg==} - '@storybook/components@8.0.9': - resolution: {integrity: sha512-JcwBGADzIJs0PSzqykrrD2KHzNG9wtexUOKuidt+FSv9szpUhe3qBAXIHpdfBRl7mOJ9TRZ5rt+mukEnfncdzA==} + '@storybook/components@8.1.11': + resolution: {integrity: sha512-iXKsNu7VmrLBtjMfPj7S4yJ6T13GU6joKcVcrcw8wfrQJGlPFp4YaURPBUEDxvCt1XWi5JkaqJBvb48kIrROEQ==} peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta - '@storybook/core-common@8.0.9': - resolution: {integrity: sha512-Jmue+sfHFb4GTYBzyWYw1MygoJiQSfISIrKmNIzAmZ+oR9EOr+jpu/i/bH+uetZ2Hqg1AGhj1VB7OtJp9HQyWw==} + '@storybook/core-common@8.1.11': + resolution: {integrity: sha512-Ix0nplD4I4DrV2t9B+62jaw1baKES9UbR/Jz9LVKFF9nsua3ON0aVe73dOjMxFWBngpzBYWe+zYBTZ7aQtDH4Q==} + peerDependencies: + prettier: ^2 || ^3 + peerDependenciesMeta: + prettier: + optional: true - '@storybook/core-events@8.0.9': - resolution: {integrity: sha512-DxSUx7wG9Qe3OFUBnv3OrYq48J8UWNo2DUR5/JecJCtp3n++L4fAEW3J0IF5FfxpQDMQSp1yTNjZ2PaWCMd2ag==} + '@storybook/core-events@8.1.11': + resolution: {integrity: sha512-vXaNe2KEW9BGlLrg0lzmf5cJ0xt+suPjWmEODH5JqBbrdZ67X6ApA2nb6WcxDQhykesWCuFN5gp1l+JuDOBi7A==} - '@storybook/core-server@8.0.9': - resolution: {integrity: sha512-BIe1T5YUBl0GYxEjRoTQsvXD2pyuzL8rPTUD41zlzSQM0R8U6Iant9SzRms4u0+rKUm2mGxxKuODlUo5ewqaGA==} + '@storybook/core-server@8.1.11': + resolution: {integrity: sha512-L6dzQTmR0np/kagNONvvlm6lSvF1FNc9js3vxsEEPnEypLbhx8bDZaHmuhmBpYUzKyUMpRVQTE/WgjHLuBBuxA==} - '@storybook/csf-plugin@8.0.9': - resolution: {integrity: sha512-pXaNCNi++kxKsqSWwvx215fPx8cNqvepLVxQ7B69qXLHj80DHn0Q3DFBO3sLXNiQMJ2JK4OYcTxMfuOiyzszKw==} + '@storybook/csf-plugin@8.1.11': + resolution: {integrity: sha512-hkA8gjFtSN/tabG0cuvmEqanMXtxPr3qTkp4UNSt1R6jBEgFHRG2y/KYLl367kDwOSFTT987ZgRfJJruU66Fvw==} - '@storybook/csf-tools@8.0.9': - resolution: {integrity: sha512-PiNMhL97giLytTdQwuhsZ92buVk4gy9H/8DtrDhUc45/1OmF95gogm6T2Yap729SIFwgpOcuq/U3aVo6d6swVQ==} + '@storybook/csf-tools@8.1.11': + resolution: {integrity: sha512-6qMWAg/dBwCVIHzANM9lSHoirwqSS+wWmv+NwAs0t9S94M75IttHYxD3IyzwaSYCC5llp0EQFvtXXAuSfFbibg==} - '@storybook/csf@0.1.6': - resolution: {integrity: sha512-JjWnBptVhBYJ14yq+cHs66BXjykRUWQ5TlD1RhPxMOtavynYyV/Q+QR98/N+XB+mcPtFMm5I2DvNkpj0/Dk8Mw==} + '@storybook/csf@0.1.9': + resolution: {integrity: sha512-JlZ6v/iFn+iKohKGpYXnMeNeTiiAMeFoDhYnPLIC8GnyyIWqEI9wJYrOK9i9rxlJ8NZAH/ojGC/u/xVC41qSgQ==} - '@storybook/docs-mdx@3.0.0': - resolution: {integrity: sha512-NmiGXl2HU33zpwTv1XORe9XG9H+dRUC1Jl11u92L4xr062pZtrShLmD4VKIsOQujxhhOrbxpwhNOt+6TdhyIdQ==} + '@storybook/docs-mdx@3.1.0-next.0': + resolution: {integrity: sha512-t4syFIeSyufieNovZbLruPt2DmRKpbwL4fERCZ1MifWDRIORCKLc4NCEHy+IqvIqd71/SJV2k4B51nF7vlJfmQ==} - '@storybook/docs-tools@8.0.9': - resolution: {integrity: sha512-OzogAeOmeHea/MxSPKRBWtOQVNSpoq+OOpimO9YRA5h5GBRJ2TUOGT44Gny6QT4ll5AvQA8fIiq9KezKcLekAg==} + '@storybook/docs-tools@8.1.11': + resolution: {integrity: sha512-mEXtR9rS7Y+OdKtT/QG6JBGYR1L41mcDhIqhnk7RmYl9qJstVAegrCKWR53sPKFdTVOHU7dmu6k+BD+TqHpyyw==} '@storybook/global@5.0.0': resolution: {integrity: sha512-FcOqPAXACP0I3oJ/ws6/rrPT9WGhu915Cg8D02a9YxLo0DE9zI+a9A5gRGvmQ09fiWPukqI8ZAEoQEdWUKMQdQ==} @@ -4024,83 +4451,83 @@ packages: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - '@storybook/instrumenter@8.0.9': - resolution: {integrity: sha512-Gw74dgpTU/2p7FG0s7DuVdqCbJ2MEcSuRJjDo7HcXRYcvWp7I6Ly+C0v7N5VaoS+kbBVerAhLKIHZgG/LZf1og==} + '@storybook/instrumenter@8.1.11': + resolution: {integrity: sha512-r/U9hcqnodNMHuzRt1g56mWrVsDazR85Djz64M3KOwBhrTj5d46DF4/EE80w/5zR5JOrT7p8WmjJRowiVteOCQ==} - '@storybook/manager-api@8.0.9': - resolution: {integrity: sha512-99b3yKArDSvfabXL7QE3nA95e4DdW/5H/ZCcr6/E2qCQJayZ6G1v/WWamKXbiaTpkndulFmcb/+ZmnDXcweIIQ==} + '@storybook/manager-api@8.1.11': + resolution: {integrity: sha512-QSgwKfAw01K9YvvZj30iGBMgQ4YaCT3vojmttuqdH5ukyXkiO7pENLJj4Y+alwUeSi0g+SJeadCI3PXySBHOGg==} - '@storybook/manager@8.0.9': - resolution: {integrity: sha512-+NnRo+5JQFGNqveKrLtC0b+Z08Tae4m44iq292bPeZMpr9OkFsIkU0PBPsHTHPkrqC/zZXRNsCsTEgvu3p2OIA==} + '@storybook/manager@8.1.11': + resolution: {integrity: sha512-e02y9dmxowo7cTKYm9am7UO6NOHoHy6Xi7xZf/UA932qLwFZUtk5pnwIEFaZWI3OQsRUCGhP+FL5zizU7uVZeg==} - '@storybook/node-logger@8.0.9': - resolution: {integrity: sha512-5ajMdZFrYrjGLJOVDq7dlEQNFsgeLHymt4dCK9MulL/ciXykmXUZXE3Bye0wFy+I2qqDVvrvR8uzCvSFvm5MAQ==} + '@storybook/node-logger@8.1.11': + resolution: {integrity: sha512-wdzFo7B2naGhS52L3n1qBkt5BfvQjs8uax6B741yKRpiGgeAN8nz8+qelkD25MbSukxvbPgDot7WJvsMU/iCzg==} - '@storybook/preview-api@8.0.9': - resolution: {integrity: sha512-zHfX34bkAMzzmE7vbDzaqFwSW6ExiBD0HiO1L/IsHF55f0f7xV7IH8uJyFRrDTvAoW3ReSxZDMvvPpeydFPKGA==} + '@storybook/preview-api@8.1.11': + resolution: {integrity: sha512-8ZChmFV56GKppCJ0hnBd/kNTfGn2gWVq1242kuet13pbJtBpvOhyq4W01e/Yo14tAPXvgz8dSnMvWLbJx4QfhQ==} - '@storybook/preview@8.0.9': - resolution: {integrity: sha512-tFsR8xc8AYBZZrZw8enklFbSQt7ZAV+rv20BoxwDhd3q7fjXyK7O4moGPqUwBZ7rukTG13nPoISxr+VXAk/HYA==} + '@storybook/preview@8.1.11': + resolution: {integrity: sha512-K/9NZmjnL0D1BROkTNWNoPqgL2UaocALRSqCARmkBLgU2Rn/FuZgEclHkWlYo6pUrmLNK+bZ+XzpNMu12iTbpg==} - '@storybook/react-dom-shim@8.0.9': - resolution: {integrity: sha512-8011KlRuG3obr5pZZ7bcEyYYNWF3tR596YadoMd267NPoHKvwAbKL1L/DNgb6kiYjZDUf9QfaKSCWW31k0kcRQ==} + '@storybook/react-dom-shim@8.1.11': + resolution: {integrity: sha512-KVDSuipqkFjpGfldoRM5xR/N1/RNmbr+sVXqMmelr0zV2jGnexEZnoa7wRHk7IuXuivLWe8BxMxzvQWqjIa4GA==} peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta - '@storybook/react-vite@8.0.9': - resolution: {integrity: sha512-FT5KeulUH6grfzOJOxJCxpv9+81UVDrT9UPcgiFhQT9rKtsgmltezThwbHknByZNw3WWnf+ieidMLEis9hd73A==} + '@storybook/react-vite@8.1.11': + resolution: {integrity: sha512-QqkE6QKsIDthXtps9+YSBQ39O4VvU7Uu3y6WSA3IPgKTtGnmIvhwXtapjf7WQ2cNb5KY1JksFxHXbDe0i5IL4g==} engines: {node: '>=18.0.0'} peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta vite: ^4.0.0 || ^5.0.0 - '@storybook/react@8.0.9': - resolution: {integrity: sha512-NeQ6suZG3HKikwe3Tx9cAIaRx7uP8FKCmlVvIiBg4LTTI5orCt94PPakvuZukZcbkqvcCnEBkebAzwUpn8PiJw==} + '@storybook/react@8.1.11': + resolution: {integrity: sha512-t+EYXOkgwg3ropLGS9y8gGvX5/Okffu/6JYL3YWksrBGAZSqVV4NkxCnVJZepS717SyhR0tN741gv/SxxFPJMg==} engines: {node: '>=18.0.0'} peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta typescript: '>= 4.2.x' peerDependenciesMeta: typescript: optional: true - '@storybook/router@8.0.9': - resolution: {integrity: sha512-aAOWxbM9J4mt+cp4o88T2PB29mgBBTOzU37/pUsTHYnKnR9XI4npXEXdN8Gv+ryqM0kj0AbBpz/llFlnR2MNNA==} + '@storybook/router@8.1.11': + resolution: {integrity: sha512-nU5lsBvy0L8wBYOkjagh29ztZicDATpZNYrHuavlhQ2jznmmHdJvXKYk+VrMAbthjQ6ZBqfeeMNPR1UlnqR5Rw==} - '@storybook/source-loader@8.0.9': - resolution: {integrity: sha512-FDnpxIGE5nIYT15pvYe6rz95TSBrdLcDll7lOHNyZisWt19MI3wZU3YkVsFNRBuFrebo+FjVU3wHyoV81ur1Qw==} + '@storybook/source-loader@8.1.11': + resolution: {integrity: sha512-4cfJ7aPjtniIdDGiFjdFpO47byHOl4RKYCJEHf9t+j0xHmlXe4B9aAinxuFfv3GKAXfLvSbbwGO0cDZQRj+brw==} - '@storybook/telemetry@8.0.9': - resolution: {integrity: sha512-AGGfcup06t+wxhBIkHd0iybieOh9PDVZQJ9oPct5JGB39+ni9wvs0WOD+MYlHbsjp8id7+aGkh6mYuYOvfck+Q==} + '@storybook/telemetry@8.1.11': + resolution: {integrity: sha512-Jqvm7HcZismKzPuebhyLECO6KjGiSk4ycbca1WUM/TUvifxCXqgoUPlHHQEEfaRdHS63/MSqtMNjLsQRLC/vNQ==} - '@storybook/test@8.0.9': - resolution: {integrity: sha512-bRd5tBJnPzR6UKbDXONWnFWtdkNOY99HMLDUWe5fTRo50GwkrpFBVqPflhdkruEeof0kAbBUbnoN2CIYgtnAFw==} + '@storybook/test@8.1.11': + resolution: {integrity: sha512-k+V3HemF2/I8fkRxRqM8uH8ULrpBSAAdBOtWSHWLvHguVcb2YA4g4kKo6tXBB9256QfyDW4ZiaAj0/9TMxmJPQ==} - '@storybook/theming@8.0.9': - resolution: {integrity: sha512-jgfDuYoiNMMirQiASN3Eg0hGDXsEtpdAcMxyShqYGwu9elxgD9yUnYC2nSckYsM74a3ZQ3JaViZ9ZFSe2FHmeQ==} + '@storybook/theming@8.1.11': + resolution: {integrity: sha512-Chn/opjO6Rl1isNobutYqAH2PjKNkj09YBw/8noomk6gElSa3JbUTyaG/+JCHA6OG/9kUsqoKDb5cZmAKNq/jA==} peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta peerDependenciesMeta: react: optional: true react-dom: optional: true - '@storybook/types@8.0.9': - resolution: {integrity: sha512-ew0EXzk9k4B557P1qIWYrnvUcgaE0WWA5qQS0AU8l+fRTp5nvl9O3SP/zNIB0SN1qDFO7dXr3idTNTyIikTcEQ==} + '@storybook/types@8.1.11': + resolution: {integrity: sha512-k9N5iRuY2+t7lVRL6xeu6diNsxO3YI3lS4Juv3RZ2K4QsE/b3yG5ElfJB8DjHDSHwRH4ORyrU71KkOCUVfvtnw==} - '@storybook/vue3-vite@8.0.9': - resolution: {integrity: sha512-IkzYsEyCo5HIvLWbJeGrBu/VIN4u+LvdIAz7vcFqVVXBtTUhy+9/8caLx8fdnM0FWgKcBRQs8HnjBB2V0lOFcg==} + '@storybook/vue3-vite@8.1.11': + resolution: {integrity: sha512-q0bqh8XEEunaTmp4YiDqM2+YZLwEIevTb5PnNe7G7f2qOiSCE1ncBDnBK717UlCd+iYr34NTztgV2/jIhz1i5w==} engines: {node: '>=18.0.0'} peerDependencies: vite: ^4.0.0 || ^5.0.0 - '@storybook/vue3@8.0.9': - resolution: {integrity: sha512-EqVdS62YbOCAE0wJrQKW0sHpM90be8N8Mvmj+HzB0QYhJNtFqP9ehwbcTfwEKtaVGudisHgGBOzNoSKDlxFaag==} + '@storybook/vue3@8.1.11': + resolution: {integrity: sha512-xJtvfLiCOY3UqwDMd0hZdsadPm1q8dwjfM1UN2Q2ssRWNfXzww1oi+Msj902wz9zFZMYVZypfTfgrdRgWmfEjA==} engines: {node: '>=18.0.0'} peerDependencies: vue: ^3.0.0 @@ -4122,26 +4549,38 @@ packages: cpu: [arm64] os: [android] - '@swc/core-darwin-arm64@1.3.56': - resolution: {integrity: sha512-DZcu7BzDaLEdWHabz9DRTP0yEBLqkrWmskFcD5BX0lGAvoIvE4duMnAqi5F2B3X7630QioHRCYFoRw2WkeE3Cw==} + '@swc/core-darwin-arm64@1.6.13': + resolution: {integrity: sha512-SOF4buAis72K22BGJ3N8y88mLNfxLNprTuJUpzikyMGrvkuBFNcxYtMhmomO0XHsgLDzOJ+hWzcgjRNzjMsUcQ==} engines: {node: '>=10'} cpu: [arm64] os: [darwin] - '@swc/core-darwin-arm64@1.4.17': - resolution: {integrity: sha512-HVl+W4LezoqHBAYg2JCqR+s9ife9yPfgWSj37iIawLWzOmuuJ7jVdIB7Ee2B75bEisSEKyxRlTl6Y1Oq3owBgw==} + '@swc/core-darwin-arm64@1.6.6': + resolution: {integrity: sha512-5DA8NUGECcbcK1YLKJwNDKqdtTYDVnkfDU1WvQSXq/rU+bjYCLtn5gCe8/yzL7ISXA6rwqPU1RDejhbNt4ARLQ==} engines: {node: '>=10'} cpu: [arm64] os: [darwin] - '@swc/core-darwin-x64@1.3.56': - resolution: {integrity: sha512-VH5saqYFasdRXJy6RAT+MXm0+IjkMZvOkohJwUei+oA65cKJofQwrJ1jZro8yOJFYvUSI3jgNRGsdBkmo/4hMw==} + '@swc/core-darwin-arm64@1.7.0-nightly-20240715.2': + resolution: {integrity: sha512-tOMR9yVA1MD320KySitaRT5yUvdzdmuUjX4+sOw2UKHqgk2s68j6JlBHZjdmqpviXXH5qwXWH3ui8ElcHcpN0Q==} + engines: {node: '>=10'} + cpu: [arm64] + os: [darwin] + + '@swc/core-darwin-x64@1.6.13': + resolution: {integrity: sha512-AW8akFSC+tmPE6YQQvK9S2A1B8pjnXEINg+gGgw0KRUUXunvu1/OEOeC5L2Co1wAwhD7bhnaefi06Qi9AiwOag==} engines: {node: '>=10'} cpu: [x64] os: [darwin] - '@swc/core-darwin-x64@1.4.17': - resolution: {integrity: sha512-WYRO9Fdzq4S/he8zjW5I95G1zcvyd9yyD3Tgi4/ic84P5XDlSMpBDpBLbr/dCPjmSg7aUXxNQqKqGkl6dQxYlA==} + '@swc/core-darwin-x64@1.6.6': + resolution: {integrity: sha512-2nbh/RHpweNRsJiYDFk1KcX7UtaKgzzTNUjwtvK5cp0wWrpbXmPvdlWOx3yzwoiSASDFx78242JHHXCIOlEdsw==} + engines: {node: '>=10'} + cpu: [x64] + os: [darwin] + + '@swc/core-darwin-x64@1.7.0-nightly-20240715.2': + resolution: {integrity: sha512-GVQqC/vSOS/LPXYEF00/+JMwXIFBquIhBy4HEdfybkoRaoeLUHxdqkUhI6dW0lRe85QUrSkg69ylAXwD4foU8Q==} engines: {node: '>=10'} cpu: [x64] os: [darwin] @@ -4152,107 +4591,164 @@ packages: cpu: [x64] os: [freebsd] - '@swc/core-linux-arm-gnueabihf@1.3.56': - resolution: {integrity: sha512-LWwPo6NnJkH01+ukqvkoNIOpMdw+Zundm4vBeicwyVrkP+mC3kwVfi03TUFpQUz3kRKdw/QEnxGTj+MouCPbtw==} + '@swc/core-linux-arm-gnueabihf@1.6.13': + resolution: {integrity: sha512-f4gxxvDXVUm2HLYXRd311mSrmbpQF2MZ4Ja6XCQz1hWAxXdhRl1gpnZ+LH/xIfGSwQChrtLLVrkxdYUCVuIjFg==} engines: {node: '>=10'} cpu: [arm] os: [linux] - '@swc/core-linux-arm-gnueabihf@1.4.17': - resolution: {integrity: sha512-cgbvpWOvtMH0XFjvwppUCR+Y+nf6QPaGu6AQ5hqCP+5Lv2zO5PG0RfasC4zBIjF53xgwEaaWmGP5/361P30X8Q==} + '@swc/core-linux-arm-gnueabihf@1.6.6': + resolution: {integrity: sha512-YgytuyUfR7b0z0SRHKV+ylr83HmgnROgeT7xryEkth6JGpAEHooCspQ4RrWTU8+WKJ7aXiZlGXPgybQ4TiS+TA==} engines: {node: '>=10'} cpu: [arm] os: [linux] - '@swc/core-linux-arm64-gnu@1.3.56': - resolution: {integrity: sha512-GzsUy/4egJ4cMlxbM+Ub7AMi5CKAc+pxBxrh8MUPQbyStW8jGgnQsJouTnGy0LHawtdEnsCOl6PcO6OgvktXuQ==} + '@swc/core-linux-arm-gnueabihf@1.7.0-nightly-20240715.2': + resolution: {integrity: sha512-r2VnlO7ABL+fUAEJa/qJeqBKG2lxQV9XcgHIyeWHzcyf9G9frcevcXSHbJSGBIIxiADRuoyrYGfRwzsLXDt7jA==} + engines: {node: '>=10'} + cpu: [arm] + os: [linux] + + '@swc/core-linux-arm64-gnu@1.6.13': + resolution: {integrity: sha512-Nf/eoW2CbG8s+9JoLtjl9FByBXyQ5cjdBsA4efO7Zw4p+YSuXDgc8HRPC+E2+ns0praDpKNZtLvDtmF2lL+2Gg==} engines: {node: '>=10'} cpu: [arm64] os: [linux] - '@swc/core-linux-arm64-gnu@1.4.17': - resolution: {integrity: sha512-l7zHgaIY24cF9dyQ/FOWbmZDsEj2a9gRFbmgx2u19e3FzOPuOnaopFj0fRYXXKCmtdx+anD750iBIYnTR+pq/Q==} + '@swc/core-linux-arm64-gnu@1.6.6': + resolution: {integrity: sha512-yGwx9fddzEE0iURqRVwKBQ4IwRHE6hNhl15WliHpi/PcYhzmYkUIpcbRXjr0dssubXAVPVnx6+jZVDSbutvnfg==} engines: {node: '>=10'} cpu: [arm64] os: [linux] - '@swc/core-linux-arm64-musl@1.3.56': - resolution: {integrity: sha512-9gxL09BIiAv8zY0DjfnFf19bo8+P4T9tdhzPwcm+1yPJcY5yr1+YFWLNFzz01agtOj6VlZ2/wUJTaOfdjjtc+A==} + '@swc/core-linux-arm64-gnu@1.7.0-nightly-20240715.2': + resolution: {integrity: sha512-Pk+RwrvsY1fB2PE3b/RcIbVfvzc3pO8WcTvZjmXQENQ0Af0R+pIR+tnnXweZB48ZdfoBE0sPE3Du1SntoZOcnA==} engines: {node: '>=10'} cpu: [arm64] os: [linux] - '@swc/core-linux-arm64-musl@1.4.17': - resolution: {integrity: sha512-qhH4gr9gAlVk8MBtzXbzTP3BJyqbAfUOATGkyUtohh85fPXQYuzVlbExix3FZXTwFHNidGHY8C+ocscI7uDaYw==} + '@swc/core-linux-arm64-musl@1.6.13': + resolution: {integrity: sha512-2OysYSYtdw79prJYuKIiux/Gj0iaGEbpS2QZWCIY4X9sGoETJ5iMg+lY+YCrIxdkkNYd7OhIbXdYFyGs/w5LDg==} engines: {node: '>=10'} cpu: [arm64] os: [linux] - '@swc/core-linux-x64-gnu@1.3.56': - resolution: {integrity: sha512-n0ORNknl50vMRkll3BDO1E4WOqY6iISlPV1ZQCRLWQ6YQ2q8/WAryBxc2OAybcGHBUFkxyACpJukeU1QZ/9tNw==} + '@swc/core-linux-arm64-musl@1.6.6': + resolution: {integrity: sha512-a6fMbqzSAsS5KCxFJyg1mD5kwN3ZFO8qQLyJ75R/htZP/eCt05jrhmOI7h2n+1HjiG332jLnZ9S8lkVE5O8Nqw==} + engines: {node: '>=10'} + cpu: [arm64] + os: [linux] + + '@swc/core-linux-arm64-musl@1.7.0-nightly-20240715.2': + resolution: {integrity: sha512-spizj6AJ3xxVz/+7sbeXeqkiGrks4u451gGf4pzlhYqWZzxsWjSS9lZXVGJ6vHslofYsQEK0pIsN+F/wOIspUg==} + engines: {node: '>=10'} + cpu: [arm64] + os: [linux] + + '@swc/core-linux-x64-gnu@1.6.13': + resolution: {integrity: sha512-PkR4CZYJNk5hcd2+tMWBpnisnmYsUzazI1O5X7VkIGFcGePTqJ/bWlfUIVVExWxvAI33PQFzLbzmN5scyIUyGQ==} engines: {node: '>=10'} cpu: [x64] os: [linux] - '@swc/core-linux-x64-gnu@1.4.17': - resolution: {integrity: sha512-vRDFATL1oN5oZMImkwbgSHEkp8xG1ofEASBypze01W1Tqto8t+yo6gsp69wzCZBlxldsvPpvFZW55Jq0Rn+UnA==} + '@swc/core-linux-x64-gnu@1.6.6': + resolution: {integrity: sha512-hRGsUKNzzZle28YF0dYIpN0bt9PceR9LaVBq7x8+l9TAaDLFbgksSxcnU/ubTtsy+WsYSYGn+A83w3xWC0O8CQ==} engines: {node: '>=10'} cpu: [x64] os: [linux] - '@swc/core-linux-x64-musl@1.3.56': - resolution: {integrity: sha512-r+D34WLAOAlJtfw1gaVWpHRwCncU9nzW9i7w9kSw4HpWYnHJOz54jLGSEmNsrhdTCz1VK2ar+V2ktFUsrlGlDA==} + '@swc/core-linux-x64-gnu@1.7.0-nightly-20240715.2': + resolution: {integrity: sha512-08zfcePPoBBBcoSHvNWK2OZk4EQtwB/tgFstDf5HROOKr9YqCxVYemWCwBFuqVHr6ALAoEeizPOqCilvk0jQnw==} engines: {node: '>=10'} cpu: [x64] os: [linux] - '@swc/core-linux-x64-musl@1.4.17': - resolution: {integrity: sha512-zQNPXAXn3nmPqv54JVEN8k2JMEcMTQ6veVuU0p5O+A7KscJq+AGle/7ZQXzpXSfUCXlLMX4wvd+rwfGhh3J4cw==} + '@swc/core-linux-x64-musl@1.6.13': + resolution: {integrity: sha512-OdsY7wryTxCKwGQcwW9jwWg3cxaHBkTTHi91+5nm7hFPpmZMz1HivJrWAMwVE7iXFw+M4l6ugB/wCvpYrUAAjA==} engines: {node: '>=10'} cpu: [x64] os: [linux] - '@swc/core-win32-arm64-msvc@1.3.56': - resolution: {integrity: sha512-29Yt75Is6X24z3x8h/xZC1HnDPkPpyLH9mDQiM6Cuc0I9mVr1XSriPEUB2N/awf5IE4SA8c+3IVq1DtKWbkJIw==} + '@swc/core-linux-x64-musl@1.6.6': + resolution: {integrity: sha512-NokIUtFxJDVv3LzGeEtYMTV3j2dnGKLac59luTeq36DQLZdJQawQIdTbzzWl2jE7lxxTZme+dhsVOH9LxE3ceg==} + engines: {node: '>=10'} + cpu: [x64] + os: [linux] + + '@swc/core-linux-x64-musl@1.7.0-nightly-20240715.2': + resolution: {integrity: sha512-hrkT5htUfC4DWHI8tI6DxBHQpw6LU6AuWjMuEJcHtGnHA3BeXxXrZsCPpuxKfUHEEQbdijK67pWWh5SCfrX+Lw==} + engines: {node: '>=10'} + cpu: [x64] + os: [linux] + + '@swc/core-win32-arm64-msvc@1.6.13': + resolution: {integrity: sha512-ap6uNmYjwk9M/+bFEuWRNl3hq4VqgQ/Lk+ID/F5WGqczNr0L7vEf+pOsRAn0F6EV+o/nyb3ePt8rLhE/wjHpPg==} engines: {node: '>=10'} cpu: [arm64] os: [win32] - '@swc/core-win32-arm64-msvc@1.4.17': - resolution: {integrity: sha512-z86n7EhOwyzxwm+DLE5NoLkxCTme2lq7QZlDjbQyfCxOt6isWz8rkW5QowTX8w9Rdmk34ncrjSLvnHOeLY17+w==} + '@swc/core-win32-arm64-msvc@1.6.6': + resolution: {integrity: sha512-lzYdI4qb4k1dFG26yv+9Jaq/bUMAhgs/2JsrLncGjLof86+uj74wKYCQnbzKAsq2hDtS5DqnHnl+//J+miZfGA==} engines: {node: '>=10'} cpu: [arm64] os: [win32] - '@swc/core-win32-ia32-msvc@1.3.56': - resolution: {integrity: sha512-mplp0zbYDrcHtfvkniXlXdB04e2qIjz2Gq/XHKr4Rnc6xVORJjjXF91IemXKpavx2oZYJws+LNJL7UFQ8jyCdQ==} + '@swc/core-win32-arm64-msvc@1.7.0-nightly-20240715.2': + resolution: {integrity: sha512-3SQj5cKo91+cNorNvOne2cqHW3Wcg+/irYts0lCGy3pruZXcgUKeTQ3kmV8pRPtXCs17YLysZOSyCF9DQIbacw==} + engines: {node: '>=10'} + cpu: [arm64] + os: [win32] + + '@swc/core-win32-ia32-msvc@1.6.13': + resolution: {integrity: sha512-IJ8KH4yIUHTnS/U1jwQmtbfQals7zWPG0a9hbEfIr4zI0yKzjd83lmtS09lm2Q24QBWOCFGEEbuZxR4tIlvfzA==} engines: {node: '>=10'} cpu: [ia32] os: [win32] - '@swc/core-win32-ia32-msvc@1.4.17': - resolution: {integrity: sha512-JBwuSTJIgiJJX6wtr4wmXbfvOswHFj223AumUrK544QV69k60FJ9q2adPW9Csk+a8wm1hLxq4HKa2K334UHJ/g==} + '@swc/core-win32-ia32-msvc@1.6.6': + resolution: {integrity: sha512-bvl7FMaXIJQ76WZU0ER4+RyfKIMGb6S2MgRkBhJOOp0i7VFx4WLOnrmMzaeoPJaJSkityVKAftfNh7NBzTIydQ==} engines: {node: '>=10'} cpu: [ia32] os: [win32] - '@swc/core-win32-x64-msvc@1.3.56': - resolution: {integrity: sha512-zp8MBnrw/bjdLenO/ifYzHrImSjKunqL0C2IF4LXYNRfcbYFh2NwobsVQMZ20IT0474lKRdlP8Oxdt+bHuXrzA==} + '@swc/core-win32-ia32-msvc@1.7.0-nightly-20240715.2': + resolution: {integrity: sha512-BiHjqoPhodpgrNXoPaflvpC98NXLa3jI6vV5ZSTLkpJ1JR+T9RcB+unkllr/mjqUZaqafW9AE784A9+wHzja3Q==} + engines: {node: '>=10'} + cpu: [ia32] + os: [win32] + + '@swc/core-win32-x64-msvc@1.6.13': + resolution: {integrity: sha512-f6/sx6LMuEnbuxtiSL/EkR0Y6qUHFw1XVrh6rwzKXptTipUdOY+nXpKoh+1UsBm/r7H0/5DtOdrn3q5ZHbFZjQ==} engines: {node: '>=10'} cpu: [x64] os: [win32] - '@swc/core-win32-x64-msvc@1.4.17': - resolution: {integrity: sha512-jFkOnGQamtVDBm3MF5Kq1lgW8vx4Rm1UvJWRUfg+0gx7Uc3Jp3QMFeMNw/rDNQYRDYPG3yunCC+2463ycd5+dg==} + '@swc/core-win32-x64-msvc@1.6.6': + resolution: {integrity: sha512-WAP0JoCTfgeYKgOeYJoJV4ZS0sQUmU3OwvXa2dYYtMLF7zsNqOiW4niU7QlThBHgUv/qNZm2p6ITEgh3w1cltw==} engines: {node: '>=10'} cpu: [x64] os: [win32] - '@swc/core@1.4.17': - resolution: {integrity: sha512-tq+mdWvodMBNBBZbwFIMTVGYHe9N7zvEaycVVjfvAx20k1XozHbHhRv+9pEVFJjwRxLdXmtvFZd3QZHRAOpoNQ==} + '@swc/core-win32-x64-msvc@1.7.0-nightly-20240715.2': + resolution: {integrity: sha512-bfSnQxYLOKRakwQo/sJA8I/krU/TfxdlER41OlvEiBXVYEjJFMb7z9NyPsk/DBbqeaA1ywHun8ohBhuEwJWpDQ==} + engines: {node: '>=10'} + cpu: [x64] + os: [win32] + + '@swc/core@1.6.13': + resolution: {integrity: sha512-eailUYex6fkfaQTev4Oa3mwn0/e3mQU4H8y1WPuImYQESOQDtVrowwUGDSc19evpBbHpKtwM+hw8nLlhIsF+Tw==} engines: {node: '>=10'} peerDependencies: - '@swc/helpers': ^0.5.0 + '@swc/helpers': '*' + peerDependenciesMeta: + '@swc/helpers': + optional: true + + '@swc/core@1.6.6': + resolution: {integrity: sha512-sHfmIUPUXNrQTwFMVCY5V5Ena2GTOeaWjS2GFUpjLhAgVfP90OP67DWow7+cYrfFtqBdILHuWnjkTcd0+uPKlg==} + engines: {node: '>=10'} + peerDependencies: + '@swc/helpers': '*' peerDependenciesMeta: '@swc/helpers': optional: true @@ -4266,14 +4762,14 @@ packages: peerDependencies: '@swc/core': '*' - '@swc/types@0.1.5': - resolution: {integrity: sha512-myfUej5naTBWnqOCc/MdVOLVjXUXtIA+NpDrDBKJtLLg2shUjBu3cZmB/85RyitKc55+lUUyl7oRfLOvkr2hsw==} + '@swc/types@0.1.9': + resolution: {integrity: sha512-qKnCno++jzcJ4lM4NTfYifm1EFSCeIfKiAHAfkENZAV5Kl9PjJIyd2yeeVv6c/2CckuLyv2NmRC5pv6pm2WQBg==} '@swc/wasm@1.2.130': resolution: {integrity: sha512-rNcJsBxS70+pv8YUWwf5fRlWX6JoY/HJc25HD/F8m6Kv7XhJdqPPMhyX6TKkUBPAG7TWlZYoxa+rHAjPy4Cj3Q==} - '@syuilo/aiscript@0.18.0': - resolution: {integrity: sha512-/iY9Vv4LLjtW/KUzId1QwXC4BlpIEPCMcoT7dyRhYdyxtwhS3Hx4b/4j1HYP+n3Pq9XKyW5zvkY72/+DNu4g6Q==} + '@syuilo/aiscript@0.19.0': + resolution: {integrity: sha512-ZWG4s1m6RrFjE7NeIMaxFz769YO1jW5ReTrOROrEO4IHheOrjxxJ/Ffe2TUNqX9/XxDloMwfWplKhfSzx8LGMA==} '@szmarczak/http-timer@4.0.6': resolution: {integrity: sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==} @@ -4289,56 +4785,56 @@ packages: '@tabler/icons@3.3.0': resolution: {integrity: sha512-PLVe9d7b59sKytbx00KgeGhQG3N176Ezv8YMmsnSz4s0ifDzMWlp/h2wEfQZ0ZNe8e377GY2OW6kovUe3Rnd0g==} - '@tensorflow/tfjs-backend-cpu@4.4.0': - resolution: {integrity: sha512-d4eln500/qNym78z9IrUUzF0ITBoJGLrxV8xd92kLVoXhg35Mm+zqUXShjFcrH8joOHOFuST0qZ0TbDDqcPzPA==} + '@tensorflow/tfjs-backend-cpu@4.20.0': + resolution: {integrity: sha512-1QRQ6AqAa/VB8JOArf5nY3Dc/QQHXbfuxgdIdQhKrABEHgvlaWt2Vv696UhIlVl75YoNY+vWlCwBdGQIKYfFGw==} engines: {yarn: '>= 1.3.2'} peerDependencies: - '@tensorflow/tfjs-core': 4.4.0 + '@tensorflow/tfjs-core': 4.20.0 - '@tensorflow/tfjs-backend-webgl@4.4.0': - resolution: {integrity: sha512-TzQKvfAPgGt9cMG+5bVoTckoG1xr/PVJM/uODkPvzcMqi3j97kuWDXwkYJIgXldStmfiKkU7f5CmyD3Cq3E6BA==} + '@tensorflow/tfjs-backend-webgl@4.20.0': + resolution: {integrity: sha512-M03fJonJGxm2u3SCzRNA2JLh0gxaAye64SEmGAXOehizowxy42l+lMsPWU8xU7r7mN6PEilBNkuKAf5YJ7Xumg==} engines: {yarn: '>= 1.3.2'} peerDependencies: - '@tensorflow/tfjs-core': 4.4.0 + '@tensorflow/tfjs-core': 4.20.0 - '@tensorflow/tfjs-converter@4.4.0': - resolution: {integrity: sha512-JUjpRStrAuw37tgPd5UENu0UjQVuJT09yF7KpOur4BriJ0uQqrbEZHMPHmvUtr5nYzkqlXJTuXIyxvEY/olNpg==} + '@tensorflow/tfjs-converter@4.20.0': + resolution: {integrity: sha512-UJ2ntQ1TNtVHB5qGMwB0j306bs3KH1E1HKJ9Dxvrc6PUaivOV+CPKqmbidOFG5LylXeRC36JBdhe+gVT2nFHNw==} peerDependencies: - '@tensorflow/tfjs-core': 4.4.0 + '@tensorflow/tfjs-core': 4.20.0 - '@tensorflow/tfjs-core@4.4.0': - resolution: {integrity: sha512-Anxpc7cAOA0Q7EUXdTbQKMg3reFvrdkgDlaYzH9ZfkMq2CgLV4Au6E/s6HmbYn/VrAtWy9mLY5c/lLJqh4764g==} + '@tensorflow/tfjs-core@4.20.0': + resolution: {integrity: sha512-m/cc9qDc63al9UhdbXRUYTLGfJJlhuN5tylAX/2pJMLj32c8a6ThGDJYoKzpf32n5g3MQGYLchjClDxeGdXMPQ==} engines: {yarn: '>= 1.3.2'} - '@tensorflow/tfjs-data@4.4.0': - resolution: {integrity: sha512-aY4eq4cgrsrXeBU6ABZAAN3tV0fG4YcHd0z+cYuNXnCo+VEQLJnPmhn+xymZ4VQZQH4GXbVS4dV9pXMclFNRFw==} + '@tensorflow/tfjs-data@4.20.0': + resolution: {integrity: sha512-k6S8joXhoXkatcoT6mYCxBzRCsnrLfnl6xjLe46SnXO0oEEy4Vuzbmp5Ydl1uU2hHr73zL91EdAC1k8Hng/+oA==} peerDependencies: - '@tensorflow/tfjs-core': 4.4.0 + '@tensorflow/tfjs-core': 4.20.0 seedrandom: ^3.0.5 - '@tensorflow/tfjs-layers@4.4.0': - resolution: {integrity: sha512-OGC7shfiD9Gc698hINHK4y9slOJvu5m54tVNm4xf+WSNrw/avvgpar6yyoL5bakYIZNQvFNK75Yr8VRPR7oPeQ==} + '@tensorflow/tfjs-layers@4.20.0': + resolution: {integrity: sha512-SCHZH29Vyw+Y9eoaJHiaNo6yqM9vD3XCKncoczonRRywejm3FFqddg1AuWAfSE9XoNPE21o9PsknvKLl/Uh+Cg==} peerDependencies: - '@tensorflow/tfjs-core': 4.4.0 + '@tensorflow/tfjs-core': 4.20.0 - '@tensorflow/tfjs-node@4.4.0': - resolution: {integrity: sha512-+JSAddsupjSQUDZeb7QGOFkL3Tty3kjPHx8ethiYFzwTZJHCMvM7wZJd0Fqnjxym6A0KpsmB7SPZgwRRXVIlPA==} + '@tensorflow/tfjs-node@4.20.0': + resolution: {integrity: sha512-pVSOlzsVqh5ck3aiNPJCltB3ASKjsLqNPvJ28lXn9Xg648U4eHDk8G47m9w4uf0FdVcWDfjPM3hDCbBZ/E2KXg==} engines: {node: '>=8.11.0'} - '@tensorflow/tfjs@4.4.0': - resolution: {integrity: sha512-EmCsnzdvawyk4b+4JKaLLuicHcJQRZtL1zSy9AWJLiiHTbDDseYgLxfaCEfLk8v2bUe7SBXwl3n3B7OjgvH11Q==} + '@tensorflow/tfjs@4.20.0': + resolution: {integrity: sha512-+ZLfJq2jyIOE2/+yKPoyD/gfy3RZypbfMrlzvBDgodTK5jnexprihhX38hxilh9HPWvWQXJqiUjKJP5ECCikrw==} hasBin: true - '@testing-library/dom@9.3.3': - resolution: {integrity: sha512-fB0R+fa3AUqbLHWyxXa2kGVtf1Fe1ZZFr0Zp6AIbIAzXb2mKbEXl+PCQNUOaq5lbTab5tfctfXRNsWXxa2f7Aw==} - engines: {node: '>=14'} + '@testing-library/dom@10.1.0': + resolution: {integrity: sha512-wdsYKy5zupPyLCW2Je5DLHSxSfbIp6h80WoHOQc+RPtmPGA52O9x5MJEkv92Sjonpq+poOAtUKhh1kBGAXBrNA==} + engines: {node: '>=18'} '@testing-library/dom@9.3.4': resolution: {integrity: sha512-FlS4ZWlp97iiNWig0Muq8p+3rVDjRiYE+YKGbAqXOu9nwJFFOdL00kFpz42M+4huzYi86vAK1sOOfyOG45muIQ==} engines: {node: '>=14'} - '@testing-library/jest-dom@6.4.2': - resolution: {integrity: sha512-CzqH0AFymEMG48CpzXFriYYkOjk6ZGPCLMhW9e9jg3KMCn5OfJecF8GtGW7yGfR/IgCe3SX8BSwjdzI6BBbZLw==} + '@testing-library/jest-dom@6.4.5': + resolution: {integrity: sha512-AguB9yvTXmCnySBP1lWjfNNUwpbElsaQ567lt2VdGqAdHtpieLgjmcVyv1q7PMIvLbgpDdkWV5Ydv3FEejyp2A==} engines: {node: '>=14', npm: '>=6', yarn: '>=1'} peerDependencies: '@jest/globals': '>= 28' @@ -4364,8 +4860,8 @@ packages: peerDependencies: '@testing-library/dom': '>=7.21.4' - '@testing-library/vue@8.0.3': - resolution: {integrity: sha512-wSsbNlZ69ZFQgVlHMtc/ZC/g9BHO7MhyDrd4nHyfEubtMr3kToN/w4/BsSBknGIF8w9UmPbsgbIuq/CbdBHzCA==} + '@testing-library/vue@8.1.0': + resolution: {integrity: sha512-ls4RiHO1ta4mxqqajWRh8158uFObVrrtAPoxk7cIp4HrnQUj/ScKzqz53HxYpG3X6Zb7H2v+0eTGLSoy8HQ2nA==} engines: {node: '>=14'} peerDependencies: '@vue/compiler-sfc': '>= 3' @@ -4381,8 +4877,8 @@ packages: resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==} engines: {node: '>=10.13.0'} - '@tsd/typescript@5.3.3': - resolution: {integrity: sha512-CQlfzol0ldaU+ftWuG52vH29uRoKboLinLy84wS8TQOu+m+tWoaUfk4svL4ij2V8M5284KymJBlHUusKj6k34w==} + '@tsd/typescript@5.4.5': + resolution: {integrity: sha512-saiCxzHRhUrRxQV2JhH580aQUZiKQUXI38FcAcikcfOomAil4G4lxT0RfrrKywoAYP/rqAdYXYmNRLppcd+hQQ==} engines: {node: '>=14.17'} '@twemoji/parser@15.0.0': @@ -4427,12 +4923,6 @@ packages: '@types/cacheable-request@6.0.3': resolution: {integrity: sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==} - '@types/chai-subset@1.3.5': - resolution: {integrity: sha512-c2mPnw+xHtXDoHmdtcCXGwyLMiauiAyxWMzhGpqHC4nqI/Y5G2XhTampslK2rb59kpcuHon03UH8W6iYUzw88A==} - - '@types/chai@4.3.11': - resolution: {integrity: sha512-qQR1dr2rGIHYlJulmr8Ioq3De0Le9E4MJ5AiaeAETJJpndT1uUNHsGFK3L/UIu+rbkQSdj8J/w2bCsBZc/Y5fQ==} - '@types/color-convert@2.0.3': resolution: {integrity: sha512-2Q6wzrNiuEvYxVQqhh7sXM2mhIhvZR/Paq4FdsQkOMgWsCIkKvSGj8Le1/XalulrmgOzPMqNa0ix+ePY4hTrfg==} @@ -4463,6 +4953,9 @@ packages: '@types/detect-port@1.3.2': resolution: {integrity: sha512-xxgAGA2SAU4111QefXPSp5eGbDm/hW6zhvYl9IeEPZEry9F4d66QAHm5qpUXjb6IsevZV/7emAEx5MhP6O192g==} + '@types/diff@5.2.1': + resolution: {integrity: sha512-uxpcuwWJGhe2AR1g8hD9F5OYGCqjqWnBUQFD8gMZsDbv8oPHzxJF6iMO6n8Tk0AdzlxoaaoQhOYlIg/PukVU8g==} + '@types/disposable-email-domains@1.0.2': resolution: {integrity: sha512-SDKwyYTjk3y5aZBxxc38yRecpJPjsqn57STz1bNxYYlv4k11bBe7QB8w4llXDTmQXKT1mFvgGmJv+8Zdu3YmJw==} @@ -4526,8 +5019,8 @@ packages: '@types/http-errors@2.0.4': resolution: {integrity: sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==} - '@types/http-link-header@1.0.5': - resolution: {integrity: sha512-AxhIKR8UbyoqCTNp9rRepkktHuUOw3DjfOfDCaO9kwI8AYzjhxyrvZq4+mRw/2daD3hYDknrtSeV6SsPwmc71w==} + '@types/http-link-header@1.0.7': + resolution: {integrity: sha512-snm5oLckop0K3cTDAiBnZDy6ncx9DJ3mCRDvs42C884MbVYPP74Tiq2hFsSDRTyjK6RyDYDIulPiW23ge+g5Lw==} '@types/istanbul-lib-coverage@2.0.4': resolution: {integrity: sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==} @@ -4544,8 +5037,8 @@ packages: '@types/js-yaml@4.0.9': resolution: {integrity: sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==} - '@types/jsdom@21.1.6': - resolution: {integrity: sha512-/7kkMsC+/kMs7gAYmmBR9P0vGTnOoLhQhyhQJSlXGI5bzTHp6xdo0TtKWQAsz6pmSAeVqKSbqeyP6hytqr9FDw==} + '@types/jsdom@21.1.7': + resolution: {integrity: sha512-yOriVnggzrnQ3a9OKOCxaVuSug3w3/SbOj5i7VwXWZEyUNl3bLF9V3MfxGbZKuwqJOQyRfqXyROBB1CoZLFWzA==} '@types/json-schema@7.0.12': resolution: {integrity: sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==} @@ -4556,8 +5049,8 @@ packages: '@types/json5@0.0.29': resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} - '@types/jsonld@1.5.13': - resolution: {integrity: sha512-n7fUU6W4kSYK8VQlf/LsE9kddBHPKhODoVOjsZswmve+2qLwBy6naWxs/EiuSZN9NU0N06Ra01FR+j87C62T0A==} + '@types/jsonld@1.5.14': + resolution: {integrity: sha512-z4IRf5oRgjPTkazDDv94sjzI5iK3DrDEW7Y5Gk4VO4+ANymgtHtNaXWi93+BmiAoG3PB9QTv5DgSpKWGYVvysA==} '@types/jsrsasign@10.5.14': resolution: {integrity: sha512-lppSlfK6etu+cuKs40K4rg8As79PH6hzIB+v55zSqImbSH3SE6Fm8MBHCiI91cWlAP3Z4igtJK1VL3fSN09blQ==} @@ -4592,8 +5085,8 @@ packages: '@types/mdx@2.0.3': resolution: {integrity: sha512-IgHxcT3RC8LzFLhKwP3gbMPeaK7BM9eBH46OdapPA7yvuIUJ8H6zHZV53J8hGZcTSnt95jANt+rTBNUUc22ACQ==} - '@types/micromatch@4.0.7': - resolution: {integrity: sha512-C/FMQ8HJAZhTsDpl4wDKZdMeeW5USjgzOczUwTGbRc1ZopPgOhIEnxY2ZgUrsuyy4DwK1JVOJZKFakv3TbCKiA==} + '@types/micromatch@4.0.9': + resolution: {integrity: sha512-7V+8ncr22h4UoYRLnLXSpTxjQrNUXtWHGeMPRJt1nULXI57G9bIcpyrHlmrQ7QK24EyyuXvYcSSWAM8GA9nqCg==} '@types/mime-types@2.1.4': resolution: {integrity: sha512-lfU4b34HOri+kAY5UheuFMWPDOI+OPceBSHZKp69gEyTL/mmJ4cnU6Y/rlme3UL3GyOn6Y42hyIEw0/q8sWx5w==} @@ -4616,12 +5109,8 @@ packages: '@types/mysql@2.15.22': resolution: {integrity: sha512-wK1pzsJVVAjYCSZWQoWHziQZbNggXFDUEIGf54g4ZM/ERuP86uGdWeKZWMYlqTPMZfHJJvLPyogXGvCOg87yLQ==} - '@types/node-fetch@2.6.4': - resolution: {integrity: sha512-1ZX9fcN4Rvkvgv4E6PAY5WXUFWFcRWxZa3EW83UjycOB9ljJCedb2CupIP4RZMEwF/M3eTcCihbBRgwtGbg5Rg==} - - '@types/node-fetch@3.0.3': - resolution: {integrity: sha512-HhggYPH5N+AQe/OmN6fmhKmRRt2XuNJow+R3pQwJxOOF9GuwM7O2mheyGeIrs5MOIeNjDEdgdoyHBOrFeJBR3g==} - deprecated: This is a stub types definition. node-fetch provides its own type definitions, so you do not need this installed. + '@types/node-fetch@2.6.11': + resolution: {integrity: sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g==} '@types/node@18.17.15': resolution: {integrity: sha512-2yrWpBk32tvV/JAd3HNHWuZn/VDN1P+72hWirHnvsvTGSqbANi+kSeuQR9yAHnbvaBvHDsoTdXV0Fe+iRtHLKA==} @@ -4629,8 +5118,8 @@ packages: '@types/node@20.11.5': resolution: {integrity: sha512-g557vgQjUUfN76MZAN/dt1z3dzcUsimuysco0KeluHgrPdJXkP/XdAURgyO2W9fZWHRtRBiVKzKn8vyOAwlG+w==} - '@types/node@20.12.7': - resolution: {integrity: sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==} + '@types/node@20.14.9': + resolution: {integrity: sha512-06OCtnTXtWOZBJlRApleWndH4JsRVs1pDCc8dLSQp+7PpUpX3ePdHyeNSFTeSe7FtKyQkrlPvHwJOW3SLd8Oyg==} '@types/node@20.9.1': resolution: {integrity: sha512-HhmzZh5LSJNS5O8jQKpJ/3ZcrrlG6L70hpGqMIAoM9YVD0YBRNWYsfwcXq8VnSjlNpCpgLzMXdiPo+dxcvSmiA==} @@ -4647,8 +5136,8 @@ packages: '@types/oauth2orize@1.11.5': resolution: {integrity: sha512-C6hrRoh9hCnqis39OpeUZSwgw+TIzcV0CsxwJMGfQjTx4I1r+CLmuEPzoDJr5NRTfc7OMwHNLkQwrGFLKrJjMQ==} - '@types/oauth@0.9.4': - resolution: {integrity: sha512-qk9orhti499fq5XxKCCEbd0OzdPZuancneyse3KtR+vgMiHRbh+mn8M4G6t64ob/Fg+GZGpa565MF/2dKWY32A==} + '@types/oauth@0.9.5': + resolution: {integrity: sha512-+oQ3C2Zx6ambINOcdIARF5Z3Tu3x//HipE889/fqo3sgpQZbe9c6ExdQFtN6qlhpR7p83lTZfPJt0tCAW29dog==} '@types/offscreencanvas@2019.3.0': resolution: {integrity: sha512-esIJx9bQg+QYF0ra8GnvfianIY8qWB0GBx54PK5Eps6m+xTj86KLavHv6qDhzKcu5UUOgNfJ2pWaIIV7TRUd9Q==} @@ -4659,8 +5148,8 @@ packages: '@types/pg-pool@2.0.4': resolution: {integrity: sha512-qZAvkv1K3QbmHHFYSNRYPkRjOWRLBYrL4B9c+wG0GSVGBw0NtJwPcgx/DSddeDJvRGMHCEQ4VMEVfuJ/0gZ3XQ==} - '@types/pg@8.11.5': - resolution: {integrity: sha512-2xMjVviMxneZHDHX5p5S6tsRRs7TpDHeeK7kTTMe/kAC/mRRNjWHjZg0rkiY+e17jXSZV3zJYDxXV8Cy72/Vuw==} + '@types/pg@8.11.6': + resolution: {integrity: sha512-/2WmmBXHLsfRqzfHW7BNZ8SbYzE8OSk7i3WjFYvfgRHj7S1xj+16Je5fUKv3lVdVzk/zn9TXOqf+avFCFIE0yQ==} '@types/pg@8.6.1': resolution: {integrity: sha512-1Kc4oAGzAl7uqUStZCDvaLFqZrW9qWSjXOmBfdgyBP5La7Us6Mg4GBvRlSoaZMhQF/zSj1C8CtKMBkoiT8eL8w==} @@ -4716,6 +5205,9 @@ packages: '@types/seedrandom@2.4.30': resolution: {integrity: sha512-AnxLHewubLVzoF/A4qdxBGHCKifw8cY32iro3DQX9TPcetE95zBeVt3jnsvtvAUf1vwzMfwzp4t/L2yqPlnjkQ==} + '@types/seedrandom@2.4.34': + resolution: {integrity: sha512-ytDiArvrn/3Xk6/vtylys5tlY6eo7Ane0hvcx++TKo6RxQXuVfW0AF/oeWqAj9dN29SyhtawuXstgmPlwNcv/A==} + '@types/seedrandom@3.0.8': resolution: {integrity: sha512-TY1eezMU2zH2ozQoAFAQFOPpvP15g+ZgSfTZt31AUUH/Rxtnz3H+A/Sv1Snw2/amp//omibc+AEkTaA8KUeOLQ==} @@ -4767,6 +5259,9 @@ packages: '@types/unist@3.0.2': resolution: {integrity: sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==} + '@types/uuid@10.0.0': + resolution: {integrity: sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==} + '@types/uuid@9.0.8': resolution: {integrity: sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==} @@ -4776,9 +5271,6 @@ packages: '@types/web-push@3.6.3': resolution: {integrity: sha512-v3oT4mMJsHeJ/rraliZ+7TbZtr5bQQuxcgD7C3/1q/zkAj29c8RE0F9lVZVu3hiQe5Z9fYcBreV7TLnfKR+4mg==} - '@types/webgl-ext@0.0.30': - resolution: {integrity: sha512-LKVgNmBxN0BbljJrVUwkxwRYqzsAEPcZOe6S2T6ZaBDIrFp0qu4FNlpc5sM1tGbXUYFgdVQIoeLk1Y1UoblyEg==} - '@types/wrap-ansi@3.0.0': resolution: {integrity: sha512-ltIpx+kM7g/MLRZfkbL7EsCEjfzCcScLpkg37eXEtx5kmrAKBkTJwd1GIAjDSL8wTpM6Hzn5YO4pSb91BEwu1g==} @@ -4816,8 +5308,8 @@ packages: typescript: optional: true - '@typescript-eslint/eslint-plugin@7.7.1': - resolution: {integrity: sha512-KwfdWXJBOviaBVhxO3p5TJiLpNuh2iyXyjmWN0f1nU87pwyvfS0EmjC6ukQVYVFJd/K1+0NWGPDXiyEyQorn0Q==} + '@typescript-eslint/eslint-plugin@7.15.0': + resolution: {integrity: sha512-uiNHpyjZtFrLwLDpHnzaDlP3Tt6sGMqTCiqmxaN4n4RP0EfYZDODJyddiFDF44Hjwxr5xAcaYxVKm9QKQFJFLA==} engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: '@typescript-eslint/parser': ^7.0.0 @@ -4847,8 +5339,8 @@ packages: typescript: optional: true - '@typescript-eslint/parser@7.7.1': - resolution: {integrity: sha512-vmPzBOOtz48F6JAGVS/kZYk4EkXao6iGrD838sp1w3NQQC0W8ry/q641KU4PrG7AKNAf56NOcR8GOpH8l9FPCw==} + '@typescript-eslint/parser@7.15.0': + resolution: {integrity: sha512-k9fYuQNnypLFcqORNClRykkGOMOj+pV6V91R4GO/l1FDGwpqmSwoOQrOHo3cGaH63e+D3ZiCAOsuS/D2c99j/A==} engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: eslint: ^8.56.0 @@ -4865,8 +5357,8 @@ packages: resolution: {integrity: sha512-6TmN4OJiohHfoOdGZ3huuLhpiUgOGTpgXNUPJgeZOZR3DnIpdSgtt83RS35OYNNXxM4TScVlpVKC9jyQSETR1A==} engines: {node: ^16.0.0 || >=18.0.0} - '@typescript-eslint/scope-manager@7.7.1': - resolution: {integrity: sha512-PytBif2SF+9SpEUKynYn5g1RHFddJUcyynGpztX3l/ik7KmZEv19WCMhUBkHXPU9es/VWGD3/zg3wg90+Dh2rA==} + '@typescript-eslint/scope-manager@7.15.0': + resolution: {integrity: sha512-Q/1yrF/XbxOTvttNVPihxh1b9fxamjEoz2Os/Pe38OHwxC24CyCqXxGTOdpb4lt6HYtqw9HetA/Rf6gDGaMPlw==} engines: {node: ^18.18.0 || >=20.0.0} '@typescript-eslint/type-utils@6.11.0': @@ -4889,8 +5381,8 @@ packages: typescript: optional: true - '@typescript-eslint/type-utils@7.7.1': - resolution: {integrity: sha512-ZksJLW3WF7o75zaBPScdW1Gbkwhd/lyeXGf1kQCxJaOeITscoSl0MjynVvCzuV5boUz/3fOI06Lz8La55mu29Q==} + '@typescript-eslint/type-utils@7.15.0': + resolution: {integrity: sha512-SkgriaeV6PDvpA6253PDVep0qCqgbO1IOBiycjnXsszNTVQe5flN5wR5jiczoEoDEnAqYFSFFc9al9BSGVltkg==} engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: eslint: ^8.56.0 @@ -4907,8 +5399,8 @@ packages: resolution: {integrity: sha512-qTWjWieJ1tRJkxgZYXx6WUYtWlBc48YRxgY2JN1aGeVpkhmnopq+SUC8UEVGNXIvWH7XyuTjwALfG6bFEgCkQA==} engines: {node: ^16.0.0 || >=18.0.0} - '@typescript-eslint/types@7.7.1': - resolution: {integrity: sha512-AmPmnGW1ZLTpWa+/2omPrPfR7BcbUU4oha5VIbSbS1a1Tv966bklvLNXxp3mrbc+P2j4MNOTfDffNsk4o0c6/w==} + '@typescript-eslint/types@7.15.0': + resolution: {integrity: sha512-aV1+B1+ySXbQH0pLK0rx66I3IkiZNidYobyfn0WFsdGhSXw+P3YOqeTq5GED458SfB24tg+ux3S+9g118hjlTw==} engines: {node: ^18.18.0 || >=20.0.0} '@typescript-eslint/typescript-estree@6.11.0': @@ -4929,8 +5421,8 @@ packages: typescript: optional: true - '@typescript-eslint/typescript-estree@7.7.1': - resolution: {integrity: sha512-CXe0JHCXru8Fa36dteXqmH2YxngKJjkQLjxzoj6LYwzZ7qZvgsLSc+eqItCrqIop8Vl2UKoAi0StVWu97FQZIQ==} + '@typescript-eslint/typescript-estree@7.15.0': + resolution: {integrity: sha512-gjyB/rHAopL/XxfmYThQbXbzRMGhZzGw6KpcMbfe8Q3nNQKStpxnUKeXb0KiN/fFDR42Z43szs6rY7eHk0zdGQ==} engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: typescript: '*' @@ -4950,8 +5442,8 @@ packages: peerDependencies: eslint: ^8.56.0 - '@typescript-eslint/utils@7.7.1': - resolution: {integrity: sha512-QUvBxPEaBXf41ZBbaidKICgVL8Hin0p6prQDu6bbetWo39BKbWJxRsErOzMNT1rXvTll+J7ChrbmMCXM9rsvOQ==} + '@typescript-eslint/utils@7.15.0': + resolution: {integrity: sha512-hfDMDqaqOqsUVGiEPSMLR/AjTSCsmJwjpKkYQRo1FNbmW4tBwBspYDwO9eh7sKSTwMQgBw9/T4DHudPaqshRWA==} engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: eslint: ^8.56.0 @@ -4964,87 +5456,75 @@ packages: resolution: {integrity: sha512-FhUqNWluiGNzlvnDZiXad4mZRhtghdoKW6e98GoEOYSu5cND+E39rG5KwJMUzeENwm1ztYBRqof8wMLP+wNPIA==} engines: {node: ^16.0.0 || >=18.0.0} - '@typescript-eslint/visitor-keys@7.7.1': - resolution: {integrity: sha512-gBL3Eq25uADw1LQ9kVpf3hRM+DWzs0uZknHYK3hq4jcTPqVCClHGDnB6UUUV2SFeBeA4KWHWbbLqmbGcZ4FYbw==} + '@typescript-eslint/visitor-keys@7.15.0': + resolution: {integrity: sha512-Hqgy/ETgpt2L5xueA/zHHIl4fJI2O4XUE9l4+OIfbJIRSnTJb/QscncdqqZzofQegIJugRIF57OJea1khw2SDw==} engines: {node: ^18.18.0 || >=20.0.0} '@ungap/structured-clone@1.2.0': resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} - '@vitejs/plugin-vue@5.0.4': - resolution: {integrity: sha512-WS3hevEszI6CEVEx28F8RjTX97k3KsrcY6kvTg7+Whm5y3oYvcqzVeGCU3hxSAn4uY2CLCkeokkGKpoctccilQ==} + '@vitejs/plugin-vue@5.0.5': + resolution: {integrity: sha512-LOjm7XeIimLBZyzinBQ6OSm3UBCNVCpLkxGC0oWmm2YPzVZoxMsdvNVimLTBzpAnR9hl/yn1SHGuRfe6/Td9rQ==} engines: {node: ^18.0.0 || >=20.0.0} peerDependencies: vite: ^5.0.0 vue: ^3.2.25 - '@vitest/coverage-v8@0.34.6': - resolution: {integrity: sha512-fivy/OK2d/EsJFoEoxHFEnNGTg+MmdZBAVK9Ka4qhXR2K3J0DS08vcGVwzDtXSuUMabLv4KtPcpSKkcMXFDViw==} + '@vitest/coverage-v8@1.6.0': + resolution: {integrity: sha512-KvapcbMY/8GYIG0rlwwOKCVNRc0OL20rrhFkg/CHNzncV03TE2XWvO5w9uZYoxNiMEBacAJt3unSOiZ7svePew==} peerDependencies: - vitest: '>=0.32.0 <1' + vitest: 1.6.0 - '@vitest/expect@0.34.6': - resolution: {integrity: sha512-QUzKpUQRc1qC7qdGo7rMK3AkETI7w18gTCUrsNnyjjJKYiuUB9+TQK3QnR1unhCnWRC0AbKv2omLGQDF/mIjOw==} + '@vitest/expect@1.6.0': + resolution: {integrity: sha512-ixEvFVQjycy/oNgHjqsL6AZCDduC+tflRluaHIzKIsdbzkLn2U/iBnVeJwB6HsIjQBdfMR8Z0tRxKUsvFJEeWQ==} - '@vitest/expect@1.3.1': - resolution: {integrity: sha512-xofQFwIzfdmLLlHa6ag0dPV8YsnKOCP1KdAeVVh34vSjN2dcUiXYCD9htu/9eM7t8Xln4v03U9HLxLpPlsXdZw==} + '@vitest/runner@1.6.0': + resolution: {integrity: sha512-P4xgwPjwesuBiHisAVz/LSSZtDjOTPYZVmNAnpHHSR6ONrf8eCJOFRvUwdHn30F5M1fxhqtl7QZQUk2dprIXAg==} - '@vitest/runner@0.34.6': - resolution: {integrity: sha512-1CUQgtJSLF47NnhN+F9X2ycxUP0kLHQ/JWvNHbeBfwW8CzEGgeskzNnHDyv1ieKTltuR6sdIHV+nmR6kPxQqzQ==} - - '@vitest/snapshot@0.34.6': - resolution: {integrity: sha512-B3OZqYn6k4VaN011D+ve+AA4whM4QkcwcrwaKwAbyyvS/NB1hCWjFIBQxAQQSQir9/RtyAAGuq+4RJmbn2dH4w==} - - '@vitest/spy@0.34.6': - resolution: {integrity: sha512-xaCvneSaeBw/cz8ySmF7ZwGvL0lBjfvqc1LpQ/vcdHEvpLn3Ff1vAvjw+CoGn0802l++5L/pxb7whwcWAw+DUQ==} - - '@vitest/spy@1.3.1': - resolution: {integrity: sha512-xAcW+S099ylC9VLU7eZfdT9myV67Nor9w9zhf0mGCYJSO+zM2839tOeROTdikOi/8Qeusffvxb/MyBSOja1Uig==} + '@vitest/snapshot@1.6.0': + resolution: {integrity: sha512-+Hx43f8Chus+DCmygqqfetcAZrDJwvTj0ymqjQq4CvmpKFSTVteEOBzCusu1x2tt4OJcvBflyHUE0DZSLgEMtQ==} '@vitest/spy@1.6.0': resolution: {integrity: sha512-leUTap6B/cqi/bQkXUu6bQV5TZPx7pmMBKBQiI0rJA8c3pB56ZsaTbREnF7CJfmvAS4V2cXIBAh/3rVwrrCYgw==} - '@vitest/utils@0.34.6': - resolution: {integrity: sha512-IG5aDD8S6zlvloDsnzHw0Ut5xczlF+kv2BOTo+iXfPr54Yhi5qbVOgGB1hZaVq4iJ4C/MZ2J0y15IlsV/ZcI0A==} - - '@vitest/utils@1.3.1': - resolution: {integrity: sha512-d3Waie/299qqRyHTm2DjADeTaNdNSVsnwHPWrs20JMpjh6eiVq7ggggweO8rc4arhf6rRkWuHKwvxGvejUXZZQ==} - '@vitest/utils@1.6.0': resolution: {integrity: sha512-21cPiuGMoMZwiOHa2i4LXkMkMkCGzA+MVFV70jRwHo95dL4x/ts5GZhML1QWuy7yfp3WzK3lRvZi3JnXTYqrBw==} '@volar/language-core@2.2.0': resolution: {integrity: sha512-a8WG9+4OdeNDW4ywABZIM6S6UN7em8uIlM/BZ2pWQUYrVmX+m8sj/X+QadvO+Li/t/LjAqbWJQtVgxdpEWLALQ==} + '@volar/language-core@2.4.0-alpha.11': + resolution: {integrity: sha512-DtftH0DtpksK1y+de/kLnu8CHcFQ7huKXi7cyxH9R0PbOOTSGXd31kijBeKNzyoXRp8dqGpu/7WhOlCWXQR62w==} + '@volar/source-map@2.2.0': resolution: {integrity: sha512-HQlPRlHOVqCCHK8wI76ZldHkEwKsjp7E6idUc36Ekni+KJDNrqgSqPvyHQixybXPHNU7CI9Uxd9/IkxO7LuNBw==} + '@volar/source-map@2.4.0-alpha.11': + resolution: {integrity: sha512-yyjmv8KUkTcxXzwme9qUMl6Szdji9JUQa8eadE4ib/spFXXZGq6QOX8cgSu5UQ0ooyBJFO1zdVH5otBJyZE3Ew==} + '@volar/typescript@2.2.0': resolution: {integrity: sha512-wC6l4zLiiCLxF+FGaHCbWlQYf4vMsnRxYhcI6WgvaNppOD6r1g+Ef1RKRJUApALWU46Yy/JDU/TbdV6w/X6Liw==} - '@vue/compiler-core@3.4.21': - resolution: {integrity: sha512-MjXawxZf2SbZszLPYxaFCjxfibYrzr3eYbKxwpLR9EQN+oaziSu3qKVbwBERj1IFIB8OLUewxB5m/BFzi613og==} + '@volar/typescript@2.4.0-alpha.11': + resolution: {integrity: sha512-N/v+wSddhtsNtfv2w0Bxj2QQWURN5budGzpyBTrlcXxz2dnvB0eAMqrEQbBi6rCOVHlRaXbh+wyTRdAcB/FHrg==} - '@vue/compiler-core@3.4.25': - resolution: {integrity: sha512-Y2pLLopaElgWnMNolgG8w3C5nNUVev80L7hdQ5iIKPtMJvhVpG0zhnBG/g3UajJmZdvW0fktyZTotEHD1Srhbg==} + '@vue/compiler-core@3.4.29': + resolution: {integrity: sha512-TFKiRkKKsRCKvg/jTSSKK7mYLJEQdUiUfykbG49rubC9SfDyvT2JrzTReopWlz2MxqeLyxh9UZhvxEIBgAhtrg==} - '@vue/compiler-core@3.4.26': - resolution: {integrity: sha512-N9Vil6Hvw7NaiyFUFBPXrAyETIGlQ8KcFMkyk6hW1Cl6NvoqvP+Y8p1Eqvx+UdqsnrnI9+HMUEJegzia3mhXmQ==} + '@vue/compiler-core@3.4.31': + resolution: {integrity: sha512-skOiodXWTV3DxfDhB4rOf3OGalpITLlgCeOwb+Y9GJpfQ8ErigdBUHomBzvG78JoVE8MJoQsb+qhZiHfKeNeEg==} - '@vue/compiler-dom@3.4.21': - resolution: {integrity: sha512-IZC6FKowtT1sl0CR5DpXSiEB5ayw75oT2bma1BEhV7RRR1+cfwLrxc2Z8Zq/RGFzJ8w5r9QtCOvTjQgdn0IKmA==} + '@vue/compiler-dom@3.4.29': + resolution: {integrity: sha512-A6+iZ2fKIEGnfPJejdB7b1FlJzgiD+Y/sxxKwJWg1EbJu6ZPgzaPQQ51ESGNv0CP6jm6Z7/pO6Ia8Ze6IKrX7w==} - '@vue/compiler-dom@3.4.25': - resolution: {integrity: sha512-Ugz5DusW57+HjllAugLci19NsDK+VyjGvmbB2TXaTcSlQxwL++2PETHx/+Qv6qFwNLzSt7HKepPe4DcTE3pBWg==} + '@vue/compiler-dom@3.4.31': + resolution: {integrity: sha512-wK424WMXsG1IGMyDGyLqB+TbmEBFM78hIsOJ9QwUVLGrcSk0ak6zYty7Pj8ftm7nEtdU/DGQxAXp0/lM/2cEpQ==} - '@vue/compiler-dom@3.4.26': - resolution: {integrity: sha512-4CWbR5vR9fMg23YqFOhr6t6WB1Fjt62d6xdFPyj8pxrYub7d+OgZaObMsoxaF9yBUHPMiPFK303v61PwAuGvZA==} + '@vue/compiler-sfc@3.4.31': + resolution: {integrity: sha512-einJxqEw8IIJxzmnxmJBuK2usI+lJonl53foq+9etB2HAzlPjAS/wa7r0uUpXw5ByX3/0uswVSrjNb17vJm1kQ==} - '@vue/compiler-sfc@3.4.26': - resolution: {integrity: sha512-It1dp+FAOCgluYSVYlDn5DtZBxk1NCiJJfu2mlQqa/b+k8GL6NG/3/zRbJnHdhV2VhxFghaDq5L4K+1dakW6cw==} - - '@vue/compiler-ssr@3.4.26': - resolution: {integrity: sha512-FNwLfk7LlEPRY/g+nw2VqiDKcnDTVdCfBREekF8X74cPLiWHUX6oldktf/Vx28yh4STNy7t+/yuLoMBBF7YDiQ==} + '@vue/compiler-ssr@3.4.31': + resolution: {integrity: sha512-RtefmITAje3fJ8FSg1gwgDhdKhZVntIVbwupdyZDSifZTRMiWxWehAOTCc8/KZDnBOcYQ4/9VWxsTbd3wT0hAA==} '@vue/devtools-api@6.6.1': resolution: {integrity: sha512-LgPscpE3Vs0x96PzSSB4IGVSZXZBZHpfxs+ZA1d+VEPwHdOXowy/Y2CsvCAIFrf+ssVU1pD1jidj505EpUnfbA==} @@ -5057,28 +5537,33 @@ packages: typescript: optional: true - '@vue/reactivity@3.4.26': - resolution: {integrity: sha512-E/ynEAu/pw0yotJeLdvZEsp5Olmxt+9/WqzvKff0gE67tw73gmbx6tRkiagE/eH0UCubzSlGRebCbidB1CpqZQ==} - - '@vue/runtime-core@3.4.26': - resolution: {integrity: sha512-AFJDLpZvhT4ujUgZSIL9pdNcO23qVFh7zWCsNdGQBw8ecLNxOOnPcK9wTTIYCmBJnuPHpukOwo62a2PPivihqw==} - - '@vue/runtime-dom@3.4.26': - resolution: {integrity: sha512-UftYA2hUXR2UOZD/Fc3IndZuCOOJgFxJsWOxDkhfVcwLbsfh2CdXE2tG4jWxBZuDAs9J9PzRTUFt1PgydEtItw==} - - '@vue/server-renderer@3.4.26': - resolution: {integrity: sha512-xoGAqSjYDPGAeRWxeoYwqJFD/gw7mpgzOvSxEmjWaFO2rE6qpbD1PC172YRpvKhrihkyHJkNDADFXTfCyVGhKw==} + '@vue/language-core@2.0.24': + resolution: {integrity: sha512-997YD6Lq/66LXr3ZOLNxDCmyn13z9NP8LU1UZn9hGCDWhzlbXAIP0hOgL3w3x4RKEaWTaaRtsHP9DzHvmduruQ==} peerDependencies: - vue: 3.4.26 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true - '@vue/shared@3.4.21': - resolution: {integrity: sha512-PuJe7vDIi6VYSinuEbUIQgMIRZGgM8e4R+G+/dQTk0X1NEdvgvvgv7m+rfmDH1gZzyA1OjjoWskvHlfRNfQf3g==} + '@vue/reactivity@3.4.31': + resolution: {integrity: sha512-VGkTani8SOoVkZNds1PfJ/T1SlAIOf8E58PGAhIOUDYPC4GAmFA2u/E14TDAFcf3vVDKunc4QqCe/SHr8xC65Q==} - '@vue/shared@3.4.25': - resolution: {integrity: sha512-k0yappJ77g2+KNrIaF0FFnzwLvUBLUYr8VOwz+/6vLsmItFp51AcxLL7Ey3iPd7BIRyWPOcqUjMnm7OkahXllA==} + '@vue/runtime-core@3.4.31': + resolution: {integrity: sha512-LDkztxeUPazxG/p8c5JDDKPfkCDBkkiNLVNf7XZIUnJ+66GVGkP+TIh34+8LtPisZ+HMWl2zqhIw0xN5MwU1cw==} - '@vue/shared@3.4.26': - resolution: {integrity: sha512-Fg4zwR0GNnjzodMt3KRy2AWGMKQXByl56+4HjN87soxLNU9P5xcJkstAlIeEF3cU6UYOzmJl1tV0dVPGIljCnQ==} + '@vue/runtime-dom@3.4.31': + resolution: {integrity: sha512-2Auws3mB7+lHhTFCg8E9ZWopA6Q6L455EcU7bzcQ4x6Dn4cCPuqj6S2oBZgN2a8vJRS/LSYYxwFFq2Hlx3Fsaw==} + + '@vue/server-renderer@3.4.31': + resolution: {integrity: sha512-D5BLbdvrlR9PE3by9GaUp1gQXlCNadIZytMIb8H2h3FMWJd4oUfkUTEH2wAr3qxoRz25uxbTcbqd3WKlm9EHQA==} + peerDependencies: + vue: 3.4.31 + + '@vue/shared@3.4.29': + resolution: {integrity: sha512-hQ2gAQcBO/CDpC82DCrinJNgOHI2v+FA7BDW4lMSPeBpQ7sRe2OLHWe5cph1s7D8DUQAwRt18dBDfJJ220APEA==} + + '@vue/shared@3.4.31': + resolution: {integrity: sha512-Yp3wtJk//8cO4NItOPpi3QkLExAr/aLBGZMmTtW9WpdwBCJpRM6zj9WgWktXAl8IDIozwNMByT45JP3tO3ACWA==} '@vue/test-utils@2.4.1': resolution: {integrity: sha512-VO8nragneNzUZUah6kOjiFmD/gwRjUauG9DROh6oaOeFwX1cZRUNHhdeogE8635cISigXFTtGLUQWx5KCb0xeg==} @@ -5089,8 +5574,8 @@ packages: '@vue/server-renderer': optional: true - '@webgpu/types@0.1.30': - resolution: {integrity: sha512-9AXJSmL3MzY8ZL//JjudA//q+2kBRGhLBFpkdGksWIuxrMy81nFrCzj2Am+mbh8WoU6rXmv7cY5E3rdlyru2Qg==} + '@webgpu/types@0.1.38': + resolution: {integrity: sha512-7LrhVKz2PRh+DD7+S+PVaFd5HxaWQvoMqBbsV9fNJO1pjUs1P8bM2vQVNfk+3URTqbuTI7gkXi0rfsN0IadoBA==} '@yarnpkg/esbuild-plugin-pnp@3.0.0-rc.15': resolution: {integrity: sha512-kYzDJO5CA9sy+on/s2aIW0411AklfCi8Ck/4QDivOqsMKpStZA2SsR+X27VTggGwpStWaLrjJcDcdDMowtG8MA==} @@ -5152,8 +5637,8 @@ packages: engines: {node: '>=0.4.0'} hasBin: true - acorn@8.11.3: - resolution: {integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==} + acorn@8.12.0: + resolution: {integrity: sha512-RTvkC4w+KNXrM39/lWCUaG0IbRkWdCv7W/IOW9oU6SawyxulvkQy5HQPVTKxEjczcUvapcrw3cFx/60VN/NRNw==} engines: {node: '>=0.4.0'} hasBin: true @@ -5185,9 +5670,9 @@ packages: resolution: {integrity: sha512-gOsf2YwSlleG6IjRYG2A7k0HmBMEo6qVNk9Bp/EaLgAJT5ngH6PXbqa4ItvnEwCm/velL5jAnQgsHsWnjhGmvw==} engines: {node: '>=18'} - aiscript-vscode@https://codeload.github.com/aiscript-dev/aiscript-vscode/tar.gz/34bf4e1530efcf1efa855bd04e2dab39735e1b02: - resolution: {tarball: https://codeload.github.com/aiscript-dev/aiscript-vscode/tar.gz/34bf4e1530efcf1efa855bd04e2dab39735e1b02} - version: 0.1.9 + aiscript-vscode@https://codeload.github.com/aiscript-dev/aiscript-vscode/tar.gz/e1e1b27f2f72cd28a473e004b6da0d8fc0bd40d9: + resolution: {tarball: https://codeload.github.com/aiscript-dev/aiscript-vscode/tar.gz/e1e1b27f2f72cd28a473e004b6da0d8fc0bd40d9} + version: 0.1.11 engines: {vscode: ^1.83.0} ajv-draft-04@1.0.0: @@ -5206,12 +5691,26 @@ packages: ajv: optional: true + ajv-formats@3.0.1: + resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + ajv@6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + ajv@8.12.0: + resolution: {integrity: sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==} + ajv@8.13.0: resolution: {integrity: sha512-PRA911Blj99jR5RMeTunVbNXMF6Lp4vZXnk5GQjcnUWUTsrXtekg/pnmFFI2u/I36Y/2bITGS30GZCXei6uNkA==} + ajv@8.16.0: + resolution: {integrity: sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==} + ansi-colors@4.1.3: resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} engines: {node: '>=6'} @@ -5291,9 +5790,16 @@ packages: argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + aria-hidden@1.2.4: + resolution: {integrity: sha512-y+CcFFwelSXpLZk/7fMB2mUbGtX9lKycf1MWJ7CaTIERyitVlyQx6C+sxcROU2BAJ24OiZyK+8wj2i8AlBoS3A==} + engines: {node: '>=10'} + aria-query@5.1.3: resolution: {integrity: sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==} + aria-query@5.3.0: + resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==} + array-buffer-byte-length@1.0.0: resolution: {integrity: sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==} @@ -5369,6 +5875,9 @@ packages: async-mutex@0.5.0: resolution: {integrity: sha512-1A94B18jkJ3DYq284ohPxoXbfTA5HsQ7/Mf4DEhcyLx3Bz27Rh59iScbB6EPiP+B+joue6YCxcMXSbFC1tZKwA==} + async@0.2.10: + resolution: {integrity: sha512-eAkdoKxU6/LkKDBzLpT+t6Ff5EtfSF4wx1WfJiPEEV7WNLnDaRXk0oVysiEPm262roaachGexwUv94WhSgN5TQ==} + async@3.2.4: resolution: {integrity: sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==} @@ -5390,8 +5899,8 @@ packages: avvio@8.3.0: resolution: {integrity: sha512-VBVH0jubFr9LdFASy/vNtm5giTrnbVquWBhT0fyizuNK2rQ7e7ONU2plZQWUNqtE1EmxFEb+kbSkFRkstiaS9Q==} - aws-sdk-client-mock@3.0.1: - resolution: {integrity: sha512-9VAzJLl8mz99KP9HjOm/93d8vznRRUTpJooPBOunRdUAnVYopCe9xmMuu7eVemu8fQ+w6rP7o5bBK1kAFkB2KQ==} + aws-sdk-client-mock@4.0.1: + resolution: {integrity: sha512-yD2mmgy73Xce097G5hIpr1k7j50qzvJ49/+6osGZiCyk4m6cwhb+2x7kKFY1gEMwTzaS8+m8fXv9SB29SkRYyQ==} aws-sign2@0.7.0: resolution: {integrity: sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==} @@ -5427,18 +5936,18 @@ packages: resolution: {integrity: sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - babel-plugin-polyfill-corejs2@0.4.6: - resolution: {integrity: sha512-jhHiWVZIlnPbEUKSSNb9YoWcQGdlTLq7z1GHL4AjFxaoOUMuuEVJ+Y4pAaQUGOGk93YsVCKPbqbfw3m0SM6H8Q==} + babel-plugin-polyfill-corejs2@0.4.11: + resolution: {integrity: sha512-sMEJ27L0gRHShOh5G54uAAPaiCOygY/5ratXuiyb2G46FmlSpc9eFCzYVyDiPxfNbwzA7mYahmjQc5q+CZQ09Q==} peerDependencies: '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 - babel-plugin-polyfill-corejs3@0.8.6: - resolution: {integrity: sha512-leDIc4l4tUgU7str5BWLS2h8q2N4Nf6lGZP6UrNDxdtfF2g69eJ5L0H7S8A5Ln/arfFAfHor5InAdZuIOwZdgQ==} + babel-plugin-polyfill-corejs3@0.10.4: + resolution: {integrity: sha512-25J6I8NGfa5YkCDogHRID3fVCadIR8/pGl1/spvCkzb6lVn6SR3ojpx9nOn9iEBcUsjY24AmdKm5khcfKdylcg==} peerDependencies: '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 - babel-plugin-polyfill-regenerator@0.5.3: - resolution: {integrity: sha512-8sHeDOmXC8csczMrYEOf0UTNa4yE2SxV5JGeT/LP1n0OYVDUUFPxG9vdk2AlDlIit4t+Kf0xCtpgXPBwnn/9pw==} + babel-plugin-polyfill-regenerator@0.6.2: + resolution: {integrity: sha512-2R25rQZWP63nGwaAswvDazbPXfrM3HwVoBXK6HcqeKrSrL/JqcC/rDcf95l4r7LXLyxDXc8uQDa064GubtCABg==} peerDependencies: '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 @@ -5511,10 +6020,6 @@ packages: bn.js@4.12.0: resolution: {integrity: sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==} - body-parser@1.20.1: - resolution: {integrity: sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==} - engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} - body-parser@1.20.2: resolution: {integrity: sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} @@ -5539,6 +6044,10 @@ packages: resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} engines: {node: '>=8'} + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + broadcast-channel@7.0.0: resolution: {integrity: sha512-a2tW0Ia1pajcPBOGUF2jXlDnvE9d5/dg6BG9h60OmRUcZVr/veUrU8vEQFwwQIhwG3KVzYwSk3v2nRRGFgQDXQ==} @@ -5583,12 +6092,12 @@ packages: buffer@6.0.3: resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} - bufferutil@4.0.7: - resolution: {integrity: sha512-kukuqc39WOHtdxtw4UScxF/WVnMFVSQVKhtx3AjZJzhd0RGZZldcrfSEbVsWWe6KNH253574cq5F+wpv0G9pJw==} + bufferutil@4.0.8: + resolution: {integrity: sha512-4T53u4PdgsXqKaIctwF8ifXlRTTmEPJ8iEPWFdGZvcf7sbwYo6FKFEX9eNNAnzFZ7EzJAQ3CJeOtCRA4rDp7Pw==} engines: {node: '>=6.14.2'} - bullmq@5.7.8: - resolution: {integrity: sha512-F/Haeu6AVHkFrfeaU/kLOjhfrH6x3CaKAZlQQ+76fa8l3kfI9oaUHeFMW+1mYVz0NtYPF7PNTWFq4ylAHYcCgA==} + bullmq@5.8.3: + resolution: {integrity: sha512-RJgQu/vgSZqjOYrZ7F1UJsSAzveNx7FFpR3Tp/1TxOMXXN9TtZMSly5MT+vjzOhQX//3+YWNRbMWpC1mkqBc9w==} buraha@0.0.1: resolution: {integrity: sha512-G563A0mTbzknm2jDaNxfZuNKIdeArs8T+XQN6t+KbmgnOoevXSXhKDkyf8Md/36Jrx99ikwbCag37VGe3myExQ==} @@ -5625,6 +6134,10 @@ packages: resolution: {integrity: sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ==} engines: {node: '>=14.16'} + cacheable-request@12.0.1: + resolution: {integrity: sha512-Yo9wGIQUaAfIbk+qY0X4cDQgCosecfBe3V9NSyeY4qPC2SAkbCS4Xj79VP8WOzitpJUZKc/wsRCYF5ariDIwkg==} + engines: {node: '>=18'} + cacheable-request@7.0.2: resolution: {integrity: sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew==} engines: {node: '>=8'} @@ -5714,8 +6227,8 @@ packages: character-parser@2.2.0: resolution: {integrity: sha512-+UqJQjFEFaTAs3bNsF2j2kEN1baG/zghZbdqoYEDxGZtJo9LBzl1A+m0D4n3qKx8N2FNv8/Xp6yV9mQmBuptaw==} - chart.js@4.4.2: - resolution: {integrity: sha512-6GD7iKwFpP5kbSD4MeRRRlTnQvxfQREy36uEtm1hzHzcOqwWx0YEHuspuoNlslu+nciLIB7fjjsHkUv/FzFcOg==} + chart.js@4.4.3: + resolution: {integrity: sha512-qK1gkGSRYcJzqrrzdR6a+I0vQ4/R+SoODXyAjscQ/4mzuNzySaMCd+hyVxitSY1+L2fjPD1Gbn+ibNqRmwQeLw==} engines: {pnpm: '>=8'} chartjs-adapter-date-fns@3.0.0: @@ -5764,8 +6277,8 @@ packages: resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} engines: {node: '>=10'} - chromatic@11.3.0: - resolution: {integrity: sha512-q1ZtJDJrjLGnz60ivpC16gmd7KFzcaA4eTb7gcytCqbaKqlHhCFr1xQmcUDsm14CK7JsqdkFU6S+JQdOd2ZNJg==} + chromatic@11.5.4: + resolution: {integrity: sha512-+J+CopeUSyGUIQJsU6X7CfvSmeVBs0j6LZ9AgF4+XTjI4pFmUiUXsTc00rH9x9W1jCppOaqDXv2kqJJXGDK3mA==} hasBin: true peerDependencies: '@chromatic-com/cypress': ^0.*.* || ^1.0.0 @@ -5800,10 +6313,6 @@ packages: engines: {node: '>=8.0.0', npm: '>=5.0.0'} hasBin: true - cli-spinners@2.7.0: - resolution: {integrity: sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw==} - engines: {node: '>=6'} - cli-spinners@2.9.2: resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} engines: {node: '>=6'} @@ -5983,8 +6492,8 @@ packages: resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==} engines: {node: '>= 0.6'} - core-js-compat@3.33.3: - resolution: {integrity: sha512-cNzGqFsh3Ot+529GIXacjTJ7kegdt5fPXxCBVS1G0iaZpuo/tBz399ymceLJveQhFFZ8qThHiP3fzuoQjKN2ow==} + core-js-compat@3.37.1: + resolution: {integrity: sha512-9TNiImhKvQqSUkOvk/mMRZzOANTiEVC7WaBNhHcKM7x+/5E1l5NvsysR19zuDQScE8k+kfQXWRN3AtS/eOSHpg==} core-js@3.29.1: resolution: {integrity: sha512-+jwgnhg6cQxKYIIjGtAHq2nwUOolo9eoFZ4sHfUH09BLXBgxnH4gA0zEd+t+BO2cNB8idaBtZFcFTRjQJRJmAw==} @@ -6038,9 +6547,9 @@ packages: resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} engines: {node: '>= 8'} - crypto-random-string@2.0.0: - resolution: {integrity: sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==} - engines: {node: '>=8'} + crypto-random-string@4.0.0: + resolution: {integrity: sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA==} + engines: {node: '>=12'} css-declaration-sorter@7.2.0: resolution: {integrity: sha512-h70rUM+3PNFuaBDTLe8wF/cdWu+dOZmb7pJt8Z2sedYbAcQVQV/tEchueg3GWxwqS0cxtbxmaHEdkNACqcvsow==} @@ -6103,13 +6612,8 @@ packages: cwise-compiler@1.1.3: resolution: {integrity: sha512-WXlK/m+Di8DMMcCjcWr4i+XzcQra9eCdXIJrgh4TUgh0pIS/yJduLxS9JgefsHJ/YVLdgPtXm9r62W92MvanEQ==} - cypress@13.7.3: - resolution: {integrity: sha512-uoecY6FTCAuIEqLUYkTrxamDBjMHTYak/1O7jtgwboHiTnS1NaMOoR08KcTrbRZFCBvYOiS4tEkQRmsV+xcrag==} - engines: {node: ^16.0.0 || ^18.0.0 || >=20.0.0} - hasBin: true - - cypress@13.8.1: - resolution: {integrity: sha512-Uk6ovhRbTg6FmXjeZW/TkbRM07KPtvM5gah1BIMp4Y2s+i/NMxgaLw0+PbYTOdw1+egE0FP3mWRiGcRkjjmhzA==} + cypress@13.13.0: + resolution: {integrity: sha512-ou/MQUDq4tcDJI2FsPaod2FZpex4kpIK43JJlcBgWrX8WX7R/05ZxGTuxedOuZBfxjZxja+fbijZGyxiLP6CFA==} engines: {node: ^16.0.0 || ^18.0.0 || >=20.0.0} hasBin: true @@ -6163,6 +6667,15 @@ packages: supports-color: optional: true + debug@4.3.5: + resolution: {integrity: sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + decamelize-keys@1.1.1: resolution: {integrity: sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==} engines: {node: '>=0.10.0'} @@ -6236,10 +6749,6 @@ packages: defu@6.1.4: resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} - del@6.1.1: - resolution: {integrity: sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg==} - engines: {node: '>=10'} - delayed-stream@1.0.0: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} @@ -6279,6 +6788,9 @@ packages: resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} engines: {node: '>=8'} + detect-node-es@1.1.0: + resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} + detect-package-manager@2.0.1: resolution: {integrity: sha512-j/lJHyoLlWi6G1LDdLgvUtz60Zo5GEj+sVYtTVXnYLDPuzgC3llMxonXym9zIwhhUII8vjdw0LXxavpLqTbl1A==} engines: {node: '>=12'} @@ -6301,6 +6813,10 @@ packages: resolution: {integrity: sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==} engines: {node: '>=0.3.1'} + diff@5.2.0: + resolution: {integrity: sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==} + engines: {node: '>=0.3.1'} + dijkstrajs@1.0.2: resolution: {integrity: sha512-QV6PMaHTCNmKSeP6QoXhVTw9snc9VD8MulTT0Bd99Pacp4SS1cjcrYPgBPmibqKVtMJJfqC6XvOXgPMEEPH/fg==} @@ -6372,8 +6888,8 @@ packages: ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} - ejs@3.1.9: - resolution: {integrity: sha512-rC+QVNMJWv+MtPgkt0y+0rVEIdbtxVADApW9JXrUVlzHetgcyczP/E7DJmWJ4fJCZF2cPcBk0laWO9ZHMG3DmQ==} + ejs@3.1.10: + resolution: {integrity: sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==} engines: {node: '>=0.10.0'} hasBin: true @@ -6439,8 +6955,8 @@ packages: es-get-iterator@1.1.3: resolution: {integrity: sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==} - es-module-lexer@0.9.3: - resolution: {integrity: sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==} + es-module-lexer@1.5.4: + resolution: {integrity: sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==} es-set-tostringtag@2.0.1: resolution: {integrity: sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==} @@ -6477,11 +6993,16 @@ packages: engines: {node: '>=12'} hasBin: true - esbuild@0.20.2: - resolution: {integrity: sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==} + esbuild@0.21.5: + resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} engines: {node: '>=12'} hasBin: true + esbuild@0.22.0: + resolution: {integrity: sha512-zNYA6bFZsVnsU481FnGAQjLDW0Pl/8BGG7EvAp15RzUvGC+ME7hf1q7LvIfStEQBz/iEHuBJCYcOwPmNCf1Tlw==} + engines: {node: '>=18'} + hasBin: true + escalade@3.1.1: resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} engines: {node: '>=6'} @@ -6551,8 +7072,8 @@ packages: '@typescript-eslint/parser': optional: true - eslint-plugin-vue@9.25.0: - resolution: {integrity: sha512-tDWlx14bVe6Bs+Nnh3IGrD+hb11kf2nukfm6jLsmJIhmiRQ1SUaksvwY9U5MvPB0pcrg0QK0xapQkfITs3RKOA==} + eslint-plugin-vue@9.26.0: + resolution: {integrity: sha512-eTvlxXgd4ijE1cdur850G6KalZqk65k1JKoOI2d1kT3hr8sPD07j1q98FRFdNnpxBELGPWxZmInxeHGF/GxtqQ==} engines: {node: ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.2.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 @@ -6564,20 +7085,36 @@ packages: resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + eslint-scope@8.0.1: + resolution: {integrity: sha512-pL8XjgP4ZOmmwfFE8mEhSxA7ZY4C+LWyqjQ3o4yWkkmD0qcMT9kkW3zWHOczhWcjTSgqycYAgwSlXvZltv65og==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint-scope@8.0.2: + resolution: {integrity: sha512-6E4xmrTw5wtxnLA5wYL3WDfhZ/1bUBGOXV0zQvVRDOtrR8D0p6W7fs3JweNYhwRYeGvd/1CKX2se0/2s7Q/nJA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + 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} - eslint@8.53.0: - resolution: {integrity: sha512-N4VuiPjXDUa4xVeV/GC/RV3hQW9Nw+Y463lkWaKKXKYMvmRiRDAtfpuPFLN+E1/6ZhyR8J2ig+eVREnYgUsiag==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + eslint-visitor-keys@4.0.0: + resolution: {integrity: sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint@9.6.0: + resolution: {integrity: sha512-ElQkdLMEEqQNM9Njff+2Y4q2afHk7JpkPvrd7Xh7xefwgQynqPxwf55J7di9+MEibWUGdNjFF9ITG9Pck5M84w==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} hasBin: true - eslint@8.57.0: - resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + eslint@9.7.0: + resolution: {integrity: sha512-FzJ9D/0nGiCGBf8UXO/IGLTgLVzIxze1zpfA8Ton2mjLovXdAPlYDv+MQDcqj3TmrhAGYfOpz9RfR+ent0AgAw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} hasBin: true + espree@10.1.0: + resolution: {integrity: sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + espree@9.6.1: resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -6591,6 +7128,14 @@ packages: resolution: {integrity: sha512-JVSoLdTlTDkmjFmab7H/9SL9qGSyjElT3myyKp7krqjVFQCDLmj1QFaCLRFBszBKI0XVZaiiXvuPIX3ZwHe1Ng==} engines: {node: '>=0.10'} + esquery@1.5.0: + resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==} + engines: {node: '>=0.10'} + + esquery@1.6.0: + resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} + engines: {node: '>=0.10'} + esrecurse@4.3.0: resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} engines: {node: '>=4.0'} @@ -6653,6 +7198,10 @@ packages: resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} engines: {node: '>=16.17'} + execa@9.2.0: + resolution: {integrity: sha512-vpOyYg7UAVKLAWWtRS2gAdgkT7oJbCn0me3gmUmxZih4kd3MF/oo8kNTBTIbkO3yuuF5uB4ZCZfn8BOolITYhg==} + engines: {node: ^18.19.0 || >=20.5.0} + executable@4.1.1: resolution: {integrity: sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg==} engines: {node: '>=4'} @@ -6668,10 +7217,6 @@ packages: exponential-backoff@3.1.1: resolution: {integrity: sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==} - express@4.18.2: - resolution: {integrity: sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==} - engines: {node: '>= 0.10.0'} - express@4.19.2: resolution: {integrity: sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==} engines: {node: '>= 0.10.0'} @@ -6745,11 +7290,8 @@ packages: resolution: {integrity: sha512-F4o8ZIMVx4YoxGfwrZys6wyjl40gF3Yv6AWWRy62ozFAyZBSS831/uyyCAqKYw3tR73g180ryG98yih6To1PUQ==} engines: {node: '>= 10'} - fastify@4.26.2: - resolution: {integrity: sha512-90pjTuPGrfVKtdpLeLzND5nyC4woXZN5VadiNQCicj/iJU4viNHKhsAnb7jmv1vu2IzkLXyBiCzdWuzeXgQ5Ug==} - - fastq@1.15.0: - resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==} + fastify@4.28.1: + resolution: {integrity: sha512-kFWUtpNr4i7t5vY2EJPCN2KgMVpuqfU4NjnJNCgiNB900oiDeYqaNDRcAfeBbOF5hGixixxcKnOU4KN9z6QncQ==} fastq@1.17.1: resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} @@ -6775,9 +7317,13 @@ packages: resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==} engines: {node: '>=8'} - file-entry-cache@6.0.1: - resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} - engines: {node: ^10.12.0 || >=12.0.0} + figures@6.1.0: + resolution: {integrity: sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==} + engines: {node: '>=18'} + + file-entry-cache@8.0.0: + resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} + engines: {node: '>=16.0.0'} file-system-cache@2.3.0: resolution: {integrity: sha512-l4DMNdsIPsVnKrgEXbJwDJsA5mB8rGwHYERMgqQx/xAUtChPJMre1bXBzDEqqVbWv9AIbFezXMxeEkZDSrXUOQ==} @@ -6805,6 +7351,10 @@ packages: resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} engines: {node: '>=8'} + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + finalhandler@1.2.0: resolution: {integrity: sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==} engines: {node: '>= 0.8'} @@ -6844,20 +7394,20 @@ packages: resolution: {integrity: sha512-MdYSsbdCaIRjzo5edthZtWmEZVMfr1qrtYZUHIdO3swCE+CoZA8S5l0s4jDsYlTa9ZiXv0pTgpzE7s4N8NeUOA==} engines: {node: '>=18'} - 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'} - flatted@3.2.7: - resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==} + flatted@3.3.1: + resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==} flow-parser@0.202.0: resolution: {integrity: sha512-ZiXxSIXK3zPmY3zrzCofFonM2T+/3Jz5QZKJyPVtUERQEJUnYkXBQ+0H3FzyqiyJs+VXqb/UNU6/K6sziVYdxw==} engines: {node: '>=0.4.0'} - fluent-ffmpeg@2.1.2: - resolution: {integrity: sha512-IZTB4kq5GK0DPp7sGQ0q/BWurGHffRtQQwVkiqDgeO6wYJLLV5ZhgNOQ65loZxxuPMKZKZcICCUnaGtlxBiR0Q==} - engines: {node: '>=0.8.0'} + fluent-ffmpeg@2.1.3: + resolution: {integrity: sha512-Be3narBNt2s6bsaqP6Jzq91heDgOEaDCJAXcE3qcma/EJBSy5FB4cvO31XBInuAuKBx8Kptf8dkhjK0IOru39Q==} + engines: {node: '>=18'} follow-redirects@1.15.2: resolution: {integrity: sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==} @@ -6890,10 +7440,6 @@ packages: resolution: {integrity: sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==} engines: {node: '>= 0.12'} - form-data@3.0.1: - resolution: {integrity: sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==} - engines: {node: '>= 6'} - form-data@4.0.0: resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} engines: {node: '>= 6'} @@ -6932,15 +7478,12 @@ packages: resolution: {integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==} engines: {node: '>=10'} - fs-minipass@1.2.7: - resolution: {integrity: sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==} - fs-minipass@2.1.0: resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==} engines: {node: '>= 8'} - fs-minipass@3.0.2: - resolution: {integrity: sha512-2GAfyfoaCDRrM6jaOS3UsBts8yJ55VioXdWcOL7dK9zdAuKT71+WBA4ifnNYqVjYv+4SsPxjK0JT4yIIn4cA/g==} + fs-minipass@3.0.3: + resolution: {integrity: sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} fs.realpath@1.0.0: @@ -6979,6 +7522,10 @@ packages: get-intrinsic@1.2.1: resolution: {integrity: sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==} + get-nonce@1.0.1: + resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} + engines: {node: '>=6'} + get-npm-tarball-url@2.0.3: resolution: {integrity: sha512-R/PW6RqyaBQNWYaSyfrh54/qtcnOp22FHCCiRhSSZj0FP3KQWCsxxt0DzIdVTbwTqe9CtQfvl/FPD4UIPt4pqw==} engines: {node: '>=12.17'} @@ -7006,6 +7553,10 @@ packages: resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==} engines: {node: '>=16'} + get-stream@9.0.1: + resolution: {integrity: sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==} + engines: {node: '>=18'} + get-symbol-description@1.0.0: resolution: {integrity: sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==} engines: {node: '>= 0.4'} @@ -7057,12 +7608,19 @@ packages: engines: {node: '>=16 || 14 >=14.17'} hasBin: true + glob@10.4.2: + resolution: {integrity: sha512-GwMlUF6PkPo3Gk21UxkCohOv0PLcIXVtKyLlpEI28R/cO/4eNOdmLk3CMW1wROV/WR/EsZOWAfBbBOqYvs88/w==} + engines: {node: '>=16 || 14 >=14.18'} + hasBin: true + glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + deprecated: Glob versions prior to v9 are no longer supported glob@8.1.0: resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==} engines: {node: '>=12'} + deprecated: Glob versions prior to v9 are no longer supported global-dirs@3.0.1: resolution: {integrity: sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==} @@ -7072,14 +7630,18 @@ packages: resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} engines: {node: '>=4'} - globals@13.19.0: - resolution: {integrity: sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==} - engines: {node: '>=8'} - globals@13.24.0: resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} engines: {node: '>=8'} + globals@14.0.0: + resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} + engines: {node: '>=18'} + + globals@15.7.0: + resolution: {integrity: sha512-ivatRXWwKC6ImcdKO7dOwXuXR5XFrdwo45qFwD7D0qOkEPzzJdLXC3BHceBdyrPOD3p1suPaWi4Y4NMm2D++AQ==} + engines: {node: '>=18'} + globalthis@1.0.3: resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==} engines: {node: '>= 0.4'} @@ -7088,6 +7650,10 @@ packages: resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} engines: {node: '>=10'} + globby@14.0.1: + resolution: {integrity: sha512-jOMLD2Z7MAhyG8aJpNOpmziMOP4rPLcc95oQPKXBazW82z+CEgPFBQvEpRUa1KeIMUJo4Wsm+q6uzO/Q/4BksQ==} + engines: {node: '>=18'} + google-protobuf@3.21.2: resolution: {integrity: sha512-3MSOYFO5U9mPGikIYCzK0SaThypfGgS6bHqrUGXG3DPHCrb+txNqeEcns1W0lkGfk0rCyNXm7xB9rMxnCiZOoA==} @@ -7102,8 +7668,8 @@ packages: resolution: {integrity: sha512-mThBblvlAF1d4O5oqyvN+ZxLAYwIJK7bpMxgYqPD9okW0C3qm5FFn7k811QrcuEBwaogR3ngOFoCfs6mRv7teQ==} engines: {node: '>=14.16'} - got@14.2.1: - resolution: {integrity: sha512-KOaPMremmsvx6l9BLC04LYE6ZFW4x7e4HkTe3LwBmtuYYQwpeS4XKqzhubTIkaQ1Nr+eXxeori0zuwupXMovBQ==} + got@14.4.1: + resolution: {integrity: sha512-IvDJbJBUeexX74xNQuMIVgCRRuNOm5wuK+OC3Dc2pnSoh1AOmgc7JVj7WC+cJ4u0aPcO9KZ2frTXcqK4W/5qTQ==} engines: {node: '>=20'} graceful-fs@4.2.11: @@ -7261,6 +7827,10 @@ packages: resolution: {integrity: sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ==} engines: {node: '>= 14'} + http-proxy-agent@7.0.2: + resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} + engines: {node: '>= 14'} + http-signature@1.2.0: resolution: {integrity: sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==} engines: {node: '>=0.8', npm: '>=1.3.7'} @@ -7293,6 +7863,10 @@ packages: resolution: {integrity: sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA==} engines: {node: '>= 14'} + https-proxy-agent@7.0.4: + resolution: {integrity: sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==} + engines: {node: '>= 14'} + human-signals@1.1.1: resolution: {integrity: sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==} engines: {node: '>=8.12.0'} @@ -7309,6 +7883,10 @@ packages: resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} engines: {node: '>=16.17.0'} + human-signals@7.0.0: + resolution: {integrity: sha512-74kytxOUSvNbjrT9KisAbaTZ/eJwD/LrbM/kh5j0IhPuJzwuA19dWvniFGwBzN9rVjg+O/e+F310PjObDXS+9Q==} + engines: {node: '>=18.18.0'} + iconv-lite@0.4.24: resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} engines: {node: '>=0.10.0'} @@ -7348,8 +7926,8 @@ packages: import-in-the-middle@1.4.2: resolution: {integrity: sha512-9WOz1Yh/cvO/p69sxRmhyQwrIGGSp7EIdcb+fFNVi7CzQGQB8U1/1XrKVSbEd/GNOAeM0peJtmi7+qphe7NvAw==} - import-in-the-middle@1.7.4: - resolution: {integrity: sha512-Lk+qzWmiQuRPPulGQeK5qq0v32k2bHnWrRPFgqyvhw7Kkov5L6MOLOIU3pcWeujc9W4q54Cp3Q2WV16eQkc7Bg==} + import-in-the-middle@1.8.1: + resolution: {integrity: sha512-yhRwoHtiLGvmSozNOALgjRPFI6uYsds60EoMqqnXyyv+JOIW/BrrLejuTGBt+bq0T5tLzOHrN0T7xYTm4Qt/ng==} import-lazy@4.0.0: resolution: {integrity: sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==} @@ -7399,6 +7977,9 @@ packages: intersection-observer@0.12.2: resolution: {integrity: sha512-7m1vEcPCxXYI8HqnL8CKI6siDyD+eIWSwgB3DZA+ZTogxk9I4CDnj4wilt9x/+/QbHI4YG5YZNmC6458/e9Ktg==} + invariant@2.2.4: + resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==} + ioredis@5.4.1: resolution: {integrity: sha512-2YZsvl7jopIa1gaePkeMtd9rAcSjOOjPtpcLlOeusyO+XH2SK5ZcT+UCrElPP+WVIInh2TzeI4XW9ENaSLVVHA==} engines: {node: '>=12.22.0'} @@ -7406,13 +7987,13 @@ packages: iota-array@1.0.0: resolution: {integrity: sha512-pZ2xT+LOHckCatGQ3DcG/a+QuEqvoxqkiL7tvE8nn3uuu+f6i1TtpB5/FtWFbxUuVr5PZCx8KskuGatbJDXOWA==} - ip-address@7.1.0: - resolution: {integrity: sha512-V9pWC/VJf2lsXqP7IWJ+pe3P1/HCYGBMZrrnT62niLGjAfCbeiwXMUxaeHvnVlz19O27pvXP4azs+Pj/A0x+SQ==} - engines: {node: '>= 10'} + ip-address@9.0.5: + resolution: {integrity: sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==} + engines: {node: '>= 12'} - ip-cidr@3.1.0: - resolution: {integrity: sha512-HUCn4snshEX1P8cja/IyU3qk8FVDW8T5zZcegDFbu4w7NojmAhk5NcOgj3M8+0fmumo1afJTPDtJlzsxLdOjtg==} - engines: {node: '>=10.0.0'} + ip-cidr@4.0.1: + resolution: {integrity: sha512-V5Nce94SVJ7NtyT/UKUeTM7sY3V7TEk48hURhtBgTiGduOa5t6p9Hd+zBOGvr4Gu7iWPxFVYNl017p0akQA84w==} + engines: {node: '>=16.14.0'} ip-regex@4.3.0: resolution: {integrity: sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q==} @@ -7554,10 +8135,6 @@ packages: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} - is-path-cwd@2.2.0: - resolution: {integrity: sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==} - engines: {node: '>=6'} - is-path-inside@3.0.3: resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} engines: {node: '>=8'} @@ -7606,12 +8183,16 @@ packages: resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + is-stream@4.0.1: + resolution: {integrity: sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==} + engines: {node: '>=18'} + is-string@1.0.7: resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==} engines: {node: '>= 0.4'} - is-svg@5.0.0: - resolution: {integrity: sha512-sRl7J0oX9yUNamSdc8cwgzh9KBLnQXNzGmW0RVHwg/jEYjGNYHC6UvnYD8+hAeut9WwxRvhG9biK7g/wDGxcMw==} + is-svg@5.0.1: + resolution: {integrity: sha512-mLYxDsfisQWdS4+gSblAwhATDoNMS/tx8G7BKA+aBIf7F0m1iUwMvuKAo6mW4WMleQAEE50I1Zqef9yMMfHk3w==} engines: {node: '>=14.16'} is-symbol@1.0.4: @@ -7629,6 +8210,10 @@ packages: resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} engines: {node: '>=10'} + is-unicode-supported@2.0.0: + resolution: {integrity: sha512-FRdAyx5lusK1iHG0TWpVtk9+1i+GjrzRffhDg4ovQ7mcidMQ6mj+MhKPmvh7Xwyv5gIS06ns49CA7Sqg7lC22Q==} + engines: {node: '>=18'} + is-weakmap@2.0.1: resolution: {integrity: sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==} @@ -7685,6 +8270,10 @@ packages: resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==} engines: {node: '>=10'} + istanbul-lib-source-maps@5.0.4: + resolution: {integrity: sha512-wHOoEsNJTVltaJp8eVkm8w+GVkVNHT2YDYo53YdzQEL2gWm1hBX5cGFR9hQJtuGLebidVX7et3+dmDZrmclduw==} + engines: {node: '>=10'} + istanbul-reports@3.1.6: resolution: {integrity: sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==} engines: {node: '>=8'} @@ -7697,6 +8286,10 @@ packages: resolution: {integrity: sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==} engines: {node: '>=14'} + jackspeak@3.4.0: + resolution: {integrity: sha512-JVYhQnN59LVPFCEcVa2C3CrEKYacvjRfqIQl+h8oi91aLYQVWRYbxjPcv1bUiUy/kLmQaANrYfNMCO3kuEDHfw==} + engines: {node: '>=14'} + jake@10.8.5: resolution: {integrity: sha512-sVpxYeuAhWt0OTWITwT98oyV0GsXyMlXCF+3L1SuafBVUIr/uILGRB+NqwkzhgXKvoJpDIpQvqkUALgdmQsQxw==} engines: {node: '>=10'} @@ -7857,6 +8450,9 @@ packages: js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + js-tokens@9.0.0: + resolution: {integrity: sha512-WriZw1luRMlmV3LGJaR6QOJjWwgLUTf89OwT2lUOyjX2dJGBwgmIkbcz+7WFZjrZM635JOIR517++e/67CP9dQ==} + js-yaml@3.14.1: resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} hasBin: true @@ -7884,8 +8480,8 @@ packages: '@babel/preset-env': optional: true - jsdom@24.0.0: - resolution: {integrity: sha512-UDS2NayCvmXSXVP6mpTj+73JnNQadZlr9N68189xib2tx5Mls7swlTNao26IoHv46BZJFvXygyRtyXd1feAk1A==} + jsdom@24.1.0: + resolution: {integrity: sha512-6gpM7pRXCwIOKxX47cgOyvyQDN/Eh0f1MeKySBV2xGdKtqJBLj8P25eY3EVCWo2mglDDzozR2r2MW4T+JiNUZA==} engines: {node: '>=18'} peerDependencies: canvas: ^2.11.2 @@ -7967,9 +8563,6 @@ packages: jsrsasign@11.1.0: resolution: {integrity: sha512-Ov74K9GihaK9/9WncTe1mPmvrO7Py665TUfUKvraXBpu+xcTWitrtuOwcjf4KMU9maPaYn0OuaWy0HOzy/GBXg==} - jssha@3.3.1: - resolution: {integrity: sha512-VCMZj12FCFMQYcFLPRm/0lOBbLi8uM2BhXPTqw3U4YAfs4AZfiApOoBLoN8cQE60Z50m1MYMTQVCfgF/KaCVhQ==} - jstransformer@1.0.0: resolution: {integrity: sha512-C9YK3Rf8q6VAPDCCU9fnqo3mAfOH6vUGnMcP4AQAYIEpWtfGLpwOTmZ+igtdK5y+VvI2n3CyYSzy4Qh34eq24A==} @@ -8046,8 +8639,8 @@ packages: enquirer: optional: true - local-pkg@0.4.3: - resolution: {integrity: sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==} + local-pkg@0.5.0: + resolution: {integrity: sha512-ok6z3qlYyCDS4ZEU27HaU6x/xZa9Whf8jD4ptH5UZTQYZVYeb9bnZ3ojVhiJNLiXK1Hfc0GNbLXcmZ5plLDDBg==} engines: {node: '>=14'} locate-path@3.0.0: @@ -8074,9 +8667,6 @@ packages: lodash.isarguments@3.1.0: resolution: {integrity: sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==} - lodash.isequal@4.5.0: - resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==} - lodash.memoize@4.1.2: resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} @@ -8158,9 +8748,8 @@ packages: magic-string@0.30.10: resolution: {integrity: sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==} - magic-string@0.30.7: - resolution: {integrity: sha512-8vBuFF/I/+OSLRmdf2wwFCJCz+nSn0m6DPvGH1fS/KiQoSaR+sETbov0eIk9KhEKy8CYqIkIAnbohxT/4H0kuA==} - engines: {node: '>=12'} + magicast@0.3.4: + resolution: {integrity: sha512-TyDF/Pn36bBji9rWKHlZe+PZb6Mx5V8IHCSxk7X4aljM4e/vyDvZZYwHewdVaqiA0nb3ghfHU/6AUpDxWoER2Q==} mailcheck@1.1.1: resolution: {integrity: sha512-3WjL8+ZDouZwKlyJBMp/4LeziLFXgleOdsYu87piGcMLqhBzCsy2QFdbtAwv757TFC/rtqd738fgJw1tFQCSgA==} @@ -8253,8 +8842,8 @@ packages: resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} engines: {node: '>= 0.6'} - meilisearch@0.38.0: - resolution: {integrity: sha512-bHaq8nYxSKw9/Qslq1Zes5g9tHgFkxy/I9o8942wv2PqlNOT0CzptIkh/x98N52GikoSZOXSQkgt6oMjtf5uZw==} + meilisearch@0.41.0: + resolution: {integrity: sha512-5KcGLxEXD7E+uNO7R68rCbGSHgCqeM3Q3RFFLSsN7ZrIgr8HPDXVAIlP4LHggAZfk0FkSzo8VSXifHCwa2k80g==} memoizerific@1.11.3: resolution: {integrity: sha512-/EuHYwAPdLtXwAwSZkh/Gutery6pD2KYd44oQLhAvQp/50mpyduZh8Q7PYHXTCJ+wuXxt7oij2LXyIJOOYFPog==} @@ -8368,8 +8957,8 @@ packages: micromark@4.0.0: resolution: {integrity: sha512-o/sd0nMof8kYff+TqcDx3VSrgBTcZpSvYcAHIfHhv5VAuNmisCxjhx6YmxS8PFEpb9z5WKWKPdzf0jM23ro3RQ==} - 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'} mime-db@1.52.0: @@ -8466,9 +9055,6 @@ packages: resolution: {integrity: sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==} engines: {node: '>=8'} - minipass@2.9.0: - resolution: {integrity: sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==} - minipass@3.3.6: resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==} engines: {node: '>=8'} @@ -8481,8 +9067,9 @@ packages: resolution: {integrity: sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==} engines: {node: '>=16 || 14 >=14.17'} - minizlib@1.3.3: - resolution: {integrity: sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==} + minipass@7.1.2: + resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} + engines: {node: '>=16 || 14 >=14.17'} minizlib@2.1.2: resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==} @@ -8542,13 +9129,13 @@ packages: msgpackr@1.10.1: resolution: {integrity: sha512-r5VRLv9qouXuLiIBrLpl2d5ZvPt8svdQTl5/vMvE4nzDMyEX4sgW5yWhuBBj5UmgwOTWj8CIdSXn5sAfsHAWIQ==} - msw-storybook-addon@2.0.1: - resolution: {integrity: sha512-pZ3JDQ9HkGQ3XDMIHvMcDSI4Vbp/LHmwHwiZu+pHLzimtI1vhAo1swjFEDAEJuBcozljYvREEC4sS7rQHPNtWg==} + msw-storybook-addon@2.0.2: + resolution: {integrity: sha512-sdw++X+AoUbaG2ku493ViVqCA/LfqnybXsKXyPUrF3ZS/x8BqGBnkBLmT/0SHCC5zIO3Vfm5zlclAxnhqOOikQ==} peerDependencies: msw: ^2.0.0 - msw@2.2.14: - resolution: {integrity: sha512-64i8rNCa1xzDK8ZYsTrVMli05D687jty8+Th+PU5VTbJ2/4P7fkQFVyDQ6ZFT5FrNR8z2BHhbY47fKNvfHrumA==} + msw@2.3.1: + resolution: {integrity: sha512-ocgvBCLn/5l3jpl1lssIb3cniuACJLoOfZu01e3n5dbJrpA5PeeWn28jCLgQDNt6d7QT8tF2fYRzm9JoEHtiig==} engines: {node: '>=18'} hasBin: true peerDependencies: @@ -8578,8 +9165,8 @@ packages: mz@2.7.0: resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} - nan@2.18.0: - resolution: {integrity: sha512-W7tfG7vMOGtD30sHoZSSc/JVYiyDPEyQVso/Zz+/uQd0B0L46gtC+pHha5FFMRpil6fm/AoEcRWyOVi4+E/f8w==} + nan@2.20.0: + resolution: {integrity: sha512-bk3gXBZDGILuuo/6sKtr0DQmSThYHLtNCdSdXk9YkxD/jK6X2vmCyyXBBxyqZ4XcnzTyYEAThfX3DCEnLf6igw==} nanoid@3.3.7: resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} @@ -8670,6 +9257,15 @@ packages: encoding: optional: true + node-fetch@2.6.13: + resolution: {integrity: sha512-StxNAxh15zr77QvvkmveSQ8uCQ4+v5FkvNTj0OESmiHu+VRi/gXArXtkWMElOsOUNLtUEvI4yS+rdtOHZTwlQA==} + engines: {node: 4.x || >=6.0.0} + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + node-fetch@2.7.0: resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} engines: {node: 4.x || >=6.0.0} @@ -8691,8 +9287,8 @@ packages: resolution: {integrity: sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ==} hasBin: true - node-gyp@10.0.1: - resolution: {integrity: sha512-gg3/bHehQfZivQVfqIyy8wTdSymF9yTyP4CJifK73imyNMU8AIGQE2pUa7dNWfmMeG9cDVF2eehiRMv0LC1iAg==} + node-gyp@10.1.0: + resolution: {integrity: sha512-B4J5M1cABxPc5PwfjhbV5hoy2DP9p8lFXASnEN6hugXOa61416tnTZ29x9sSwAd0o99XNIcpvDDy1swAExsVKA==} engines: {node: ^16.14.0 || >=18.0.0} hasBin: true @@ -8702,8 +9298,8 @@ packages: node-releases@2.0.14: resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==} - nodemailer@6.9.13: - resolution: {integrity: sha512-7o38Yogx6krdoBf3jCAqnIN4oSQFx+fMa0I7dK1D+me9kBxx12D+/33wSb+fhOCtIxvYJ+4x4IMEhmhCKfAiOA==} + nodemailer@6.9.14: + resolution: {integrity: sha512-Dobp/ebDKBvz91sbtRKhcznLThrKxKt97GI2FAlAyy+fk19j73Uz3sBXolVtmcXjaorivqsbbbjDY+Jkt4/bQA==} engines: {node: '>=6.0.0'} nodemon@3.0.2: @@ -8711,8 +9307,8 @@ packages: engines: {node: '>=10'} hasBin: true - nodemon@3.1.0: - resolution: {integrity: sha512-xqlktYlDMCepBJd43ZQhjWwMw2obW/JRvkrLxq5RCNcuDDX1DbcPT+qT1IlIIdf+DhnWs90JpTMe+Y5KxOchvA==} + nodemon@3.1.4: + resolution: {integrity: sha512-wjPBbFhtpJwmIeY2yP7QF+UKzPfltVGtfce1g/bB15/8vCGZj8uxD62b/b9M9/WVgme0NZudpownKN+c0plXlQ==} engines: {node: '>=10'} hasBin: true @@ -8758,6 +9354,10 @@ packages: resolution: {integrity: sha512-uVFpKhj5MheNBJRTiMZ9pE/7hD1QTeEvugSJW/OmLzAp78PB5O6adfMNTvmfKhXBkvCzC+rqifWcVYpGFwTjnw==} engines: {node: '>=14.16'} + normalize-url@8.0.1: + resolution: {integrity: sha512-IO9QvjUMWxPQQhs60oOu10CRkWCiZzSUkzbXGGV9pviYl1fXYcvkzQ5jV9z8Y6un8ARoVRl4EtC6v6jNqbaJ/w==} + engines: {node: '>=14.16'} + npm-run-path@2.0.2: resolution: {integrity: sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==} engines: {node: '>=4'} @@ -8770,6 +9370,10 @@ packages: resolution: {integrity: sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + npm-run-path@5.3.0: + resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + npmlog@5.0.1: resolution: {integrity: sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==} @@ -8781,8 +9385,8 @@ packages: nth-check@2.1.1: resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} - nwsapi@2.2.9: - resolution: {integrity: sha512-2f3F0SEEer8bBu0dsNCFF50N0cTThV1nWFYcEYFZttdW0lDAoybv9cQoK7X7/68Z89S7FoRrVjP1LPX4XRf9vg==} + nwsapi@2.2.10: + resolution: {integrity: sha512-QK0sRs7MKv0tKe1+5uZIQk/C8XGza4DAnztJG8iD+TpJIORARrCxczA738awHrZoHeTjSSoHqao2teO0dC/gFQ==} oauth-sign@0.9.0: resolution: {integrity: sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==} @@ -8881,6 +9485,10 @@ packages: resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==} engines: {node: '>= 0.8.0'} + optionator@0.9.4: + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} + engines: {node: '>= 0.8.0'} + ora@5.4.1: resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==} engines: {node: '>=10'} @@ -8895,8 +9503,8 @@ packages: ospath@1.2.2: resolution: {integrity: sha512-o6E5qJV5zkAbIDNhGSIlyOhScKXgQrSRMilfph0clDfM0nEnBOlKlH4sWDmG95BW/CvwNz0vmm7dJVtU2KlMiA==} - otpauth@9.2.3: - resolution: {integrity: sha512-oAG55Ch4MBL5Jdg+RXfKiRCZ2lCwa/UIQKsmSfYbGGLSI4dErY1HPZv0JGPPESIYGyDO3s9iJqM4HU/1IppMoQ==} + otpauth@9.3.1: + resolution: {integrity: sha512-E6d2tMxPofHNk4sRFp+kqW7vQ+WJGO9VLI2N/W00DnI+ThskU12Qa10kyNSGklrzhN5c+wRUsN4GijVgCU2N9w==} outvariant@1.4.2: resolution: {integrity: sha512-Ou3dJ6bA/UJ5GVHxah4LnqDwZRwAmWxrG3wtrHrbGnP4RnLCtA64A4F+ae7Y8ww660JaddSoArUR5HjipWSHAQ==} @@ -8925,9 +9533,9 @@ packages: resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} engines: {node: '>=10'} - p-limit@4.0.0: - resolution: {integrity: sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + p-limit@5.0.0: + resolution: {integrity: sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ==} + engines: {node: '>=18'} p-locate@3.0.0: resolution: {integrity: sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==} @@ -8957,6 +9565,9 @@ packages: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} + package-json-from-dist@1.0.0: + resolution: {integrity: sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==} + pako@0.2.9: resolution: {integrity: sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==} @@ -8971,6 +9582,10 @@ packages: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} + parse-ms@4.0.0: + resolution: {integrity: sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==} + engines: {node: '>=18'} + parse-srcset@1.0.2: resolution: {integrity: sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q==} @@ -9031,6 +9646,10 @@ packages: resolution: {integrity: sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA==} engines: {node: '>=16 || 14 >=14.17'} + path-scurry@1.11.1: + resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} + engines: {node: '>=16 || 14 >=14.18'} + path-to-regexp@0.1.7: resolution: {integrity: sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==} @@ -9047,6 +9666,10 @@ packages: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} + path-type@5.0.0: + resolution: {integrity: sha512-5HviZNaZcfqP95rwpv+1HDgUamezbqdSYTyzjTvwtJSnIH+3vnbmWsItli8OFEndS984VT55M3jduxZbX351gg==} + engines: {node: '>=12'} + pathe@1.1.2: resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} @@ -9088,9 +9711,6 @@ packages: peerDependencies: pg: '>=8.0' - pg-protocol@1.6.0: - resolution: {integrity: sha512-M+PDm637OY5WM307051+bsDia5Xej6d9IR4GwJse1qA1DIhiKlksvrneZOYQq42OM+spubpcNYEo2FcKQrDk+Q==} - pg-protocol@1.6.1: resolution: {integrity: sha512-jPIlvgoD63hrEuihvIg+tJhoGjUsLPn6poJY9N5CnlPd91c2T18T/9zBtLxZSb1EhYxBRoZJtzScCaWlYLtktg==} @@ -9102,8 +9722,8 @@ packages: resolution: {integrity: sha512-hRCSDuLII9/LE3smys1hRHcu5QGcLs9ggT7I/TCs0IE+2Eesxi9+9RWAAwZ0yaGjxoWICF/YHLOEjydGujoJ+g==} engines: {node: '>=10'} - pg@8.11.5: - resolution: {integrity: sha512-jqgNHSKL5cbDjFlHyYsCXmQDrfIX/3RsNwYqpd4N0Kt8niLuNoRNH+aazv6cOd43gPh9Y4DjQCtb+X0MH0Hvnw==} + pg@8.12.0: + resolution: {integrity: sha512-A+LHUSnwnxrnL/tZ+OLfqR1SxLN3c/pgDztZ47Rpbsd4jUytsTtwQo/TLPRzPJMp/1pbhYVhH9cuSZLAajNfjQ==} engines: {node: '>= 8.0.0'} peerDependencies: pg-native: '>=3.0.1' @@ -9114,8 +9734,8 @@ packages: pgpass@1.0.5: resolution: {integrity: sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==} - photoswipe@5.4.3: - resolution: {integrity: sha512-9UC6oJBK4oXFZ5HcdlcvGkfEHsVrmE4csUdCQhEjHYb3PvPLO3PG7UhnPuOgjxwmhq5s17Un5NUdum01LgBDng==} + photoswipe@5.4.4: + resolution: {integrity: sha512-WNFHoKrkZNnvFFhbHL93WDkW3ifwVOXSW3w1UuZZelSmgXpIGiZSNlZJq37rR8YejqME2rHs9EhH9ZvlvFH2NA==} engines: {node: '>= 0.12.0'} picocolors@1.0.0: @@ -9137,14 +9757,14 @@ packages: resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} engines: {node: '>=6'} - pino-abstract-transport@1.1.0: - resolution: {integrity: sha512-lsleG3/2a/JIWUtf9Q5gUNErBqwIu1tUKTT3dUzaf5DySw9ra1wcqKjJjLX1VTY64Wk1eEOYsVGSaGfCK85ekA==} + pino-abstract-transport@1.2.0: + resolution: {integrity: sha512-Guhh8EZfPCfH+PMXAb6rKOjGQEoy0xlAIn+irODG5kgfYV+BQ0rGYYWTIel3P5mmyXqkYkPmdIkywsn6QKUR1Q==} - pino-std-serializers@6.1.0: - resolution: {integrity: sha512-KO0m2f1HkrPe9S0ldjx7za9BJjeHqBku5Ch8JyxETxT8dEFGz1PwgrHaOQupVYitpzbFSYm7nnljxD8dik2c+g==} + pino-std-serializers@7.0.0: + resolution: {integrity: sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA==} - pino@8.17.0: - resolution: {integrity: sha512-ey+Mku+PVPhvxglLXMg1l1zQMwSHuNrKC3MD40EDZbkckJmmuY7DYZLIOwwjZ8ix/Nvhe9dZt5H99cgkot9bAw==} + pino@9.2.0: + resolution: {integrity: sha512-g3/hpwfujK5a4oVbaefoJxezLzsDgLcNJeITvC6yrfwYeT9la+edCK42j5QpEQSQCZgTKapXvnQIdgZwvRaZug==} hasBin: true pirates@4.0.5: @@ -9412,8 +10032,8 @@ packages: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} - prettier@3.2.5: - resolution: {integrity: sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==} + prettier@3.3.2: + resolution: {integrity: sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA==} engines: {node: '>=14'} hasBin: true @@ -9433,6 +10053,10 @@ packages: resolution: {integrity: sha512-66hKPCr+72mlfiSjlEB1+45IjXSqvVAIy6mocupoww4tBFE9R9IhwwUGoI4G++Tc9Aq+2rxOt0RFU6gPcrte0A==} engines: {node: '>= 0.8'} + pretty-ms@9.0.0: + resolution: {integrity: sha512-E9e9HJ9R9NasGOgPaPE8VMeiPKAyWR5jcFpNnwIejslIhWqdqOrb2wShBsncMPUb+BcCd2OPYfh7p2W6oemTng==} + engines: {node: '>=18'} + private-ip@2.3.3: resolution: {integrity: sha512-5zyFfekIVUOTVbL92hc8LJOtE/gyGHeREHkJ2yTyByP8Q2YZVoBqLg3EfYLeF0oVvGqtaEX2t2Qovja0/gStXw==} @@ -9518,12 +10142,15 @@ packages: pug-attrs@3.0.0: resolution: {integrity: sha512-azINV9dUtzPMFQktvTXciNAfAuVh/L/JCl0vtPCwvOA21uZrC08K/UnmrL+SXGEVc1FwzjW62+xw5S/uaLj6cA==} - pug-code-gen@3.0.2: - resolution: {integrity: sha512-nJMhW16MbiGRiyR4miDTQMRWDgKplnHyeLvioEJYbk1RsPI3FuA3saEP8uwnTb2nTJEKBU90NFVWJBk4OU5qyg==} + pug-code-gen@3.0.3: + resolution: {integrity: sha512-cYQg0JW0w32Ux+XTeZnBEeuWrAY7/HNE6TWnhiHGnnRYlCgyAUPoyh9KzCMa9WhcJlJ1AtQqpEYHc+vbCzA+Aw==} pug-error@2.0.0: resolution: {integrity: sha512-sjiUsi9M4RAGHktC1drQfCr5C5eriu24Lfbt4s+7SykztEOwVZtbFk1RRq0tzLxcMxMYTBR+zMQaG07J/btayQ==} + pug-error@2.1.0: + resolution: {integrity: sha512-lv7sU9e5Jk8IeUheHata6/UThZ7RK2jnaaNztxfPYUY+VxZyk/ePVaNZ/vwmH8WqGvDz3LrNYt/+gA55NDg6Pg==} + pug-filters@4.0.0: resolution: {integrity: sha512-yeNFtq5Yxmfz0f9z2rMXGw/8/4i1cCFecw/Q7+D0V2DdtII5UvqE12VaZ2AY7ri6o5RNXiweGH79OCq+2RQU4A==} @@ -9548,8 +10175,8 @@ packages: pug-walk@2.0.0: resolution: {integrity: sha512-yYELe9Q5q9IQhuvqsZNwA5hfPkMJ8u92bQLIMcsMxf/VADjNtEYptU+inlufAFYcWdHlwNfZOEnOOQrZrcyJCQ==} - pug@3.0.2: - resolution: {integrity: sha512-bp0I/hiK1D1vChHh6EfDxtndHji55XP/ZJKwsRqrz6lRia6ZC2OZbdAymlxdVFwd1L70ebrVJw4/eZ79skrIaw==} + pug@3.0.3: + resolution: {integrity: sha512-uBi6kmc9f3SZ3PXxqcHiUZLmIXgfgWooKWXcwSGwQd2Zi5Rb0bT14+8CJjJgI8AB+nndLaNgHGrcc6bPIB665g==} pump@2.0.1: resolution: {integrity: sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==} @@ -9632,10 +10259,6 @@ packages: ratelimiter@3.4.1: resolution: {integrity: sha512-5FJbRW/Jkkdk29ksedAfWFkQkhbUrMx3QJGwMKAypeIiQf4yrLW+gtPKZiaWt4zPrtw1uGufOjGO7UGM6VllsQ==} - raw-body@2.5.1: - resolution: {integrity: sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==} - engines: {node: '>= 0.8'} - raw-body@2.5.2: resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==} engines: {node: '>= 0.8'} @@ -9644,8 +10267,8 @@ packages: resolution: {integrity: sha512-fUeWjrkOO0t1rg7B2fdyDTvngj+9RlUyL92vOdiB7c0FPguWVsniIMjEtHH+meLBO9rzkUlUzBVXgWrjI8P9LA==} engines: {node: '>=12'} - re2@1.20.10: - resolution: {integrity: sha512-/5JjSPXobSDaKFL6rD5Gb4qD4CVBITQb7NAxfQ/NA7o0HER3SJAPV3lPO2kvzw0/PN1pVJNVATEUk4y9j7oIIA==} + re2@1.21.3: + resolution: {integrity: sha512-GI+KoGkHT4kxTaX+9p0FgNB1XUnCndO9slG5qqeEoZ7kbf6Dk6ohQVpmwKVeSp7LPLn+g6Q3BaCopz4oHuBDuQ==} react-colorful@5.6.1: resolution: {integrity: sha512-1exovf0uGTGyq5mXQT0zgQ80uvj2PCwvF8zY1RN9/vbJVSjSo3fsB/4L3ObbF7u70NduSiK4xu4Y6q1MHoUGEw==} @@ -9685,6 +10308,36 @@ packages: react-is@18.2.0: resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==} + react-remove-scroll-bar@2.3.6: + resolution: {integrity: sha512-DtSYaao4mBmX+HDo5YWYdBWQwYIQQshUV/dVxFxK+KM26Wjwp1gZ6rv6OC3oujI6Bfu6Xyg3TwK533AQutsn/g==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + + react-remove-scroll@2.5.7: + resolution: {integrity: sha512-FnrTWO4L7/Bhhf3CYBNArEG/yROV0tKmTv7/3h9QCFvH6sndeFf1wPqOcbFVu5VAulS5dV1wGT3GZZ/1GawqiA==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + + react-style-singleton@2.2.1: + resolution: {integrity: sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + react@18.3.1: resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} engines: {node: '>=0.10.0'} @@ -9726,10 +10379,6 @@ packages: resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==} engines: {node: '>= 12.13.0'} - recast@0.23.4: - resolution: {integrity: sha512-qtEDqIZGVcSZCHniWwZWbRy79Dc6Wp3kT/UmDA2RJKBPg7+7k51aQBZirHmUGn5uvHf2rg8DkjizrN26k61ATw==} - engines: {node: '>= 4'} - recast@0.23.6: resolution: {integrity: sha512-9FHoNjX1yjuesMwuthAmPKabxYQdOgihFYmT5ebXfYGBcnqXZf3WOVz+5foEZ8Y83P4ZY6yQD5GMmtV+pgCCAQ==} engines: {node: '>= 4'} @@ -9853,9 +10502,6 @@ packages: resolution: {integrity: sha512-6K/gDlqgQscOlg9fSRpWstA8sYe8rbELsSTNpx+3kTrsVCzvSl0zIvRErM7fdl9ERWDsKnrLnwB+Ne89918XOg==} engines: {node: '>=10'} - resolve@1.19.0: - resolution: {integrity: sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==} - resolve@1.22.8: resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} hasBin: true @@ -9883,11 +10529,15 @@ packages: resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + rfc4648@1.5.3: + resolution: {integrity: sha512-MjOWxM065+WswwnmNONOT+bD1nXzY9Km6u3kzvnx8F8/HXGZdz3T6e6vZJ8Q/RIMUSp/nxqjH3GwvJDy8ijeQQ==} + rfdc@1.3.0: resolution: {integrity: sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==} rimraf@2.6.3: resolution: {integrity: sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==} + deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true rimraf@2.7.1: @@ -9898,14 +10548,17 @@ packages: resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} hasBin: true - rollup@4.17.2: - resolution: {integrity: sha512-/9ClTJPByC0U4zNLowV1tMBe8yMEAxewtR3cUNX5BoEpGH3dQEWpJLr6CLp0fPdYRF/fzVOgvDb1zXuakwF5kQ==} + rollup@4.18.0: + resolution: {integrity: sha512-QmJz14PX3rzbJCN1SG4Xe/bAAX2a6NpCP8ab2vfu2GiUr8AQcr2nCV/oEO3yneFarB67zk8ShlIyWb2LGTb3Sg==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true rrweb-cssom@0.6.0: resolution: {integrity: sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==} + rrweb-cssom@0.7.1: + resolution: {integrity: sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg==} + rss-parser@3.13.0: resolution: {integrity: sha512-7jWUBV5yGN3rqMMj7CZufl/291QAhvrrGpDNE4k/02ZchL0npisiYYqULF71jCEKoIiHvK/Q2e6IkDwPziT7+w==} @@ -9941,8 +10594,8 @@ packages: sanitize-html@2.13.0: resolution: {integrity: sha512-Xff91Z+4Mz5QiNSLdLWwjgBDm5b1RU6xBT0+12rapjiaR7SwfRdjw8f+6Rir2MXKLrDicRFHdb51hGOAxmsUIA==} - sass@1.76.0: - resolution: {integrity: sha512-nc3LeqvF2FNW5xGF1zxZifdW3ffIz5aBb7I7tSvOoNu7z1RQ6pFt9MBuiPtjgaI62YWrM/txjWlOCFiGtf2xpw==} + sass@1.77.6: + resolution: {integrity: sha512-ByXE1oLD79GVq9Ht1PeHWCPMPB8XHpBuz1r85oByKHjZY6qV6rWnQovQzXJXuQ/XyE1Oj3iPk3lo28uzaRA2/Q==} engines: {node: '>=14.0.0'} hasBin: true @@ -10016,8 +10669,8 @@ packages: resolution: {integrity: sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==} engines: {node: '>=8'} - sharp@0.33.3: - resolution: {integrity: sha512-vHUeXJU1UvlO/BNwTpT0x/r53WkLUVxrmb5JTgW92fdFCFk0ispLMAeu/jPO2vjkXM1fYUi3K7/qcLF47pwM1A==} + sharp@0.33.4: + resolution: {integrity: sha512-7i/dt5kGl7qR4gwPRD2biwD2/SvBn3O04J77XKFgL2OnZtQw+AG9wnuS/csmu80nPRHLYE9E41fyEiG8nhH6/Q==} engines: {libvips: '>=8.15.2', node: ^18.17.0 || ^20.3.0 || >=21.0.0} shebang-command@1.2.0: @@ -10036,8 +10689,8 @@ packages: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} - shiki@1.4.0: - resolution: {integrity: sha512-5WIn0OL8PWm7JhnTwRWXniy6eEDY234mRrERVlFa646V2ErQqwIFd2UML7e0Pq9eqSKLoMa3Ke+xbsF+DAuy+Q==} + shiki@1.10.0: + resolution: {integrity: sha512-YD2sXQ+TMD/F9BimV9Jn0wj35pqOvywvOG/3PB6hGHyGKlM7TJ9tyJ02jOb2kF8F0HfJwKNYrh3sW7jEcuRlXA==} shimmer@1.2.1: resolution: {integrity: sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==} @@ -10055,8 +10708,8 @@ packages: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} - simple-oauth2@5.0.0: - resolution: {integrity: sha512-8291lo/z5ZdpmiOFzOs1kF3cxn22bMj5FFH+DNUppLJrpoIlM1QnFiE7KpshHu3J3i21TVcx4yW+gXYjdCKDLQ==} + simple-oauth2@5.0.1: + resolution: {integrity: sha512-JcmGdzvbHKU3GegF3BK6zNi46DqFTxPMjwYddu2bgYqZuy7Gtm8U8wdedkVE4lI4LEqXocmPBLAvC4BIiiBc5w==} simple-swizzle@0.2.2: resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==} @@ -10156,6 +10809,10 @@ packages: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} + slash@5.1.0: + resolution: {integrity: sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==} + engines: {node: '>=14.16'} + slice-ansi@3.0.0: resolution: {integrity: sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==} engines: {node: '>=8'} @@ -10176,8 +10833,8 @@ packages: resolution: {integrity: sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==} engines: {node: '>= 10.13.0', npm: '>= 3.0.0'} - sonic-boom@3.7.0: - resolution: {integrity: sha512-IudtNvSqA/ObjN97tfgNmOKyDOs4dNcg4cUUsHDebqsgb8wGBBwb31LIgShNO8fye0dFI52X1+tFoKKI6Rq1Gg==} + sonic-boom@4.0.1: + resolution: {integrity: sha512-hTSD/6JMLyT4r9zeof6UtuBDpjJ9sO08/nmS5djaA9eozT9oOlNdpXSnzcgj4FTqpk3nkLrs61l4gip9r1HCrQ==} sort-keys-length@1.0.1: resolution: {integrity: sha512-GRbEOUqCxemTAk/b32F2xa8wDTs+Z1QHOkbhJDQTvv/6G3ZkbJ+frYWsTcc7cBB3Fu4wy4XlLCuNtJuMn7Gsvw==} @@ -10237,8 +10894,8 @@ packages: sprintf-js@1.0.3: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} - sprintf-js@1.1.2: - resolution: {integrity: sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==} + sprintf-js@1.1.3: + resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==} sshpk@1.17.0: resolution: {integrity: sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==} @@ -10259,8 +10916,8 @@ packages: standard-as-callback@2.1.0: resolution: {integrity: sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==} - start-server-and-test@2.0.3: - resolution: {integrity: sha512-QsVObjfjFZKJE6CS6bSKNwWZCKBG6975/jKRPPGFfFh+yOQglSeGXiNWjzgQNXdphcBI9nXbyso9tPfX4YAUhg==} + start-server-and-test@2.0.4: + resolution: {integrity: sha512-CKNeBTcP0hVqIlNismHMudb9q3lLdAjcVPO13/7gfI66fcJpeIb/o4NzQd1JK/CD+lfWVqr10ZH9Y14+OwlJuw==} engines: {node: '>=16'} hasBin: true @@ -10297,8 +10954,8 @@ packages: react-dom: optional: true - storybook@8.0.9: - resolution: {integrity: sha512-/Mvij0Br5bUwJpCvqAUZMEDIWmdRxEyllvVj8Ukw5lIWJePxfpSsz4px5jg9+R6B9tO8sQSqjg4HJvQ/pZk8Tg==} + storybook@8.1.11: + resolution: {integrity: sha512-3KjIhF8lczXhKKHyHbOqV30dvuRYJSxc0d1as/C8kybuwE7cLaydhWGma7VBv5bTSPv0rDzucx7KcO+achArPg==} hasBin: true stream-browserify@3.0.0: @@ -10396,6 +11053,10 @@ packages: resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} engines: {node: '>=12'} + strip-final-newline@4.0.0: + resolution: {integrity: sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==} + engines: {node: '>=18'} + strip-indent@3.0.0: resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} engines: {node: '>=8'} @@ -10408,8 +11069,8 @@ packages: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} - strip-literal@1.3.0: - resolution: {integrity: sha512-PugKzOsyXpArk0yWmUwqOZecSO0GH0bPoctLcqNDH9J04pVW3lflYE0ujElBGTloevcxF5MofAOZ7C5l2b+wLg==} + strip-literal@2.1.0: + resolution: {integrity: sha512-Op+UycaUt/8FbN/Z2TWPBLge3jWrP3xj10f3fnYxf052bKuS3EKs1ZQcVGjnEMdsNVAM+plXRdmjrZ/KgG3Skw==} strip-outer@2.0.0: resolution: {integrity: sha512-A21Xsm1XzUkK0qK1ZrytDUvqsQWict2Cykhvi0fBQntGG5JSprESasEyV1EZ/4CiR5WB5KjzLTrP/bO37B0wPg==} @@ -10422,6 +11083,10 @@ packages: resolution: {integrity: sha512-pQ+V+nYQdC5H3Q7qBZAz/MO6lwGhoC2gOAjuouGf/VO0m7vQRh8QNMl2Uf6SwAtzZ9bOw3UIeBukEGNJl5dtXQ==} engines: {node: '>=14.16'} + structured-headers@1.0.1: + resolution: {integrity: sha512-QYBxdBtA4Tl5rFPuqmbmdrS9kbtren74RTJTcs0VSQNVV5iRhJD4QlYTLD0+81SBwUQctjEQzjTRI3WG4DzICA==} + engines: {node: '>= 14', npm: '>=6'} + stylehacks@6.1.1: resolution: {integrity: sha512-gSTTEQ670cJNoaeIp9KX6lZmm8LJ3jPB5yJmX8Zq/wQxOsAFXV3qjWzHas3YYk1qesuVIyYWWUpZ0vSE/dTSGg==} engines: {node: ^14 || ^16 || >=18.0} @@ -10460,8 +11125,8 @@ packages: symbol-tree@3.2.4: resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} - systeminformation@5.22.7: - resolution: {integrity: sha512-AWxlP05KeHbpGdgvZkcudJpsmChc2Y5Eo/GvxG/iUA/Aws5LZKHAMSeAo+V+nD+nxWZaxrwpWcnx4SH3oxNL3A==} + systeminformation@5.22.11: + resolution: {integrity: sha512-aLws5yi4KCHTb0BVvbodQY5bY8eW4asMRDTxTW46hqw9lGjACX6TlLdJrkdoHYRB0qs+MekqEq1zG7WDnWE8Ug==} engines: {node: '>=8.0.0'} os: [darwin, linux, win32, freebsd, openbsd, netbsd, sunos, android] hasBin: true @@ -10476,10 +11141,6 @@ packages: tar-stream@3.1.6: resolution: {integrity: sha512-B/UyjYwPpMBv+PaFSWAmtYjwdrlEaZQEhMIBFNC5oEG8lpiW8XjcSdmEaClj28ArfKScKHs2nshz3k2le6crsg==} - tar@4.4.19: - resolution: {integrity: sha512-a20gEsvHnWe0ygBY8JbxoM4w3SJdhc7ZAuxkLqh+nvNQN2IOt0B5lLgM490X5Hl8FF0dl0tOf2ewFYAlIFgzVA==} - engines: {node: '>=4.5'} - tar@6.2.1: resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==} engines: {node: '>=10'} @@ -10491,20 +11152,25 @@ packages: telejson@7.2.0: resolution: {integrity: sha512-1QTEcJkJEhc8OnStBx/ILRu5J2p0GjvWsBx56bmZRqnrkdBMUe+nX92jxV+p3dB4CP6PZCdJMQJwCggkNBMzkQ==} - temp-dir@2.0.0: - resolution: {integrity: sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==} - engines: {node: '>=8'} + temp-dir@3.0.0: + resolution: {integrity: sha512-nHc6S/bwIilKHNRgK/3jlhDoIHcp45YgyiwcAk46Tr0LfEqGBVpmiAyuiuxeVE44m3mXnEeVhaipLOEWmH+Njw==} + engines: {node: '>=14.16'} temp@0.8.4: resolution: {integrity: sha512-s0ZZzd0BzYv5tLSptZooSjK8oj6C+c19p7Vqta9+6NPOf7r+fxq0cJe6/oN4LTC79sy5NY8ucOJNgwsKCSbfqg==} engines: {node: '>=6.0.0'} - tempy@1.0.1: - resolution: {integrity: sha512-biM9brNqxSc04Ee71hzFbryD11nX7VPhQQY32AdDmjFvodsRFz/3ufeoTZ6uYkRFfGo188tENcASNs3vTdsM0w==} - engines: {node: '>=10'} + tempy@3.1.0: + resolution: {integrity: sha512-7jDLIdD2Zp0bDe5r3D2qtkd1QOCacylBuL7oa4udvN6v2pqr4+LcCr67C8DR1zkpaZ8XosF5m1yQSabKAW6f2g==} + engines: {node: '>=14.16'} - terser@5.30.3: - resolution: {integrity: sha512-STdUgOUx8rLbMGO9IOwHLpCqolkDITFFQSMYYwKE1N2lY6MVSaeoi10z/EhWxRc6ybqoVmKSkhKYH/XUpl7vSA==} + terser@5.31.1: + resolution: {integrity: sha512-37upzU1+viGvuFtBo9NPufCb9dwM0+l9hMxYyWfBA+fbwrPqNJAhbZ6W47bBFnZHKHTUBnMvi87434qq+qnxOg==} + engines: {node: '>=10'} + hasBin: true + + terser@5.31.2: + resolution: {integrity: sha512-LGyRZVFm/QElZHy/CPr/O4eNZOZIzsrQ92y4v9UJe/pFJjypje2yI3C2FmPtvUEnhadlSbmG2nXtdcjHOjCfxw==} engines: {node: '>=10'} hasBin: true @@ -10525,14 +11191,14 @@ packages: thenify@3.3.1: resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} - thread-stream@2.3.0: - resolution: {integrity: sha512-kaDqm1DET9pp3NXwR8382WHbnpXnRkN9xGN9dQt3B2+dmXiW8X1SOwmFOxAErEQ47ObhZ96J6yhZNXuyCOL7KA==} + thread-stream@3.1.0: + resolution: {integrity: sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A==} - three@0.164.1: - resolution: {integrity: sha512-iC/hUBbl1vzFny7f5GtqzVXYjMJKaTPxiCxXfrvVdBi1Sf+jhd1CAkitiFwC7mIBFCo3MrDLJG97yisoaWig0w==} + three@0.165.0: + resolution: {integrity: sha512-cc96IlVYGydeceu0e5xq70H8/yoVT/tXBxV/W8A/U6uOq7DXc4/s1Mkmnu6SqoYGhSRWWYFOhVwvq6V0VtbplA==} - throttle-debounce@5.0.0: - resolution: {integrity: sha512-2iQTSgkkc1Zyk0MeVrt/3BvuOXYPl/R8Z0U2xxo9rjwNciaHDG3R+Lm6dh4EeUci49DanvBnuqI6jshoQQRGEg==} + throttle-debounce@5.0.2: + resolution: {integrity: sha512-B71/4oyj61iNH0KeCamLuE2rmKuTO5byTOSVwECM5FA7TiAiAW+UqTKZ9ERueC4qvgSttUhdmq1mXC3kJqGX7A==} engines: {node: '>=12.22'} throttleit@1.0.0: @@ -10547,9 +11213,6 @@ packages: through@2.3.8: resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} - tiny-invariant@1.3.1: - resolution: {integrity: sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw==} - tiny-invariant@1.3.3: resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} @@ -10563,8 +11226,8 @@ packages: tinycolor2@1.6.0: resolution: {integrity: sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==} - tinypool@0.7.0: - resolution: {integrity: sha512-zSYNUlYSMhJ6Zdou4cJwo/p7w5nmAH17GRfU/ui3ctvjXFErXXkruT4MWW6poDeXgCaIBlGLrfU6TbTXxyGMww==} + tinypool@0.8.4: + resolution: {integrity: sha512-i11VH5gS6IFeLY3gMBQ00/MmLncVP7JLXOw1vlgkytLmJK7QnEr7NXf0LBdxfmNPAeyetukOk0bOYrJrFGjYJQ==} engines: {node: '>=14.0.0'} tinyspy@2.2.0: @@ -10589,10 +11252,6 @@ packages: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} - toad-cache@3.3.0: - resolution: {integrity: sha512-3oDzcogWGHZdkwrHyvJVpPjA7oNzY6ENOV3PsWJY9XYPZ6INo94Yd47s5may1U+nleBPwDhrRiTPMIvKaa3MQg==} - engines: {node: '>=12'} - toad-cache@3.7.0: resolution: {integrity: sha512-/m8M+2BJUpoJdgAHoG+baCwBT+tf2VraSfkBgl0Y00qIWt41DJ8R5B8nsEw0I58YwF5IZH6z24/2TobDKnqSWw==} engines: {node: '>=12'} @@ -10619,8 +11278,8 @@ packages: resolution: {integrity: sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==} engines: {node: '>=0.8'} - tough-cookie@4.1.3: - resolution: {integrity: sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==} + tough-cookie@4.1.4: + resolution: {integrity: sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==} engines: {node: '>=6'} tr46@0.0.3: @@ -10667,8 +11326,8 @@ packages: ts-map@1.0.3: resolution: {integrity: sha512-vDWbsl26LIcPGmDpoVzjEP6+hvHZkBkLW7JpvwbCv/5IYPJlsbzCVXY3wsCeAxAUeTclNOUZxnLdGh3VBD/J6w==} - tsc-alias@1.8.8: - resolution: {integrity: sha512-OYUOd2wl0H858NvABWr/BoSKNERw3N9GTi3rHPK8Iv4O1UyUXIrTTOAZNHsjlVpXFOhpJBVARI1s+rzwLivN3Q==} + tsc-alias@1.8.10: + resolution: {integrity: sha512-Ibv4KAWfFkFdKJxnWfVtdOmB0Zi1RJVxcbPGiCDsFpCQSsmpWyuzHG3rQyI5YkobWwxFPEyQfu1hdo4qLG2zPw==} hasBin: true tsconfig-paths@3.15.0: @@ -10678,8 +11337,8 @@ packages: resolution: {integrity: sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==} engines: {node: '>=6'} - tsd@0.30.7: - resolution: {integrity: sha512-oTiJ28D6B/KXoU3ww/Eji+xqHJojiuPVMwA12g4KYX1O72N93Nb6P3P3h2OAhhf92Xl8NIhb/xFmBZd5zw/xUw==} + tsd@0.31.1: + resolution: {integrity: sha512-sSL84A0SFwx2xGMWrxlGaarKFSQszWjJS2vgNDDLwatytzg2aq6ShlwHsBYxRNmjzXISODwMva5ZOdAg/4AoOA==} engines: {node: '>=14.16'} hasBin: true @@ -10689,6 +11348,9 @@ packages: tslib@2.6.2: resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} + tslib@2.6.3: + resolution: {integrity: sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==} + tsx@4.4.0: resolution: {integrity: sha512-4fwcEjRUxW20ciSaMB8zkpGwCPxuRGnadDuj/pBk5S9uT29zvWz15PK36GrKJo45mSJomDxVejZ73c6lr3811Q==} engines: {node: '>=18.0.0'} @@ -10708,10 +11370,6 @@ packages: resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} engines: {node: '>=4'} - type-fest@0.16.0: - resolution: {integrity: sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==} - engines: {node: '>=10'} - type-fest@0.18.1: resolution: {integrity: sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==} engines: {node: '>=10'} @@ -10732,10 +11390,18 @@ packages: resolution: {integrity: sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==} engines: {node: '>=8'} + type-fest@1.4.0: + resolution: {integrity: sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==} + engines: {node: '>=10'} + type-fest@2.19.0: resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==} engines: {node: '>=12.20'} + type-fest@4.20.1: + resolution: {integrity: sha512-R6wDsVsoS9xYOpy8vgeBlqpdOyzJ12HNfQhC/aAKWM3YoCV9TtunJzh/QpkMgeDhkoynDcw5f1y+qF9yc/HHyg==} + engines: {node: '>=16'} + type-fest@4.9.0: resolution: {integrity: sha512-KS/6lh/ynPGiHD/LnAobrEFq3Ad4pBzOlJ1wAnJx9N4EYoqFhMfLIBjUT2UEx4wg5ZE+cC1ob6DCSpppVo+rtg==} engines: {node: '>=16'} @@ -10830,8 +11496,8 @@ packages: engines: {node: '>=14.17'} hasBin: true - typescript@5.4.5: - resolution: {integrity: sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==} + typescript@5.5.3: + resolution: {integrity: sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==} engines: {node: '>=14.17'} hasBin: true @@ -10883,6 +11549,10 @@ packages: resolution: {integrity: sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==} engines: {node: '>=4'} + unicorn-magic@0.1.0: + resolution: {integrity: sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==} + engines: {node: '>=18'} + unified@11.0.4: resolution: {integrity: sha512-apMPnyLjAX+ty4OrNap7yumyVAMlKx5IWU2wlzzUdYJO9A8f1p9m/gywF/GM2ZDFcjQPrx59Mc90KwmxsoklxQ==} @@ -10897,9 +11567,9 @@ packages: resolution: {integrity: sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - unique-string@2.0.0: - resolution: {integrity: sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==} - engines: {node: '>=8'} + unique-string@3.0.0: + resolution: {integrity: sha512-VGXBUVwxKMBUznyffQweQABPRRW1vHZAbadFZud4pLFAqRGvv/96vafgjWFqzourzr8YonlQiPgH0YCJfawoGQ==} + engines: {node: '>=12'} unist-util-is@6.0.0: resolution: {integrity: sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==} @@ -10951,8 +11621,28 @@ packages: url-parse@1.5.10: resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==} - utf-8-validate@6.0.3: - resolution: {integrity: sha512-uIuGf9TWQ/y+0Lp+KGZCMuJWc3N9BHA+l/UmHd/oUHwJJDeysyTRxNQVkbzsIWfGFbRe3OcgML/i0mvVRPOyDA==} + use-callback-ref@1.3.2: + resolution: {integrity: sha512-elOQwe6Q8gqZgDA8mrh44qRTQqpIHDcZ3hXTLjBe1i4ph8XpNJnO+aQf3NaG+lriLopI4HMx9VjQLfPQ6vhnoA==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + + use-sidecar@1.1.2: + resolution: {integrity: sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': ^16.9.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + + utf-8-validate@6.0.4: + resolution: {integrity: sha512-xu9GQDeFp+eZ6LnCywXN/zBancWvOpUMzgjLPSjy4BRHSmTelvn2E0DG0o1sTiw5hkCKBHo8rwSKncfRfv2EEQ==} engines: {node: '>=6.14.2'} util-deprecate@1.0.2: @@ -10965,6 +11655,10 @@ packages: resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} engines: {node: '>= 0.4.0'} + uuid@10.0.0: + resolution: {integrity: sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==} + hasBin: true + uuid@3.4.0: resolution: {integrity: sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==} deprecated: Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details. @@ -10978,8 +11672,8 @@ packages: resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} hasBin: true - v-code-diff@1.11.0: - resolution: {integrity: sha512-lBlO+FXw3I3qFKbnlorXZ4sb5cFnrdxlc6lj3Y1CWrbn2LC7PoVbGlwH0W+nvAVX1rdJhhc15rKIQdHyMkXe/w==} + v-code-diff@1.12.0: + resolution: {integrity: sha512-vvdCBG02mIIiW6Gx6jF119hzxELt+6TlJIwchglR1JYzboHePNxIkVBjR/aoAOVlsGa+5Vtb77cd/N84nrXWPA==} peerDependencies: '@vue/composition-api': ^1.4.9 vue: ^2.6.0 || >=3.0.0 @@ -10994,10 +11688,6 @@ packages: validate-npm-package-license@3.0.4: resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} - validator@13.9.0: - resolution: {integrity: sha512-B+dGG8U3fdtM0/aNK4/X8CXq/EcxU2WPrPEkJGslb47qyHsxmbggTWK0yEA4qnYVNF+nxNlN88o14hIcPmSIEA==} - engines: {node: '>= 0.10'} - vary@1.1.2: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} @@ -11012,16 +11702,16 @@ packages: vfile@6.0.1: resolution: {integrity: sha512-1bYqc7pt6NIADBJ98UiG0Bn/CHIVOoZ/IyEkqIruLg0mE1BKzkOXY2D6CSqQIcKqgadppE5lrxgWXJmXd7zZJw==} - vite-node@0.34.6: - resolution: {integrity: sha512-nlBMJ9x6n7/Amaz6F3zJ97EBwR2FkzhBRxF5e+jE6LA3yi6Wtc2lyTij1OnDMIr34v5g/tVQtsVAzhT0jc5ygA==} - engines: {node: '>=v14.18.0'} + vite-node@1.6.0: + resolution: {integrity: sha512-de6HJgzC+TFzOu0NTC4RAIsyf/DY/ibWDYQUcuEA84EMHhcefTUGkjFHKKEJhQN4A+6I0u++kr3l36ZF2d7XRw==} + engines: {node: ^18.0.0 || >=20.0.0} hasBin: true vite-plugin-turbosnap@1.0.3: resolution: {integrity: sha512-p4D8CFVhZS412SyQX125qxyzOgIFouwOcvjZWk6bQbNPR1wtaEzFT6jZxAjf1dejlGqa6fqHcuCvQea6EWUkUA==} - vite@5.2.11: - resolution: {integrity: sha512-HndV31LWW05i1BLPMUCE1B9E9GFbOu1MbenhS58FuK6owSO5qHm7GiCotrNY1YE5rMeQSFBGmT5ZaLEjFizgiQ==} + vite@5.3.2: + resolution: {integrity: sha512-6lA7OBHBlXUxiJxbO5aAY2fsHHzDr1q7DvXYnyZycRs2Dz+dXBWuhpWHvmljTRTpQC2uvGmUFFkSHF2vGo90MA==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true peerDependencies: @@ -11054,22 +11744,22 @@ packages: peerDependencies: vitest: '>=0.16.0' - vitest@0.34.6: - resolution: {integrity: sha512-+5CALsOvbNKnS+ZHMXtuUC7nL8/7F1F2DnHGjSsszX8zCjWSSviphCb/NuS9Nzf4Q03KyyDRBAXhF/8lffME4Q==} - engines: {node: '>=v14.18.0'} + vitest@1.6.0: + resolution: {integrity: sha512-H5r/dN06swuFnzNFhq/dnz37bPXnq8xB2xB5JOVk8K09rUtoeNN+LHWkoQ0A/i3hvbUKKcCei9KpbxqHMLhLLA==} + 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': 1.6.0 + '@vitest/ui': 1.6.0 happy-dom: '*' jsdom: '*' - playwright: '*' - safaridriver: '*' - webdriverio: '*' peerDependenciesMeta: '@edge-runtime/vm': optional: true + '@types/node': + optional: true '@vitest/browser': optional: true '@vitest/ui': @@ -11078,12 +11768,6 @@ packages: optional: true jsdom: optional: true - playwright: - optional: true - safaridriver: - optional: true - webdriverio: - optional: true void-elements@3.1.0: resolution: {integrity: sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==} @@ -11110,6 +11794,9 @@ packages: resolution: {integrity: sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==} hasBin: true + vscode-uri@3.0.8: + resolution: {integrity: sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==} + vue-component-meta@2.0.16: resolution: {integrity: sha512-IyIMClUMYcKxAL34GqdPbR4V45MUeHXqQiZlHxeYMV5Qcqp4M+CEmtGpF//XBSS138heDkYkceHAtJQjLUB1Lw==} peerDependencies: @@ -11124,8 +11811,11 @@ packages: vue-component-type-helpers@2.0.16: resolution: {integrity: sha512-qisL/iAfdO++7w+SsfYQJVPj6QKvxp4i1MMxvsNO41z/8zu3KuAw9LkhKUfP/kcOWGDxESp+pQObWppXusejCA==} - vue-component-type-helpers@2.0.19: - resolution: {integrity: sha512-cN3f1aTxxKo4lzNeQAkVopswuImUrb5Iurll9Gaw5cqpnbTAxtEMM1mgi6ou4X79OCyqYv1U1mzBHJkzmiK82w==} + vue-component-type-helpers@2.0.24: + resolution: {integrity: sha512-Jr5N8QVYEcbQuMN1LRgvg61758G8HTnzUlQsAFOxx6Y6X8kmhJ7C+jOvWsQruYxi3uHhhS6BghyRlyiwO99DBg==} + + vue-component-type-helpers@2.0.26: + resolution: {integrity: sha512-sO9qQ8oC520SW6kqlls0iqDak53gsTVSrYylajgjmkt1c0vcgjsGSy1KzlDrbEx8pm02IEYhlUkU5hCYf8rwtg==} vue-demi@0.14.7: resolution: {integrity: sha512-EOG8KXDQNwkJILkx/gPcoL/7vH+hORoBaKgGe+6W7VFMvCYJfmF2dGbvgDroVnI8LU7/kTu8mbjRZGBU1z9NTA==} @@ -11143,8 +11833,8 @@ packages: peerDependencies: vue: '>=2' - vue-eslint-parser@9.4.2: - resolution: {integrity: sha512-Ry9oiGmCAK91HrKMtCrKFWmSFWvYkpGglCeFAIqDdr9zdXmMMpJOmUJS7WWsW7fX81h6mwHmUZCQQ1E0PkSwYQ==} + vue-eslint-parser@9.4.3: + resolution: {integrity: sha512-2rYRLWlIpaiN8xbPiDyXZXRgLGOtWxERV7ND5fFAv5qo1D2N9Fu9MNajBNc6o13lZ+24DAWCkQCvj4klgmcITg==} engines: {node: ^14.17.0 || >=16.0.0} peerDependencies: eslint: '>=6.0.0' @@ -11163,14 +11853,14 @@ packages: vue-template-compiler@2.7.14: resolution: {integrity: sha512-zyA5Y3ArvVG0NacJDkkzJuPQDF8RFeRlzV2vLeSnhSpieO6LK2OVbdLPi5MPPs09Ii+gMO8nY4S3iKQxBxDmWQ==} - vue-tsc@2.0.16: - resolution: {integrity: sha512-/gHAWJa216PeEhfxtAToIbxdWgw01wuQzo48ZUqMYVEyNqDp+OYV9xMO5HaPS2P3Ls0+EsjguMZLY4cGobX4Ew==} + vue-tsc@2.0.24: + resolution: {integrity: sha512-1qi4P8L7yS78A7OJ7CDDxUIZPD6nVxoQEgX3DkRZNi1HI1qOfzOJwQlNpmwkogSVD6S/XcanbW9sktzpSxz6rA==} hasBin: true peerDependencies: - typescript: '*' + typescript: '>=5.0.0' - vue@3.4.26: - resolution: {integrity: sha512-bUIq/p+VB+0xrJubaemrfhk1/FiW9iX+pDV+62I/XJ6EkspAO9/DXEjbDFoe8pIfOZBqfk45i9BMc41ptP/uRg==} + vue@3.4.31: + resolution: {integrity: sha512-njqRrOy7W3YLAlVqSKpBebtZpDVg21FPoaq1I7f/+qqBThK9ChAIjkRWgeP6Eat+8C+iia4P3OYqpATP21BCoQ==} peerDependencies: typescript: '*' peerDependenciesMeta: @@ -11210,6 +11900,10 @@ packages: resolution: {integrity: sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==} engines: {node: '>= 8'} + web-streams-polyfill@4.0.0: + resolution: {integrity: sha512-0zJXHRAYEjM2tUfZ2DiSOHAa2aw1tisnnhU3ufD57R8iefL+DcdJyRBRyJpG+NUimDgbTI/lH+gAE1PAvV3Cgw==} + engines: {node: '>= 8'} + webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} @@ -11286,6 +11980,10 @@ packages: resolution: {integrity: sha512-RNGKj82nUPg3g5ygxkQl0R937xLyho1J24ItRCBTr/m1YnZkzJy1hUiHUJrc/VlsDQzsCnInEGSg3bci0Lmd4w==} engines: {node: '>= 10.0.0'} + word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} + wordwrap@1.0.0: resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} @@ -11311,8 +12009,8 @@ packages: resolution: {integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} - ws@8.17.0: - resolution: {integrity: sha512-uJq6108EgZMAl20KagGkzCKfMEjxmKvZHG7Tlq0Z6nOky7YF7aq4mOx6xK8TJ/i1LeK4Qus7INktacctDgY8Ow==} + ws@8.17.1: + resolution: {integrity: sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==} engines: {node: '>=10.0.0'} peerDependencies: bufferutil: ^4.0.1 @@ -11404,10 +12102,9 @@ packages: resolution: {integrity: sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==} engines: {node: '>=12.20'} - z-schema@5.0.5: - resolution: {integrity: sha512-D7eujBWkLa3p2sIpJA0d1pr7es+a7m0vFAnZLlCEKq/Ij2k0MLi9Br2UPxoxdYystm5K1yeBGzub0FlYUEWj2Q==} - engines: {node: '>=8.0.0'} - hasBin: true + yoctocolors@2.0.2: + resolution: {integrity: sha512-Ct97huExsu7cWeEjmrXlofevF8CvzUglJ4iGUet5B8xn1oumtAZBpHU4GzYuoE6PVqcZ5hghtBrSlhwHuR1Jmw==} + engines: {node: '>=18'} zip-stream@6.0.1: resolution: {integrity: sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==} @@ -11443,458 +12140,510 @@ snapshots: dependencies: default-browser-id: 3.0.0 - '@aws-crypto/crc32@3.0.0': + '@aws-crypto/crc32@5.2.0': dependencies: - '@aws-crypto/util': 3.0.0 - '@aws-sdk/types': 3.413.0 - tslib: 1.14.1 + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.598.0 + tslib: 2.6.2 - '@aws-crypto/crc32c@3.0.0': + '@aws-crypto/crc32c@5.2.0': dependencies: - '@aws-crypto/util': 3.0.0 - '@aws-sdk/types': 3.413.0 - tslib: 1.14.1 + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.598.0 + tslib: 2.6.2 - '@aws-crypto/ie11-detection@3.0.0': + '@aws-crypto/sha1-browser@5.2.0': dependencies: - tslib: 1.14.1 - - '@aws-crypto/sha1-browser@3.0.0': - dependencies: - '@aws-crypto/ie11-detection': 3.0.0 - '@aws-crypto/supports-web-crypto': 3.0.0 - '@aws-crypto/util': 3.0.0 - '@aws-sdk/types': 3.413.0 + '@aws-crypto/supports-web-crypto': 5.2.0 + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.598.0 '@aws-sdk/util-locate-window': 3.208.0 - '@aws-sdk/util-utf8-browser': 3.259.0 - tslib: 1.14.1 - - '@aws-crypto/sha256-browser@3.0.0': - dependencies: - '@aws-crypto/ie11-detection': 3.0.0 - '@aws-crypto/sha256-js': 3.0.0 - '@aws-crypto/supports-web-crypto': 3.0.0 - '@aws-crypto/util': 3.0.0 - '@aws-sdk/types': 3.413.0 - '@aws-sdk/util-locate-window': 3.208.0 - '@aws-sdk/util-utf8-browser': 3.259.0 - tslib: 1.14.1 - - '@aws-crypto/sha256-js@3.0.0': - dependencies: - '@aws-crypto/util': 3.0.0 - '@aws-sdk/types': 3.413.0 - tslib: 1.14.1 - - '@aws-crypto/supports-web-crypto@3.0.0': - dependencies: - tslib: 1.14.1 - - '@aws-crypto/util@3.0.0': - dependencies: - '@aws-sdk/types': 3.413.0 - '@aws-sdk/util-utf8-browser': 3.259.0 - tslib: 1.14.1 - - '@aws-sdk/client-s3@3.412.0': - dependencies: - '@aws-crypto/sha1-browser': 3.0.0 - '@aws-crypto/sha256-browser': 3.0.0 - '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sts': 3.410.0 - '@aws-sdk/credential-provider-node': 3.410.0 - '@aws-sdk/middleware-bucket-endpoint': 3.410.0 - '@aws-sdk/middleware-expect-continue': 3.410.0 - '@aws-sdk/middleware-flexible-checksums': 3.410.0 - '@aws-sdk/middleware-host-header': 3.410.0 - '@aws-sdk/middleware-location-constraint': 3.410.0 - '@aws-sdk/middleware-logger': 3.410.0 - '@aws-sdk/middleware-recursion-detection': 3.410.0 - '@aws-sdk/middleware-sdk-s3': 3.410.0 - '@aws-sdk/middleware-signing': 3.410.0 - '@aws-sdk/middleware-ssec': 3.410.0 - '@aws-sdk/middleware-user-agent': 3.410.0 - '@aws-sdk/signature-v4-multi-region': 3.412.0 - '@aws-sdk/types': 3.410.0 - '@aws-sdk/util-endpoints': 3.410.0 - '@aws-sdk/util-user-agent-browser': 3.410.0 - '@aws-sdk/util-user-agent-node': 3.410.0 - '@aws-sdk/xml-builder': 3.310.0 - '@smithy/config-resolver': 2.0.9 - '@smithy/eventstream-serde-browser': 2.0.8 - '@smithy/eventstream-serde-config-resolver': 2.0.8 - '@smithy/eventstream-serde-node': 2.0.8 - '@smithy/fetch-http-handler': 2.1.4 - '@smithy/hash-blob-browser': 2.0.8 - '@smithy/hash-node': 2.0.8 - '@smithy/hash-stream-node': 2.0.8 - '@smithy/invalid-dependency': 2.0.8 - '@smithy/md5-js': 2.0.8 - '@smithy/middleware-content-length': 2.0.10 - '@smithy/middleware-endpoint': 2.0.8 - '@smithy/middleware-retry': 2.0.11 - '@smithy/middleware-serde': 2.0.8 - '@smithy/middleware-stack': 2.0.1 - '@smithy/node-config-provider': 2.0.11 - '@smithy/node-http-handler': 2.5.0 - '@smithy/protocol-http': 3.0.10 - '@smithy/smithy-client': 2.1.5 - '@smithy/types': 2.6.0 - '@smithy/url-parser': 2.0.8 - '@smithy/util-base64': 2.0.0 - '@smithy/util-body-length-browser': 2.0.0 - '@smithy/util-body-length-node': 2.1.0 - '@smithy/util-defaults-mode-browser': 2.0.9 - '@smithy/util-defaults-mode-node': 2.0.11 - '@smithy/util-retry': 2.0.1 - '@smithy/util-stream': 2.0.11 '@smithy/util-utf8': 2.0.0 - '@smithy/util-waiter': 2.0.8 + tslib: 2.6.2 + + '@aws-crypto/sha256-browser@5.2.0': + dependencies: + '@aws-crypto/sha256-js': 5.2.0 + '@aws-crypto/supports-web-crypto': 5.2.0 + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.598.0 + '@aws-sdk/util-locate-window': 3.208.0 + '@smithy/util-utf8': 2.0.0 + tslib: 2.6.2 + + '@aws-crypto/sha256-js@5.2.0': + dependencies: + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.598.0 + tslib: 2.6.2 + + '@aws-crypto/supports-web-crypto@5.2.0': + dependencies: + tslib: 2.6.2 + + '@aws-crypto/util@5.2.0': + dependencies: + '@aws-sdk/types': 3.598.0 + '@smithy/util-utf8': 2.0.0 + tslib: 2.6.2 + + '@aws-sdk/client-s3@3.600.0': + dependencies: + '@aws-crypto/sha1-browser': 5.2.0 + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/client-sso-oidc': 3.600.0(@aws-sdk/client-sts@3.600.0) + '@aws-sdk/client-sts': 3.600.0 + '@aws-sdk/core': 3.598.0 + '@aws-sdk/credential-provider-node': 3.600.0(@aws-sdk/client-sso-oidc@3.600.0)(@aws-sdk/client-sts@3.600.0) + '@aws-sdk/middleware-bucket-endpoint': 3.598.0 + '@aws-sdk/middleware-expect-continue': 3.598.0 + '@aws-sdk/middleware-flexible-checksums': 3.598.0 + '@aws-sdk/middleware-host-header': 3.598.0 + '@aws-sdk/middleware-location-constraint': 3.598.0 + '@aws-sdk/middleware-logger': 3.598.0 + '@aws-sdk/middleware-recursion-detection': 3.598.0 + '@aws-sdk/middleware-sdk-s3': 3.598.0 + '@aws-sdk/middleware-signing': 3.598.0 + '@aws-sdk/middleware-ssec': 3.598.0 + '@aws-sdk/middleware-user-agent': 3.598.0 + '@aws-sdk/region-config-resolver': 3.598.0 + '@aws-sdk/signature-v4-multi-region': 3.598.0 + '@aws-sdk/types': 3.598.0 + '@aws-sdk/util-endpoints': 3.598.0 + '@aws-sdk/util-user-agent-browser': 3.598.0 + '@aws-sdk/util-user-agent-node': 3.598.0 + '@aws-sdk/xml-builder': 3.598.0 + '@smithy/config-resolver': 3.0.4 + '@smithy/core': 2.2.4 + '@smithy/eventstream-serde-browser': 3.0.4 + '@smithy/eventstream-serde-config-resolver': 3.0.3 + '@smithy/eventstream-serde-node': 3.0.4 + '@smithy/fetch-http-handler': 3.2.0 + '@smithy/hash-blob-browser': 3.1.2 + '@smithy/hash-node': 3.0.3 + '@smithy/hash-stream-node': 3.1.2 + '@smithy/invalid-dependency': 3.0.3 + '@smithy/md5-js': 3.0.3 + '@smithy/middleware-content-length': 3.0.3 + '@smithy/middleware-endpoint': 3.0.4 + '@smithy/middleware-retry': 3.0.7 + '@smithy/middleware-serde': 3.0.3 + '@smithy/middleware-stack': 3.0.3 + '@smithy/node-config-provider': 3.1.3 + '@smithy/node-http-handler': 3.1.1 + '@smithy/protocol-http': 4.0.3 + '@smithy/smithy-client': 3.1.5 + '@smithy/types': 3.3.0 + '@smithy/url-parser': 3.0.3 + '@smithy/util-base64': 3.0.0 + '@smithy/util-body-length-browser': 3.0.0 + '@smithy/util-body-length-node': 3.0.0 + '@smithy/util-defaults-mode-browser': 3.0.7 + '@smithy/util-defaults-mode-node': 3.0.7 + '@smithy/util-endpoints': 2.0.4 + '@smithy/util-retry': 3.0.3 + '@smithy/util-stream': 3.0.5 + '@smithy/util-utf8': 3.0.0 + '@smithy/util-waiter': 3.1.2 + tslib: 2.6.2 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/client-sso-oidc@3.600.0(@aws-sdk/client-sts@3.600.0)': + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/client-sts': 3.600.0 + '@aws-sdk/core': 3.598.0 + '@aws-sdk/credential-provider-node': 3.600.0(@aws-sdk/client-sso-oidc@3.600.0)(@aws-sdk/client-sts@3.600.0) + '@aws-sdk/middleware-host-header': 3.598.0 + '@aws-sdk/middleware-logger': 3.598.0 + '@aws-sdk/middleware-recursion-detection': 3.598.0 + '@aws-sdk/middleware-user-agent': 3.598.0 + '@aws-sdk/region-config-resolver': 3.598.0 + '@aws-sdk/types': 3.598.0 + '@aws-sdk/util-endpoints': 3.598.0 + '@aws-sdk/util-user-agent-browser': 3.598.0 + '@aws-sdk/util-user-agent-node': 3.598.0 + '@smithy/config-resolver': 3.0.4 + '@smithy/core': 2.2.4 + '@smithy/fetch-http-handler': 3.2.0 + '@smithy/hash-node': 3.0.3 + '@smithy/invalid-dependency': 3.0.3 + '@smithy/middleware-content-length': 3.0.3 + '@smithy/middleware-endpoint': 3.0.4 + '@smithy/middleware-retry': 3.0.7 + '@smithy/middleware-serde': 3.0.3 + '@smithy/middleware-stack': 3.0.3 + '@smithy/node-config-provider': 3.1.3 + '@smithy/node-http-handler': 3.1.1 + '@smithy/protocol-http': 4.0.3 + '@smithy/smithy-client': 3.1.5 + '@smithy/types': 3.3.0 + '@smithy/url-parser': 3.0.3 + '@smithy/util-base64': 3.0.0 + '@smithy/util-body-length-browser': 3.0.0 + '@smithy/util-body-length-node': 3.0.0 + '@smithy/util-defaults-mode-browser': 3.0.7 + '@smithy/util-defaults-mode-node': 3.0.7 + '@smithy/util-endpoints': 2.0.4 + '@smithy/util-middleware': 3.0.3 + '@smithy/util-retry': 3.0.3 + '@smithy/util-utf8': 3.0.0 + tslib: 2.6.2 + transitivePeerDependencies: + - '@aws-sdk/client-sts' + - aws-crt + + '@aws-sdk/client-sso@3.598.0': + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/core': 3.598.0 + '@aws-sdk/middleware-host-header': 3.598.0 + '@aws-sdk/middleware-logger': 3.598.0 + '@aws-sdk/middleware-recursion-detection': 3.598.0 + '@aws-sdk/middleware-user-agent': 3.598.0 + '@aws-sdk/region-config-resolver': 3.598.0 + '@aws-sdk/types': 3.598.0 + '@aws-sdk/util-endpoints': 3.598.0 + '@aws-sdk/util-user-agent-browser': 3.598.0 + '@aws-sdk/util-user-agent-node': 3.598.0 + '@smithy/config-resolver': 3.0.4 + '@smithy/core': 2.2.4 + '@smithy/fetch-http-handler': 3.2.0 + '@smithy/hash-node': 3.0.3 + '@smithy/invalid-dependency': 3.0.3 + '@smithy/middleware-content-length': 3.0.3 + '@smithy/middleware-endpoint': 3.0.4 + '@smithy/middleware-retry': 3.0.7 + '@smithy/middleware-serde': 3.0.3 + '@smithy/middleware-stack': 3.0.3 + '@smithy/node-config-provider': 3.1.3 + '@smithy/node-http-handler': 3.1.1 + '@smithy/protocol-http': 4.0.3 + '@smithy/smithy-client': 3.1.5 + '@smithy/types': 3.3.0 + '@smithy/url-parser': 3.0.3 + '@smithy/util-base64': 3.0.0 + '@smithy/util-body-length-browser': 3.0.0 + '@smithy/util-body-length-node': 3.0.0 + '@smithy/util-defaults-mode-browser': 3.0.7 + '@smithy/util-defaults-mode-node': 3.0.7 + '@smithy/util-endpoints': 2.0.4 + '@smithy/util-middleware': 3.0.3 + '@smithy/util-retry': 3.0.3 + '@smithy/util-utf8': 3.0.0 + tslib: 2.6.2 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/client-sts@3.600.0': + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/client-sso-oidc': 3.600.0(@aws-sdk/client-sts@3.600.0) + '@aws-sdk/core': 3.598.0 + '@aws-sdk/credential-provider-node': 3.600.0(@aws-sdk/client-sso-oidc@3.600.0)(@aws-sdk/client-sts@3.600.0) + '@aws-sdk/middleware-host-header': 3.598.0 + '@aws-sdk/middleware-logger': 3.598.0 + '@aws-sdk/middleware-recursion-detection': 3.598.0 + '@aws-sdk/middleware-user-agent': 3.598.0 + '@aws-sdk/region-config-resolver': 3.598.0 + '@aws-sdk/types': 3.598.0 + '@aws-sdk/util-endpoints': 3.598.0 + '@aws-sdk/util-user-agent-browser': 3.598.0 + '@aws-sdk/util-user-agent-node': 3.598.0 + '@smithy/config-resolver': 3.0.4 + '@smithy/core': 2.2.4 + '@smithy/fetch-http-handler': 3.2.0 + '@smithy/hash-node': 3.0.3 + '@smithy/invalid-dependency': 3.0.3 + '@smithy/middleware-content-length': 3.0.3 + '@smithy/middleware-endpoint': 3.0.4 + '@smithy/middleware-retry': 3.0.7 + '@smithy/middleware-serde': 3.0.3 + '@smithy/middleware-stack': 3.0.3 + '@smithy/node-config-provider': 3.1.3 + '@smithy/node-http-handler': 3.1.1 + '@smithy/protocol-http': 4.0.3 + '@smithy/smithy-client': 3.1.5 + '@smithy/types': 3.3.0 + '@smithy/url-parser': 3.0.3 + '@smithy/util-base64': 3.0.0 + '@smithy/util-body-length-browser': 3.0.0 + '@smithy/util-body-length-node': 3.0.0 + '@smithy/util-defaults-mode-browser': 3.0.7 + '@smithy/util-defaults-mode-node': 3.0.7 + '@smithy/util-endpoints': 2.0.4 + '@smithy/util-middleware': 3.0.3 + '@smithy/util-retry': 3.0.3 + '@smithy/util-utf8': 3.0.0 + tslib: 2.6.2 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/core@3.598.0': + dependencies: + '@smithy/core': 2.2.4 + '@smithy/protocol-http': 4.0.3 + '@smithy/signature-v4': 3.1.2 + '@smithy/smithy-client': 3.1.5 + '@smithy/types': 3.3.0 fast-xml-parser: 4.2.5 tslib: 2.6.2 - transitivePeerDependencies: - - aws-crt - '@aws-sdk/client-sso@3.410.0': + '@aws-sdk/credential-provider-env@3.598.0': dependencies: - '@aws-crypto/sha256-browser': 3.0.0 - '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/middleware-host-header': 3.410.0 - '@aws-sdk/middleware-logger': 3.410.0 - '@aws-sdk/middleware-recursion-detection': 3.410.0 - '@aws-sdk/middleware-user-agent': 3.410.0 - '@aws-sdk/types': 3.410.0 - '@aws-sdk/util-endpoints': 3.410.0 - '@aws-sdk/util-user-agent-browser': 3.410.0 - '@aws-sdk/util-user-agent-node': 3.410.0 - '@smithy/config-resolver': 2.0.9 - '@smithy/fetch-http-handler': 2.1.4 - '@smithy/hash-node': 2.0.8 - '@smithy/invalid-dependency': 2.0.8 - '@smithy/middleware-content-length': 2.0.10 - '@smithy/middleware-endpoint': 2.0.8 - '@smithy/middleware-retry': 2.0.11 - '@smithy/middleware-serde': 2.0.8 - '@smithy/middleware-stack': 2.0.1 - '@smithy/node-config-provider': 2.0.11 - '@smithy/node-http-handler': 2.5.0 - '@smithy/protocol-http': 3.0.10 - '@smithy/smithy-client': 2.1.5 - '@smithy/types': 2.6.0 - '@smithy/url-parser': 2.0.8 - '@smithy/util-base64': 2.0.0 - '@smithy/util-body-length-browser': 2.0.0 - '@smithy/util-body-length-node': 2.1.0 - '@smithy/util-defaults-mode-browser': 2.0.9 - '@smithy/util-defaults-mode-node': 2.0.11 - '@smithy/util-retry': 2.0.1 - '@smithy/util-utf8': 2.0.0 + '@aws-sdk/types': 3.598.0 + '@smithy/property-provider': 3.1.3 + '@smithy/types': 3.3.0 + tslib: 2.6.2 + + '@aws-sdk/credential-provider-http@3.598.0': + dependencies: + '@aws-sdk/types': 3.598.0 + '@smithy/fetch-http-handler': 3.2.0 + '@smithy/node-http-handler': 3.1.1 + '@smithy/property-provider': 3.1.3 + '@smithy/protocol-http': 4.0.3 + '@smithy/smithy-client': 3.1.5 + '@smithy/types': 3.3.0 + '@smithy/util-stream': 3.0.5 + tslib: 2.6.2 + + '@aws-sdk/credential-provider-ini@3.598.0(@aws-sdk/client-sso-oidc@3.600.0)(@aws-sdk/client-sts@3.600.0)': + dependencies: + '@aws-sdk/client-sts': 3.600.0 + '@aws-sdk/credential-provider-env': 3.598.0 + '@aws-sdk/credential-provider-http': 3.598.0 + '@aws-sdk/credential-provider-process': 3.598.0 + '@aws-sdk/credential-provider-sso': 3.598.0(@aws-sdk/client-sso-oidc@3.600.0) + '@aws-sdk/credential-provider-web-identity': 3.598.0(@aws-sdk/client-sts@3.600.0) + '@aws-sdk/types': 3.598.0 + '@smithy/credential-provider-imds': 3.1.3 + '@smithy/property-provider': 3.1.3 + '@smithy/shared-ini-file-loader': 3.1.3 + '@smithy/types': 3.3.0 tslib: 2.6.2 transitivePeerDependencies: + - '@aws-sdk/client-sso-oidc' - aws-crt - '@aws-sdk/client-sts@3.410.0': + '@aws-sdk/credential-provider-node@3.600.0(@aws-sdk/client-sso-oidc@3.600.0)(@aws-sdk/client-sts@3.600.0)': dependencies: - '@aws-crypto/sha256-browser': 3.0.0 - '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/credential-provider-node': 3.410.0 - '@aws-sdk/middleware-host-header': 3.410.0 - '@aws-sdk/middleware-logger': 3.410.0 - '@aws-sdk/middleware-recursion-detection': 3.410.0 - '@aws-sdk/middleware-sdk-sts': 3.410.0 - '@aws-sdk/middleware-signing': 3.410.0 - '@aws-sdk/middleware-user-agent': 3.410.0 - '@aws-sdk/types': 3.410.0 - '@aws-sdk/util-endpoints': 3.410.0 - '@aws-sdk/util-user-agent-browser': 3.410.0 - '@aws-sdk/util-user-agent-node': 3.410.0 - '@smithy/config-resolver': 2.0.9 - '@smithy/fetch-http-handler': 2.1.4 - '@smithy/hash-node': 2.0.8 - '@smithy/invalid-dependency': 2.0.8 - '@smithy/middleware-content-length': 2.0.10 - '@smithy/middleware-endpoint': 2.0.8 - '@smithy/middleware-retry': 2.0.11 - '@smithy/middleware-serde': 2.0.8 - '@smithy/middleware-stack': 2.0.1 - '@smithy/node-config-provider': 2.0.11 - '@smithy/node-http-handler': 2.5.0 - '@smithy/protocol-http': 3.0.10 - '@smithy/smithy-client': 2.1.5 - '@smithy/types': 2.6.0 - '@smithy/url-parser': 2.0.8 - '@smithy/util-base64': 2.0.0 - '@smithy/util-body-length-browser': 2.0.0 - '@smithy/util-body-length-node': 2.1.0 - '@smithy/util-defaults-mode-browser': 2.0.9 - '@smithy/util-defaults-mode-node': 2.0.11 - '@smithy/util-retry': 2.0.1 - '@smithy/util-utf8': 2.0.0 - fast-xml-parser: 4.2.5 + '@aws-sdk/credential-provider-env': 3.598.0 + '@aws-sdk/credential-provider-http': 3.598.0 + '@aws-sdk/credential-provider-ini': 3.598.0(@aws-sdk/client-sso-oidc@3.600.0)(@aws-sdk/client-sts@3.600.0) + '@aws-sdk/credential-provider-process': 3.598.0 + '@aws-sdk/credential-provider-sso': 3.598.0(@aws-sdk/client-sso-oidc@3.600.0) + '@aws-sdk/credential-provider-web-identity': 3.598.0(@aws-sdk/client-sts@3.600.0) + '@aws-sdk/types': 3.598.0 + '@smithy/credential-provider-imds': 3.1.3 + '@smithy/property-provider': 3.1.3 + '@smithy/shared-ini-file-loader': 3.1.3 + '@smithy/types': 3.3.0 tslib: 2.6.2 transitivePeerDependencies: + - '@aws-sdk/client-sso-oidc' + - '@aws-sdk/client-sts' - aws-crt - '@aws-sdk/credential-provider-env@3.410.0': + '@aws-sdk/credential-provider-process@3.598.0': dependencies: - '@aws-sdk/types': 3.410.0 - '@smithy/property-provider': 2.0.9 - '@smithy/types': 2.6.0 + '@aws-sdk/types': 3.598.0 + '@smithy/property-provider': 3.1.3 + '@smithy/shared-ini-file-loader': 3.1.3 + '@smithy/types': 3.3.0 tslib: 2.6.2 - '@aws-sdk/credential-provider-ini@3.410.0': + '@aws-sdk/credential-provider-sso@3.598.0(@aws-sdk/client-sso-oidc@3.600.0)': dependencies: - '@aws-sdk/credential-provider-env': 3.410.0 - '@aws-sdk/credential-provider-process': 3.410.0 - '@aws-sdk/credential-provider-sso': 3.410.0 - '@aws-sdk/credential-provider-web-identity': 3.410.0 - '@aws-sdk/types': 3.410.0 - '@smithy/credential-provider-imds': 2.0.11 - '@smithy/property-provider': 2.0.9 - '@smithy/shared-ini-file-loader': 2.0.10 - '@smithy/types': 2.6.0 + '@aws-sdk/client-sso': 3.598.0 + '@aws-sdk/token-providers': 3.598.0(@aws-sdk/client-sso-oidc@3.600.0) + '@aws-sdk/types': 3.598.0 + '@smithy/property-provider': 3.1.3 + '@smithy/shared-ini-file-loader': 3.1.3 + '@smithy/types': 3.3.0 tslib: 2.6.2 transitivePeerDependencies: + - '@aws-sdk/client-sso-oidc' - aws-crt - '@aws-sdk/credential-provider-node@3.410.0': + '@aws-sdk/credential-provider-web-identity@3.598.0(@aws-sdk/client-sts@3.600.0)': dependencies: - '@aws-sdk/credential-provider-env': 3.410.0 - '@aws-sdk/credential-provider-ini': 3.410.0 - '@aws-sdk/credential-provider-process': 3.410.0 - '@aws-sdk/credential-provider-sso': 3.410.0 - '@aws-sdk/credential-provider-web-identity': 3.410.0 - '@aws-sdk/types': 3.410.0 - '@smithy/credential-provider-imds': 2.0.11 - '@smithy/property-provider': 2.0.9 - '@smithy/shared-ini-file-loader': 2.0.10 - '@smithy/types': 2.6.0 - tslib: 2.6.2 - transitivePeerDependencies: - - aws-crt - - '@aws-sdk/credential-provider-process@3.410.0': - dependencies: - '@aws-sdk/types': 3.410.0 - '@smithy/property-provider': 2.0.9 - '@smithy/shared-ini-file-loader': 2.0.10 - '@smithy/types': 2.6.0 + '@aws-sdk/client-sts': 3.600.0 + '@aws-sdk/types': 3.598.0 + '@smithy/property-provider': 3.1.3 + '@smithy/types': 3.3.0 tslib: 2.6.2 - '@aws-sdk/credential-provider-sso@3.410.0': + '@aws-sdk/lib-storage@3.600.0(@aws-sdk/client-s3@3.600.0)': dependencies: - '@aws-sdk/client-sso': 3.410.0 - '@aws-sdk/token-providers': 3.410.0 - '@aws-sdk/types': 3.410.0 - '@smithy/property-provider': 2.0.9 - '@smithy/shared-ini-file-loader': 2.0.10 - '@smithy/types': 2.6.0 - tslib: 2.6.2 - transitivePeerDependencies: - - aws-crt - - '@aws-sdk/credential-provider-web-identity@3.410.0': - dependencies: - '@aws-sdk/types': 3.410.0 - '@smithy/property-provider': 2.0.9 - '@smithy/types': 2.6.0 - tslib: 2.6.2 - - '@aws-sdk/lib-storage@3.412.0(@aws-sdk/client-s3@3.412.0)': - dependencies: - '@aws-sdk/client-s3': 3.412.0 - '@smithy/abort-controller': 2.0.14 - '@smithy/middleware-endpoint': 2.0.8 - '@smithy/smithy-client': 2.1.5 + '@aws-sdk/client-s3': 3.600.0 + '@smithy/abort-controller': 3.1.1 + '@smithy/middleware-endpoint': 3.0.4 + '@smithy/smithy-client': 3.1.5 buffer: 5.6.0 events: 3.3.0 stream-browserify: 3.0.0 tslib: 2.6.2 - '@aws-sdk/middleware-bucket-endpoint@3.410.0': + '@aws-sdk/middleware-bucket-endpoint@3.598.0': dependencies: - '@aws-sdk/types': 3.410.0 - '@aws-sdk/util-arn-parser': 3.310.0 - '@smithy/node-config-provider': 2.0.11 - '@smithy/protocol-http': 3.0.10 - '@smithy/types': 2.6.0 - '@smithy/util-config-provider': 2.0.0 + '@aws-sdk/types': 3.598.0 + '@aws-sdk/util-arn-parser': 3.568.0 + '@smithy/node-config-provider': 3.1.3 + '@smithy/protocol-http': 4.0.3 + '@smithy/types': 3.3.0 + '@smithy/util-config-provider': 3.0.0 tslib: 2.6.2 - '@aws-sdk/middleware-expect-continue@3.410.0': + '@aws-sdk/middleware-expect-continue@3.598.0': dependencies: - '@aws-sdk/types': 3.410.0 - '@smithy/protocol-http': 3.0.10 - '@smithy/types': 2.6.0 + '@aws-sdk/types': 3.598.0 + '@smithy/protocol-http': 4.0.3 + '@smithy/types': 3.3.0 tslib: 2.6.2 - '@aws-sdk/middleware-flexible-checksums@3.410.0': + '@aws-sdk/middleware-flexible-checksums@3.598.0': dependencies: - '@aws-crypto/crc32': 3.0.0 - '@aws-crypto/crc32c': 3.0.0 - '@aws-sdk/types': 3.410.0 - '@smithy/is-array-buffer': 2.0.0 - '@smithy/protocol-http': 3.0.10 - '@smithy/types': 2.6.0 - '@smithy/util-utf8': 2.0.0 + '@aws-crypto/crc32': 5.2.0 + '@aws-crypto/crc32c': 5.2.0 + '@aws-sdk/types': 3.598.0 + '@smithy/is-array-buffer': 3.0.0 + '@smithy/protocol-http': 4.0.3 + '@smithy/types': 3.3.0 + '@smithy/util-utf8': 3.0.0 tslib: 2.6.2 - '@aws-sdk/middleware-host-header@3.410.0': + '@aws-sdk/middleware-host-header@3.598.0': dependencies: - '@aws-sdk/types': 3.410.0 - '@smithy/protocol-http': 3.0.10 - '@smithy/types': 2.6.0 + '@aws-sdk/types': 3.598.0 + '@smithy/protocol-http': 4.0.3 + '@smithy/types': 3.3.0 tslib: 2.6.2 - '@aws-sdk/middleware-location-constraint@3.410.0': + '@aws-sdk/middleware-location-constraint@3.598.0': dependencies: - '@aws-sdk/types': 3.410.0 - '@smithy/types': 2.6.0 + '@aws-sdk/types': 3.598.0 + '@smithy/types': 3.3.0 tslib: 2.6.2 - '@aws-sdk/middleware-logger@3.410.0': + '@aws-sdk/middleware-logger@3.598.0': dependencies: - '@aws-sdk/types': 3.410.0 - '@smithy/types': 2.6.0 + '@aws-sdk/types': 3.598.0 + '@smithy/types': 3.3.0 tslib: 2.6.2 - '@aws-sdk/middleware-recursion-detection@3.410.0': + '@aws-sdk/middleware-recursion-detection@3.598.0': dependencies: - '@aws-sdk/types': 3.410.0 - '@smithy/protocol-http': 3.0.10 - '@smithy/types': 2.6.0 + '@aws-sdk/types': 3.598.0 + '@smithy/protocol-http': 4.0.3 + '@smithy/types': 3.3.0 tslib: 2.6.2 - '@aws-sdk/middleware-sdk-s3@3.410.0': + '@aws-sdk/middleware-sdk-s3@3.598.0': dependencies: - '@aws-sdk/types': 3.410.0 - '@aws-sdk/util-arn-parser': 3.310.0 - '@smithy/protocol-http': 3.0.10 - '@smithy/types': 2.6.0 + '@aws-sdk/types': 3.598.0 + '@aws-sdk/util-arn-parser': 3.568.0 + '@smithy/node-config-provider': 3.1.3 + '@smithy/protocol-http': 4.0.3 + '@smithy/signature-v4': 3.1.2 + '@smithy/smithy-client': 3.1.5 + '@smithy/types': 3.3.0 + '@smithy/util-config-provider': 3.0.0 tslib: 2.6.2 - '@aws-sdk/middleware-sdk-sts@3.410.0': + '@aws-sdk/middleware-signing@3.598.0': dependencies: - '@aws-sdk/middleware-signing': 3.410.0 - '@aws-sdk/types': 3.410.0 - '@smithy/types': 2.6.0 + '@aws-sdk/types': 3.598.0 + '@smithy/property-provider': 3.1.3 + '@smithy/protocol-http': 4.0.3 + '@smithy/signature-v4': 3.1.2 + '@smithy/types': 3.3.0 + '@smithy/util-middleware': 3.0.3 tslib: 2.6.2 - '@aws-sdk/middleware-signing@3.410.0': + '@aws-sdk/middleware-ssec@3.598.0': dependencies: - '@aws-sdk/types': 3.410.0 - '@smithy/property-provider': 2.0.9 - '@smithy/protocol-http': 3.0.10 - '@smithy/signature-v4': 2.0.5 - '@smithy/types': 2.6.0 - '@smithy/util-middleware': 2.0.1 + '@aws-sdk/types': 3.598.0 + '@smithy/types': 3.3.0 tslib: 2.6.2 - '@aws-sdk/middleware-ssec@3.410.0': + '@aws-sdk/middleware-user-agent@3.598.0': dependencies: - '@aws-sdk/types': 3.410.0 - '@smithy/types': 2.6.0 + '@aws-sdk/types': 3.598.0 + '@aws-sdk/util-endpoints': 3.598.0 + '@smithy/protocol-http': 4.0.3 + '@smithy/types': 3.3.0 tslib: 2.6.2 - '@aws-sdk/middleware-user-agent@3.410.0': + '@aws-sdk/region-config-resolver@3.598.0': dependencies: - '@aws-sdk/types': 3.410.0 - '@aws-sdk/util-endpoints': 3.410.0 - '@smithy/protocol-http': 3.0.10 - '@smithy/types': 2.6.0 + '@aws-sdk/types': 3.598.0 + '@smithy/node-config-provider': 3.1.3 + '@smithy/types': 3.3.0 + '@smithy/util-config-provider': 3.0.0 + '@smithy/util-middleware': 3.0.3 tslib: 2.6.2 - '@aws-sdk/signature-v4-multi-region@3.412.0': + '@aws-sdk/signature-v4-multi-region@3.598.0': dependencies: - '@aws-sdk/types': 3.410.0 - '@smithy/protocol-http': 3.0.10 - '@smithy/signature-v4': 2.0.5 - '@smithy/types': 2.6.0 + '@aws-sdk/middleware-sdk-s3': 3.598.0 + '@aws-sdk/types': 3.598.0 + '@smithy/protocol-http': 4.0.3 + '@smithy/signature-v4': 3.1.2 + '@smithy/types': 3.3.0 tslib: 2.6.2 - '@aws-sdk/token-providers@3.410.0': + '@aws-sdk/token-providers@3.598.0(@aws-sdk/client-sso-oidc@3.600.0)': dependencies: - '@aws-crypto/sha256-browser': 3.0.0 - '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/middleware-host-header': 3.410.0 - '@aws-sdk/middleware-logger': 3.410.0 - '@aws-sdk/middleware-recursion-detection': 3.410.0 - '@aws-sdk/middleware-user-agent': 3.410.0 - '@aws-sdk/types': 3.410.0 - '@aws-sdk/util-endpoints': 3.410.0 - '@aws-sdk/util-user-agent-browser': 3.410.0 - '@aws-sdk/util-user-agent-node': 3.410.0 - '@smithy/config-resolver': 2.0.9 - '@smithy/fetch-http-handler': 2.1.4 - '@smithy/hash-node': 2.0.8 - '@smithy/invalid-dependency': 2.0.8 - '@smithy/middleware-content-length': 2.0.10 - '@smithy/middleware-endpoint': 2.0.8 - '@smithy/middleware-retry': 2.0.11 - '@smithy/middleware-serde': 2.0.8 - '@smithy/middleware-stack': 2.0.1 - '@smithy/node-config-provider': 2.0.11 - '@smithy/node-http-handler': 2.5.0 - '@smithy/property-provider': 2.0.9 - '@smithy/protocol-http': 3.0.10 - '@smithy/shared-ini-file-loader': 2.0.10 - '@smithy/smithy-client': 2.1.5 - '@smithy/types': 2.6.0 - '@smithy/url-parser': 2.0.8 - '@smithy/util-base64': 2.0.0 - '@smithy/util-body-length-browser': 2.0.0 - '@smithy/util-body-length-node': 2.1.0 - '@smithy/util-defaults-mode-browser': 2.0.9 - '@smithy/util-defaults-mode-node': 2.0.11 - '@smithy/util-retry': 2.0.1 - '@smithy/util-utf8': 2.0.0 - tslib: 2.6.2 - transitivePeerDependencies: - - aws-crt - - '@aws-sdk/types@3.410.0': - dependencies: - '@smithy/types': 2.6.0 + '@aws-sdk/client-sso-oidc': 3.600.0(@aws-sdk/client-sts@3.600.0) + '@aws-sdk/types': 3.598.0 + '@smithy/property-provider': 3.1.3 + '@smithy/shared-ini-file-loader': 3.1.3 + '@smithy/types': 3.3.0 tslib: 2.6.2 - '@aws-sdk/types@3.413.0': + '@aws-sdk/types@3.598.0': dependencies: - '@smithy/types': 2.6.0 + '@smithy/types': 3.3.0 tslib: 2.6.2 - '@aws-sdk/util-arn-parser@3.310.0': + '@aws-sdk/util-arn-parser@3.568.0': dependencies: tslib: 2.6.2 - '@aws-sdk/util-endpoints@3.410.0': + '@aws-sdk/util-endpoints@3.598.0': dependencies: - '@aws-sdk/types': 3.410.0 + '@aws-sdk/types': 3.598.0 + '@smithy/types': 3.3.0 + '@smithy/util-endpoints': 2.0.4 tslib: 2.6.2 '@aws-sdk/util-locate-window@3.208.0': dependencies: tslib: 2.6.2 - '@aws-sdk/util-user-agent-browser@3.410.0': + '@aws-sdk/util-user-agent-browser@3.598.0': dependencies: - '@aws-sdk/types': 3.410.0 - '@smithy/types': 2.6.0 + '@aws-sdk/types': 3.598.0 + '@smithy/types': 3.3.0 bowser: 2.11.0 tslib: 2.6.2 - '@aws-sdk/util-user-agent-node@3.410.0': + '@aws-sdk/util-user-agent-node@3.598.0': dependencies: - '@aws-sdk/types': 3.410.0 - '@smithy/node-config-provider': 2.0.11 - '@smithy/types': 2.6.0 + '@aws-sdk/types': 3.598.0 + '@smithy/node-config-provider': 3.1.3 + '@smithy/types': 3.3.0 tslib: 2.6.2 - '@aws-sdk/util-utf8-browser@3.259.0': - dependencies: - tslib: 2.6.2 - - '@aws-sdk/xml-builder@3.310.0': + '@aws-sdk/xml-builder@3.598.0': dependencies: + '@smithy/types': 3.3.0 tslib: 2.6.2 '@babel/code-frame@7.23.5': @@ -11902,8 +12651,15 @@ snapshots: '@babel/highlight': 7.23.4 chalk: 2.4.2 + '@babel/code-frame@7.24.7': + dependencies: + '@babel/highlight': 7.24.7 + picocolors: 1.0.0 + '@babel/compat-data@7.23.5': {} + '@babel/compat-data@7.24.7': {} + '@babel/core@7.23.5': dependencies: '@ampproject/remapping': 2.2.1 @@ -11917,27 +12673,27 @@ snapshots: '@babel/traverse': 7.23.5 '@babel/types': 7.23.5 convert-source-map: 2.0.0 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.5(supports-color@8.1.1) gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 transitivePeerDependencies: - supports-color - '@babel/core@7.24.0': + '@babel/core@7.24.7': dependencies: '@ampproject/remapping': 2.2.1 - '@babel/code-frame': 7.23.5 - '@babel/generator': 7.23.6 - '@babel/helper-compilation-targets': 7.23.6 - '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.0) - '@babel/helpers': 7.24.0 - '@babel/parser': 7.24.0 - '@babel/template': 7.24.0 - '@babel/traverse': 7.24.0 - '@babel/types': 7.24.0 + '@babel/code-frame': 7.24.7 + '@babel/generator': 7.24.7 + '@babel/helper-compilation-targets': 7.24.7 + '@babel/helper-module-transforms': 7.24.7(@babel/core@7.24.7) + '@babel/helpers': 7.24.7 + '@babel/parser': 7.24.7 + '@babel/template': 7.24.7 + '@babel/traverse': 7.24.7 + '@babel/types': 7.24.7 convert-source-map: 2.0.0 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.5(supports-color@8.1.1) gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -11951,20 +12707,23 @@ snapshots: '@jridgewell/trace-mapping': 0.3.18 jsesc: 2.5.2 - '@babel/generator@7.23.6': + '@babel/generator@7.24.7': dependencies: - '@babel/types': 7.24.0 - '@jridgewell/gen-mapping': 0.3.2 - '@jridgewell/trace-mapping': 0.3.18 + '@babel/types': 7.24.7 + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 jsesc: 2.5.2 - '@babel/helper-annotate-as-pure@7.22.5': + '@babel/helper-annotate-as-pure@7.24.7': dependencies: - '@babel/types': 7.24.0 + '@babel/types': 7.24.7 - '@babel/helper-builder-binary-assignment-operator-visitor@7.22.15': + '@babel/helper-builder-binary-assignment-operator-visitor@7.24.7': dependencies: - '@babel/types': 7.24.0 + '@babel/traverse': 7.24.7 + '@babel/types': 7.24.7 + transitivePeerDependencies: + - supports-color '@babel/helper-compilation-targets@7.22.15': dependencies: @@ -11974,40 +12733,42 @@ snapshots: lru-cache: 5.1.1 semver: 6.3.1 - '@babel/helper-compilation-targets@7.23.6': + '@babel/helper-compilation-targets@7.24.7': dependencies: - '@babel/compat-data': 7.23.5 - '@babel/helper-validator-option': 7.23.5 + '@babel/compat-data': 7.24.7 + '@babel/helper-validator-option': 7.24.7 browserslist: 4.23.0 lru-cache: 5.1.1 semver: 6.3.1 - '@babel/helper-create-class-features-plugin@7.23.5(@babel/core@7.24.0)': + '@babel/helper-create-class-features-plugin@7.24.7(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 - '@babel/helper-annotate-as-pure': 7.22.5 - '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-function-name': 7.23.0 - '@babel/helper-member-expression-to-functions': 7.23.0 - '@babel/helper-optimise-call-expression': 7.22.5 - '@babel/helper-replace-supers': 7.22.20(@babel/core@7.24.0) - '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 - '@babel/helper-split-export-declaration': 7.22.6 + '@babel/core': 7.24.7 + '@babel/helper-annotate-as-pure': 7.24.7 + '@babel/helper-environment-visitor': 7.24.7 + '@babel/helper-function-name': 7.24.7 + '@babel/helper-member-expression-to-functions': 7.24.7 + '@babel/helper-optimise-call-expression': 7.24.7 + '@babel/helper-replace-supers': 7.24.7(@babel/core@7.24.7) + '@babel/helper-skip-transparent-expression-wrappers': 7.24.7 + '@babel/helper-split-export-declaration': 7.24.7 semver: 6.3.1 + transitivePeerDependencies: + - supports-color - '@babel/helper-create-regexp-features-plugin@7.22.15(@babel/core@7.24.0)': + '@babel/helper-create-regexp-features-plugin@7.24.7(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 - '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/core': 7.24.7 + '@babel/helper-annotate-as-pure': 7.24.7 regexpu-core: 5.3.2 semver: 6.3.1 - '@babel/helper-define-polyfill-provider@0.4.3(@babel/core@7.24.0)': + '@babel/helper-define-polyfill-provider@0.6.2(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 - '@babel/helper-compilation-targets': 7.23.6 - '@babel/helper-plugin-utils': 7.22.5 - debug: 4.3.4(supports-color@8.1.1) + '@babel/core': 7.24.7 + '@babel/helper-compilation-targets': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 + debug: 4.3.5(supports-color@8.1.1) lodash.debounce: 4.0.8 resolve: 1.22.8 transitivePeerDependencies: @@ -12015,23 +12776,46 @@ snapshots: '@babel/helper-environment-visitor@7.22.20': {} + '@babel/helper-environment-visitor@7.24.7': + dependencies: + '@babel/types': 7.24.7 + '@babel/helper-function-name@7.23.0': dependencies: - '@babel/template': 7.24.0 - '@babel/types': 7.24.0 + '@babel/template': 7.24.7 + '@babel/types': 7.24.7 + + '@babel/helper-function-name@7.24.7': + dependencies: + '@babel/template': 7.24.7 + '@babel/types': 7.24.7 '@babel/helper-hoist-variables@7.22.5': dependencies: - '@babel/types': 7.24.0 + '@babel/types': 7.24.7 - '@babel/helper-member-expression-to-functions@7.23.0': + '@babel/helper-hoist-variables@7.24.7': dependencies: - '@babel/types': 7.24.0 + '@babel/types': 7.24.7 + + '@babel/helper-member-expression-to-functions@7.24.7': + dependencies: + '@babel/traverse': 7.24.7 + '@babel/types': 7.24.7 + transitivePeerDependencies: + - supports-color '@babel/helper-module-imports@7.22.15': dependencies: '@babel/types': 7.23.5 + '@babel/helper-module-imports@7.24.7': + dependencies: + '@babel/traverse': 7.24.7 + '@babel/types': 7.24.7 + transitivePeerDependencies: + - supports-color + '@babel/helper-module-transforms@7.23.3(@babel/core@7.23.5)': dependencies: '@babel/core': 7.23.5 @@ -12041,58 +12825,89 @@ snapshots: '@babel/helper-split-export-declaration': 7.22.6 '@babel/helper-validator-identifier': 7.22.20 - '@babel/helper-module-transforms@7.23.3(@babel/core@7.24.0)': + '@babel/helper-module-transforms@7.24.7(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 - '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-module-imports': 7.22.15 - '@babel/helper-simple-access': 7.22.5 - '@babel/helper-split-export-declaration': 7.22.6 - '@babel/helper-validator-identifier': 7.22.20 + '@babel/core': 7.24.7 + '@babel/helper-environment-visitor': 7.24.7 + '@babel/helper-module-imports': 7.24.7 + '@babel/helper-simple-access': 7.24.7 + '@babel/helper-split-export-declaration': 7.24.7 + '@babel/helper-validator-identifier': 7.24.7 + transitivePeerDependencies: + - supports-color - '@babel/helper-optimise-call-expression@7.22.5': + '@babel/helper-optimise-call-expression@7.24.7': dependencies: - '@babel/types': 7.24.0 + '@babel/types': 7.24.7 '@babel/helper-plugin-utils@7.22.5': {} - '@babel/helper-remap-async-to-generator@7.22.20(@babel/core@7.24.0)': - dependencies: - '@babel/core': 7.24.0 - '@babel/helper-annotate-as-pure': 7.22.5 - '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-wrap-function': 7.22.20 + '@babel/helper-plugin-utils@7.24.7': {} - '@babel/helper-replace-supers@7.22.20(@babel/core@7.24.0)': + '@babel/helper-remap-async-to-generator@7.24.7(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 - '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-member-expression-to-functions': 7.23.0 - '@babel/helper-optimise-call-expression': 7.22.5 + '@babel/core': 7.24.7 + '@babel/helper-annotate-as-pure': 7.24.7 + '@babel/helper-environment-visitor': 7.24.7 + '@babel/helper-wrap-function': 7.24.7 + transitivePeerDependencies: + - supports-color + + '@babel/helper-replace-supers@7.24.7(@babel/core@7.24.7)': + dependencies: + '@babel/core': 7.24.7 + '@babel/helper-environment-visitor': 7.24.7 + '@babel/helper-member-expression-to-functions': 7.24.7 + '@babel/helper-optimise-call-expression': 7.24.7 + transitivePeerDependencies: + - supports-color '@babel/helper-simple-access@7.22.5': dependencies: '@babel/types': 7.23.5 - '@babel/helper-skip-transparent-expression-wrappers@7.22.5': + '@babel/helper-simple-access@7.24.7': dependencies: - '@babel/types': 7.24.0 + '@babel/traverse': 7.24.7 + '@babel/types': 7.24.7 + transitivePeerDependencies: + - supports-color + + '@babel/helper-skip-transparent-expression-wrappers@7.24.7': + dependencies: + '@babel/traverse': 7.24.7 + '@babel/types': 7.24.7 + transitivePeerDependencies: + - supports-color '@babel/helper-split-export-declaration@7.22.6': dependencies: '@babel/types': 7.23.5 + '@babel/helper-split-export-declaration@7.24.7': + dependencies: + '@babel/types': 7.24.7 + '@babel/helper-string-parser@7.23.4': {} + '@babel/helper-string-parser@7.24.7': {} + '@babel/helper-validator-identifier@7.22.20': {} + '@babel/helper-validator-identifier@7.24.7': {} + '@babel/helper-validator-option@7.23.5': {} - '@babel/helper-wrap-function@7.22.20': + '@babel/helper-validator-option@7.24.7': {} + + '@babel/helper-wrap-function@7.24.7': dependencies: - '@babel/helper-function-name': 7.23.0 - '@babel/template': 7.24.0 - '@babel/types': 7.24.0 + '@babel/helper-function-name': 7.24.7 + '@babel/template': 7.24.7 + '@babel/traverse': 7.24.7 + '@babel/types': 7.24.7 + transitivePeerDependencies: + - supports-color '@babel/helpers@7.23.5': dependencies: @@ -12102,13 +12917,10 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/helpers@7.24.0': + '@babel/helpers@7.24.7': dependencies: - '@babel/template': 7.24.0 - '@babel/traverse': 7.24.0 - '@babel/types': 7.24.0 - transitivePeerDependencies: - - supports-color + '@babel/template': 7.24.7 + '@babel/types': 7.24.7 '@babel/highlight@7.23.4': dependencies: @@ -12116,48 +12928,63 @@ snapshots: chalk: 2.4.2 js-tokens: 4.0.0 + '@babel/highlight@7.24.7': + dependencies: + '@babel/helper-validator-identifier': 7.24.7 + chalk: 2.4.2 + js-tokens: 4.0.0 + picocolors: 1.0.0 + '@babel/parser@7.23.9': dependencies: '@babel/types': 7.23.5 - '@babel/parser@7.24.0': - dependencies: - '@babel/types': 7.24.0 - '@babel/parser@7.24.5': dependencies: '@babel/types': 7.24.0 - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.23.3(@babel/core@7.24.0)': + '@babel/parser@7.24.7': dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/types': 7.24.7 - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.23.3(@babel/core@7.24.0)': + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.24.7(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 - '@babel/plugin-transform-optional-chaining': 7.23.4(@babel/core@7.24.0) + '@babel/core': 7.24.7 + '@babel/helper-environment-visitor': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.23.3(@babel/core@7.24.0)': + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.24.7(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 - '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.24.0)': + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.24.7(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-skip-transparent-expression-wrappers': 7.24.7 + '@babel/plugin-transform-optional-chaining': 7.24.7(@babel/core@7.24.7) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.24.7(@babel/core@7.24.7)': + dependencies: + '@babel/core': 7.24.7 + '@babel/helper-environment-visitor': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 + + '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.24.7)': + dependencies: + '@babel/core': 7.24.7 '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.23.5)': dependencies: '@babel/core': 7.23.5 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.24.0)': + '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 + '@babel/core': 7.24.7 '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.23.5)': @@ -12170,49 +12997,49 @@ snapshots: '@babel/core': 7.23.5 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.24.0)': + '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 + '@babel/core': 7.24.7 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.24.0)': + '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.24.0)': + '@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-syntax-export-namespace-from@7.8.3(@babel/core@7.24.0)': + '@babel/plugin-syntax-export-namespace-from@7.8.3(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-syntax-flow@7.23.3(@babel/core@7.24.0)': + '@babel/plugin-syntax-flow@7.23.3(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-syntax-import-assertions@7.23.3(@babel/core@7.24.0)': + '@babel/plugin-syntax-import-assertions@7.24.7(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-syntax-import-attributes@7.23.3(@babel/core@7.24.0)': + '@babel/plugin-syntax-import-attributes@7.24.7(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.23.5)': dependencies: '@babel/core': 7.23.5 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.24.0)': + '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 + '@babel/core': 7.24.7 '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.23.5)': @@ -12220,9 +13047,9 @@ snapshots: '@babel/core': 7.23.5 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.24.0)': + '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 + '@babel/core': 7.24.7 '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-jsx@7.23.3(@babel/core@7.23.5)': @@ -12230,9 +13057,9 @@ snapshots: '@babel/core': 7.23.5 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-jsx@7.23.3(@babel/core@7.24.0)': + '@babel/plugin-syntax-jsx@7.23.3(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 + '@babel/core': 7.24.7 '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.23.5)': @@ -12240,9 +13067,9 @@ snapshots: '@babel/core': 7.23.5 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.24.0)': + '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 + '@babel/core': 7.24.7 '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.23.5)': @@ -12250,9 +13077,9 @@ snapshots: '@babel/core': 7.23.5 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.24.0)': + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 + '@babel/core': 7.24.7 '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.23.5)': @@ -12260,9 +13087,9 @@ snapshots: '@babel/core': 7.23.5 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.24.0)': + '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 + '@babel/core': 7.24.7 '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.23.5)': @@ -12270,9 +13097,9 @@ snapshots: '@babel/core': 7.23.5 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.24.0)': + '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 + '@babel/core': 7.24.7 '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.23.5)': @@ -12280,9 +13107,9 @@ snapshots: '@babel/core': 7.23.5 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.24.0)': + '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 + '@babel/core': 7.24.7 '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.23.5)': @@ -12290,24 +13117,24 @@ snapshots: '@babel/core': 7.23.5 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.24.0)': + '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 + '@babel/core': 7.24.7 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.24.0)': + '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.23.5)': dependencies: '@babel/core': 7.23.5 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.24.0)': + '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 + '@babel/core': 7.24.7 '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-typescript@7.23.3(@babel/core@7.23.5)': @@ -12315,435 +13142,471 @@ snapshots: '@babel/core': 7.23.5 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-typescript@7.23.3(@babel/core@7.24.0)': + '@babel/plugin-syntax-typescript@7.23.3(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 + '@babel/core': 7.24.7 '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.24.0)': + '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 - '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.0) - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.24.7 + '@babel/helper-create-regexp-features-plugin': 7.24.7(@babel/core@7.24.7) + '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-transform-arrow-functions@7.23.3(@babel/core@7.24.0)': + '@babel/plugin-transform-arrow-functions@7.24.7(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-transform-async-generator-functions@7.23.4(@babel/core@7.24.0)': + '@babel/plugin-transform-async-generator-functions@7.24.7(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 - '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.24.0) - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.24.0) + '@babel/core': 7.24.7 + '@babel/helper-environment-visitor': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-remap-async-to-generator': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.24.7) + transitivePeerDependencies: + - supports-color - '@babel/plugin-transform-async-to-generator@7.23.3(@babel/core@7.24.0)': + '@babel/plugin-transform-async-to-generator@7.24.7(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 - '@babel/helper-module-imports': 7.22.15 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.24.0) + '@babel/core': 7.24.7 + '@babel/helper-module-imports': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-remap-async-to-generator': 7.24.7(@babel/core@7.24.7) + transitivePeerDependencies: + - supports-color - '@babel/plugin-transform-block-scoped-functions@7.23.3(@babel/core@7.24.0)': + '@babel/plugin-transform-block-scoped-functions@7.24.7(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-transform-block-scoping@7.23.4(@babel/core@7.24.0)': + '@babel/plugin-transform-block-scoping@7.24.7(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-transform-class-properties@7.23.3(@babel/core@7.24.0)': + '@babel/plugin-transform-class-properties@7.24.7(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 - '@babel/helper-create-class-features-plugin': 7.23.5(@babel/core@7.24.0) - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.24.7 + '@babel/helper-create-class-features-plugin': 7.24.7(@babel/core@7.24.7) + '@babel/helper-plugin-utils': 7.24.7 + transitivePeerDependencies: + - supports-color - '@babel/plugin-transform-class-static-block@7.23.4(@babel/core@7.24.0)': + '@babel/plugin-transform-class-static-block@7.24.7(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 - '@babel/helper-create-class-features-plugin': 7.23.5(@babel/core@7.24.0) - '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.24.0) + '@babel/core': 7.24.7 + '@babel/helper-create-class-features-plugin': 7.24.7(@babel/core@7.24.7) + '@babel/helper-plugin-utils': 7.24.7 + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.24.7) + transitivePeerDependencies: + - supports-color - '@babel/plugin-transform-classes@7.23.5(@babel/core@7.24.0)': + '@babel/plugin-transform-classes@7.24.7(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 - '@babel/helper-annotate-as-pure': 7.22.5 - '@babel/helper-compilation-targets': 7.23.6 - '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-function-name': 7.23.0 - '@babel/helper-optimise-call-expression': 7.22.5 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/helper-replace-supers': 7.22.20(@babel/core@7.24.0) - '@babel/helper-split-export-declaration': 7.22.6 + '@babel/core': 7.24.7 + '@babel/helper-annotate-as-pure': 7.24.7 + '@babel/helper-compilation-targets': 7.24.7 + '@babel/helper-environment-visitor': 7.24.7 + '@babel/helper-function-name': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-replace-supers': 7.24.7(@babel/core@7.24.7) + '@babel/helper-split-export-declaration': 7.24.7 globals: 11.12.0 + transitivePeerDependencies: + - supports-color - '@babel/plugin-transform-computed-properties@7.23.3(@babel/core@7.24.0)': + '@babel/plugin-transform-computed-properties@7.24.7(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/template': 7.24.0 + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 + '@babel/template': 7.24.7 - '@babel/plugin-transform-destructuring@7.23.3(@babel/core@7.24.0)': + '@babel/plugin-transform-destructuring@7.24.7(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-transform-dotall-regex@7.23.3(@babel/core@7.24.0)': + '@babel/plugin-transform-dotall-regex@7.24.7(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 - '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.0) - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.24.7 + '@babel/helper-create-regexp-features-plugin': 7.24.7(@babel/core@7.24.7) + '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-transform-duplicate-keys@7.23.3(@babel/core@7.24.0)': + '@babel/plugin-transform-duplicate-keys@7.24.7(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-transform-dynamic-import@7.23.4(@babel/core@7.24.0)': + '@babel/plugin-transform-dynamic-import@7.24.7(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.24.0) + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 + '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.24.7) - '@babel/plugin-transform-exponentiation-operator@7.23.3(@babel/core@7.24.0)': + '@babel/plugin-transform-exponentiation-operator@7.24.7(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 - '@babel/helper-builder-binary-assignment-operator-visitor': 7.22.15 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.24.7 + '@babel/helper-builder-binary-assignment-operator-visitor': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 + transitivePeerDependencies: + - supports-color - '@babel/plugin-transform-export-namespace-from@7.23.4(@babel/core@7.24.0)': + '@babel/plugin-transform-export-namespace-from@7.24.7(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.24.0) + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 + '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.24.7) - '@babel/plugin-transform-flow-strip-types@7.23.3(@babel/core@7.24.0)': + '@babel/plugin-transform-flow-strip-types@7.23.3(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-flow': 7.23.3(@babel/core@7.24.0) + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 + '@babel/plugin-syntax-flow': 7.23.3(@babel/core@7.24.7) - '@babel/plugin-transform-for-of@7.23.3(@babel/core@7.24.0)': + '@babel/plugin-transform-for-of@7.24.7(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-skip-transparent-expression-wrappers': 7.24.7 + transitivePeerDependencies: + - supports-color - '@babel/plugin-transform-function-name@7.23.3(@babel/core@7.24.0)': + '@babel/plugin-transform-function-name@7.24.7(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 - '@babel/helper-compilation-targets': 7.23.6 - '@babel/helper-function-name': 7.23.0 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.24.7 + '@babel/helper-compilation-targets': 7.24.7 + '@babel/helper-function-name': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-transform-json-strings@7.23.4(@babel/core@7.24.0)': + '@babel/plugin-transform-json-strings@7.24.7(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.24.0) + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.24.7) - '@babel/plugin-transform-literals@7.23.3(@babel/core@7.24.0)': + '@babel/plugin-transform-literals@7.24.7(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-transform-logical-assignment-operators@7.23.4(@babel/core@7.24.0)': + '@babel/plugin-transform-logical-assignment-operators@7.24.7(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.24.0) + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.24.7) - '@babel/plugin-transform-member-expression-literals@7.23.3(@babel/core@7.24.0)': + '@babel/plugin-transform-member-expression-literals@7.24.7(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-transform-modules-amd@7.23.3(@babel/core@7.24.0)': + '@babel/plugin-transform-modules-amd@7.24.7(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 - '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.0) - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.24.7 + '@babel/helper-module-transforms': 7.24.7(@babel/core@7.24.7) + '@babel/helper-plugin-utils': 7.24.7 + transitivePeerDependencies: + - supports-color - '@babel/plugin-transform-modules-commonjs@7.23.3(@babel/core@7.24.0)': + '@babel/plugin-transform-modules-commonjs@7.24.7(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 - '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.0) - '@babel/helper-plugin-utils': 7.22.5 - '@babel/helper-simple-access': 7.22.5 + '@babel/core': 7.24.7 + '@babel/helper-module-transforms': 7.24.7(@babel/core@7.24.7) + '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-simple-access': 7.24.7 + transitivePeerDependencies: + - supports-color - '@babel/plugin-transform-modules-systemjs@7.23.3(@babel/core@7.24.0)': + '@babel/plugin-transform-modules-systemjs@7.24.7(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 - '@babel/helper-hoist-variables': 7.22.5 - '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.0) - '@babel/helper-plugin-utils': 7.22.5 - '@babel/helper-validator-identifier': 7.22.20 + '@babel/core': 7.24.7 + '@babel/helper-hoist-variables': 7.24.7 + '@babel/helper-module-transforms': 7.24.7(@babel/core@7.24.7) + '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-validator-identifier': 7.24.7 + transitivePeerDependencies: + - supports-color - '@babel/plugin-transform-modules-umd@7.23.3(@babel/core@7.24.0)': + '@babel/plugin-transform-modules-umd@7.24.7(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 - '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.0) - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.24.7 + '@babel/helper-module-transforms': 7.24.7(@babel/core@7.24.7) + '@babel/helper-plugin-utils': 7.24.7 + transitivePeerDependencies: + - supports-color - '@babel/plugin-transform-named-capturing-groups-regex@7.22.5(@babel/core@7.24.0)': + '@babel/plugin-transform-named-capturing-groups-regex@7.24.7(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 - '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.0) - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.24.7 + '@babel/helper-create-regexp-features-plugin': 7.24.7(@babel/core@7.24.7) + '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-transform-new-target@7.23.3(@babel/core@7.24.0)': + '@babel/plugin-transform-new-target@7.24.7(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-transform-nullish-coalescing-operator@7.23.4(@babel/core@7.24.0)': + '@babel/plugin-transform-nullish-coalescing-operator@7.24.7(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.0) + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.7) - '@babel/plugin-transform-numeric-separator@7.23.4(@babel/core@7.24.0)': + '@babel/plugin-transform-numeric-separator@7.24.7(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.24.0) + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.24.7) - '@babel/plugin-transform-object-rest-spread@7.23.4(@babel/core@7.24.0)': + '@babel/plugin-transform-object-rest-spread@7.24.7(@babel/core@7.24.7)': dependencies: - '@babel/compat-data': 7.23.5 - '@babel/core': 7.24.0 - '@babel/helper-compilation-targets': 7.23.6 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.24.0) - '@babel/plugin-transform-parameters': 7.23.3(@babel/core@7.24.0) + '@babel/core': 7.24.7 + '@babel/helper-compilation-targets': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.24.7) + '@babel/plugin-transform-parameters': 7.24.7(@babel/core@7.24.7) - '@babel/plugin-transform-object-super@7.23.3(@babel/core@7.24.0)': + '@babel/plugin-transform-object-super@7.24.7(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/helper-replace-supers': 7.22.20(@babel/core@7.24.0) + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-replace-supers': 7.24.7(@babel/core@7.24.7) + transitivePeerDependencies: + - supports-color - '@babel/plugin-transform-optional-catch-binding@7.23.4(@babel/core@7.24.0)': + '@babel/plugin-transform-optional-catch-binding@7.24.7(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.24.0) + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.24.7) - '@babel/plugin-transform-optional-chaining@7.23.4(@babel/core@7.24.0)': + '@babel/plugin-transform-optional-chaining@7.24.7(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.0) + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-skip-transparent-expression-wrappers': 7.24.7 + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.7) + transitivePeerDependencies: + - supports-color - '@babel/plugin-transform-parameters@7.23.3(@babel/core@7.24.0)': + '@babel/plugin-transform-parameters@7.24.7(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-transform-private-methods@7.23.3(@babel/core@7.24.0)': + '@babel/plugin-transform-private-methods@7.24.7(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 - '@babel/helper-create-class-features-plugin': 7.23.5(@babel/core@7.24.0) - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.24.7 + '@babel/helper-create-class-features-plugin': 7.24.7(@babel/core@7.24.7) + '@babel/helper-plugin-utils': 7.24.7 + transitivePeerDependencies: + - supports-color - '@babel/plugin-transform-private-property-in-object@7.23.4(@babel/core@7.24.0)': + '@babel/plugin-transform-private-property-in-object@7.24.7(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 - '@babel/helper-annotate-as-pure': 7.22.5 - '@babel/helper-create-class-features-plugin': 7.23.5(@babel/core@7.24.0) - '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.24.0) + '@babel/core': 7.24.7 + '@babel/helper-annotate-as-pure': 7.24.7 + '@babel/helper-create-class-features-plugin': 7.24.7(@babel/core@7.24.7) + '@babel/helper-plugin-utils': 7.24.7 + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.24.7) + transitivePeerDependencies: + - supports-color - '@babel/plugin-transform-property-literals@7.23.3(@babel/core@7.24.0)': + '@babel/plugin-transform-property-literals@7.24.7(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-transform-regenerator@7.23.3(@babel/core@7.24.0)': + '@babel/plugin-transform-regenerator@7.24.7(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 regenerator-transform: 0.15.2 - '@babel/plugin-transform-reserved-words@7.23.3(@babel/core@7.24.0)': + '@babel/plugin-transform-reserved-words@7.24.7(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-transform-shorthand-properties@7.23.3(@babel/core@7.24.0)': + '@babel/plugin-transform-shorthand-properties@7.24.7(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-transform-spread@7.23.3(@babel/core@7.24.0)': + '@babel/plugin-transform-spread@7.24.7(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-skip-transparent-expression-wrappers': 7.24.7 + transitivePeerDependencies: + - supports-color - '@babel/plugin-transform-sticky-regex@7.23.3(@babel/core@7.24.0)': + '@babel/plugin-transform-sticky-regex@7.24.7(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-transform-template-literals@7.23.3(@babel/core@7.24.0)': + '@babel/plugin-transform-template-literals@7.24.7(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-transform-typeof-symbol@7.23.3(@babel/core@7.24.0)': + '@babel/plugin-transform-typeof-symbol@7.24.7(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-transform-typescript@7.23.5(@babel/core@7.24.0)': + '@babel/plugin-transform-typescript@7.23.5(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 - '@babel/helper-annotate-as-pure': 7.22.5 - '@babel/helper-create-class-features-plugin': 7.23.5(@babel/core@7.24.0) - '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-typescript': 7.23.3(@babel/core@7.24.0) + '@babel/core': 7.24.7 + '@babel/helper-annotate-as-pure': 7.24.7 + '@babel/helper-create-class-features-plugin': 7.24.7(@babel/core@7.24.7) + '@babel/helper-plugin-utils': 7.24.7 + '@babel/plugin-syntax-typescript': 7.23.3(@babel/core@7.24.7) + transitivePeerDependencies: + - supports-color - '@babel/plugin-transform-unicode-escapes@7.23.3(@babel/core@7.24.0)': + '@babel/plugin-transform-unicode-escapes@7.24.7(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-transform-unicode-property-regex@7.23.3(@babel/core@7.24.0)': + '@babel/plugin-transform-unicode-property-regex@7.24.7(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 - '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.0) - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.24.7 + '@babel/helper-create-regexp-features-plugin': 7.24.7(@babel/core@7.24.7) + '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-transform-unicode-regex@7.23.3(@babel/core@7.24.0)': + '@babel/plugin-transform-unicode-regex@7.24.7(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 - '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.0) - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.24.7 + '@babel/helper-create-regexp-features-plugin': 7.24.7(@babel/core@7.24.7) + '@babel/helper-plugin-utils': 7.24.7 - '@babel/plugin-transform-unicode-sets-regex@7.23.3(@babel/core@7.24.0)': + '@babel/plugin-transform-unicode-sets-regex@7.24.7(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 - '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.0) - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.24.7 + '@babel/helper-create-regexp-features-plugin': 7.24.7(@babel/core@7.24.7) + '@babel/helper-plugin-utils': 7.24.7 - '@babel/preset-env@7.23.5(@babel/core@7.24.0)': + '@babel/preset-env@7.24.7(@babel/core@7.24.7)': dependencies: - '@babel/compat-data': 7.23.5 - '@babel/core': 7.24.0 - '@babel/helper-compilation-targets': 7.23.6 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/helper-validator-option': 7.23.5 - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.24.0) - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.24.0) - '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.24.0) - '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.24.0) - '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.24.0) - '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.24.0) - '@babel/plugin-syntax-import-assertions': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-syntax-import-attributes': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.24.0) - '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.24.0) - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.24.0) - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.0) - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.24.0) - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.24.0) - '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.24.0) - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.0) - '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.24.0) - '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.24.0) - '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.24.0) - '@babel/plugin-transform-arrow-functions': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-transform-async-generator-functions': 7.23.4(@babel/core@7.24.0) - '@babel/plugin-transform-async-to-generator': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-transform-block-scoped-functions': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-transform-block-scoping': 7.23.4(@babel/core@7.24.0) - '@babel/plugin-transform-class-properties': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-transform-class-static-block': 7.23.4(@babel/core@7.24.0) - '@babel/plugin-transform-classes': 7.23.5(@babel/core@7.24.0) - '@babel/plugin-transform-computed-properties': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-transform-destructuring': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-transform-dotall-regex': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-transform-duplicate-keys': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-transform-dynamic-import': 7.23.4(@babel/core@7.24.0) - '@babel/plugin-transform-exponentiation-operator': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-transform-export-namespace-from': 7.23.4(@babel/core@7.24.0) - '@babel/plugin-transform-for-of': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-transform-function-name': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-transform-json-strings': 7.23.4(@babel/core@7.24.0) - '@babel/plugin-transform-literals': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-transform-logical-assignment-operators': 7.23.4(@babel/core@7.24.0) - '@babel/plugin-transform-member-expression-literals': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-transform-modules-amd': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-transform-modules-commonjs': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-transform-modules-systemjs': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-transform-modules-umd': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-transform-named-capturing-groups-regex': 7.22.5(@babel/core@7.24.0) - '@babel/plugin-transform-new-target': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-transform-nullish-coalescing-operator': 7.23.4(@babel/core@7.24.0) - '@babel/plugin-transform-numeric-separator': 7.23.4(@babel/core@7.24.0) - '@babel/plugin-transform-object-rest-spread': 7.23.4(@babel/core@7.24.0) - '@babel/plugin-transform-object-super': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-transform-optional-catch-binding': 7.23.4(@babel/core@7.24.0) - '@babel/plugin-transform-optional-chaining': 7.23.4(@babel/core@7.24.0) - '@babel/plugin-transform-parameters': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-transform-private-methods': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-transform-private-property-in-object': 7.23.4(@babel/core@7.24.0) - '@babel/plugin-transform-property-literals': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-transform-regenerator': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-transform-reserved-words': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-transform-shorthand-properties': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-transform-spread': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-transform-sticky-regex': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-transform-template-literals': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-transform-typeof-symbol': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-transform-unicode-escapes': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-transform-unicode-property-regex': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-transform-unicode-regex': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-transform-unicode-sets-regex': 7.23.3(@babel/core@7.24.0) - '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.24.0) - babel-plugin-polyfill-corejs2: 0.4.6(@babel/core@7.24.0) - babel-plugin-polyfill-corejs3: 0.8.6(@babel/core@7.24.0) - babel-plugin-polyfill-regenerator: 0.5.3(@babel/core@7.24.0) - core-js-compat: 3.33.3 + '@babel/compat-data': 7.24.7 + '@babel/core': 7.24.7 + '@babel/helper-compilation-targets': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-validator-option': 7.24.7 + '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.24.7) + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.24.7) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.24.7) + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.24.7) + '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.24.7) + '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.24.7) + '@babel/plugin-syntax-import-assertions': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-syntax-import-attributes': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.24.7) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.24.7) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.24.7) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.7) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.24.7) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.24.7) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.24.7) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.7) + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.24.7) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.24.7) + '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.24.7) + '@babel/plugin-transform-arrow-functions': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-async-generator-functions': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-async-to-generator': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-block-scoped-functions': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-block-scoping': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-class-properties': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-class-static-block': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-classes': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-computed-properties': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-destructuring': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-dotall-regex': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-duplicate-keys': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-dynamic-import': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-exponentiation-operator': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-export-namespace-from': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-for-of': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-function-name': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-json-strings': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-literals': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-logical-assignment-operators': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-member-expression-literals': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-modules-amd': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-modules-commonjs': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-modules-systemjs': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-modules-umd': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-named-capturing-groups-regex': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-new-target': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-nullish-coalescing-operator': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-numeric-separator': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-object-rest-spread': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-object-super': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-optional-catch-binding': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-optional-chaining': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-parameters': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-private-methods': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-private-property-in-object': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-property-literals': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-regenerator': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-reserved-words': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-shorthand-properties': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-spread': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-sticky-regex': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-template-literals': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-typeof-symbol': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-unicode-escapes': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-unicode-property-regex': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-unicode-regex': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-unicode-sets-regex': 7.24.7(@babel/core@7.24.7) + '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.24.7) + babel-plugin-polyfill-corejs2: 0.4.11(@babel/core@7.24.7) + babel-plugin-polyfill-corejs3: 0.10.4(@babel/core@7.24.7) + babel-plugin-polyfill-regenerator: 0.6.2(@babel/core@7.24.7) + core-js-compat: 3.37.1 semver: 6.3.1 transitivePeerDependencies: - supports-color - '@babel/preset-flow@7.23.3(@babel/core@7.24.0)': + '@babel/preset-flow@7.23.3(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/helper-validator-option': 7.23.5 - '@babel/plugin-transform-flow-strip-types': 7.23.3(@babel/core@7.24.0) + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-validator-option': 7.24.7 + '@babel/plugin-transform-flow-strip-types': 7.23.3(@babel/core@7.24.7) - '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.24.0)': + '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/types': 7.24.0 + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 + '@babel/types': 7.24.7 esutils: 2.0.3 - '@babel/preset-typescript@7.23.3(@babel/core@7.24.0)': + '@babel/preset-typescript@7.23.3(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/helper-validator-option': 7.23.5 - '@babel/plugin-syntax-jsx': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-transform-modules-commonjs': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-transform-typescript': 7.23.5(@babel/core@7.24.0) + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-validator-option': 7.24.7 + '@babel/plugin-syntax-jsx': 7.23.3(@babel/core@7.24.7) + '@babel/plugin-transform-modules-commonjs': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-typescript': 7.23.5(@babel/core@7.24.7) + transitivePeerDependencies: + - supports-color - '@babel/register@7.22.15(@babel/core@7.24.0)': + '@babel/register@7.22.15(@babel/core@7.24.7)': dependencies: - '@babel/core': 7.24.0 + '@babel/core': 7.24.7 clone-deep: 4.0.1 find-cache-dir: 2.1.0 make-dir: 2.1.0 @@ -12764,9 +13627,15 @@ snapshots: '@babel/template@7.24.0': dependencies: - '@babel/code-frame': 7.23.5 - '@babel/parser': 7.24.0 - '@babel/types': 7.24.0 + '@babel/code-frame': 7.24.7 + '@babel/parser': 7.24.7 + '@babel/types': 7.24.7 + + '@babel/template@7.24.7': + dependencies: + '@babel/code-frame': 7.24.7 + '@babel/parser': 7.24.7 + '@babel/types': 7.24.7 '@babel/traverse@7.23.5': dependencies: @@ -12778,22 +13647,22 @@ snapshots: '@babel/helper-split-export-declaration': 7.22.6 '@babel/parser': 7.23.9 '@babel/types': 7.23.5 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.5(supports-color@8.1.1) globals: 11.12.0 transitivePeerDependencies: - supports-color - '@babel/traverse@7.24.0': + '@babel/traverse@7.24.7': dependencies: - '@babel/code-frame': 7.23.5 - '@babel/generator': 7.23.6 - '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-function-name': 7.23.0 - '@babel/helper-hoist-variables': 7.22.5 - '@babel/helper-split-export-declaration': 7.22.6 - '@babel/parser': 7.24.0 - '@babel/types': 7.24.0 - debug: 4.3.4(supports-color@8.1.1) + '@babel/code-frame': 7.24.7 + '@babel/generator': 7.24.7 + '@babel/helper-environment-visitor': 7.24.7 + '@babel/helper-function-name': 7.24.7 + '@babel/helper-hoist-variables': 7.24.7 + '@babel/helper-split-export-declaration': 7.24.7 + '@babel/parser': 7.24.7 + '@babel/types': 7.24.7 + debug: 4.3.5(supports-color@8.1.1) globals: 11.12.0 transitivePeerDependencies: - supports-color @@ -12810,26 +13679,32 @@ snapshots: '@babel/helper-validator-identifier': 7.22.20 to-fast-properties: 2.0.0 + '@babel/types@7.24.7': + dependencies: + '@babel/helper-string-parser': 7.24.7 + '@babel/helper-validator-identifier': 7.24.7 + to-fast-properties: 2.0.0 + '@base2/pretty-print-object@1.0.1': {} '@bcoe/v8-coverage@0.2.3': {} - '@bull-board/api@5.17.0(@bull-board/ui@5.17.0)': + '@bull-board/api@5.20.5(@bull-board/ui@5.20.5)': dependencies: - '@bull-board/ui': 5.17.0 + '@bull-board/ui': 5.20.5 redis-info: 3.1.0 - '@bull-board/fastify@5.17.0': + '@bull-board/fastify@5.20.5': dependencies: - '@bull-board/api': 5.17.0(@bull-board/ui@5.17.0) - '@bull-board/ui': 5.17.0 + '@bull-board/api': 5.20.5(@bull-board/ui@5.20.5) + '@bull-board/ui': 5.20.5 '@fastify/static': 6.12.0 '@fastify/view': 8.2.0 - ejs: 3.1.9 + ejs: 3.1.10 - '@bull-board/ui@5.17.0': + '@bull-board/ui@5.20.5': dependencies: - '@bull-board/api': 5.17.0(@bull-board/ui@5.17.0) + '@bull-board/api': 5.20.5(@bull-board/ui@5.20.5) '@bundled-es-modules/cookie@2.0.0': dependencies: @@ -12927,7 +13802,7 @@ snapshots: performance-now: 2.1.0 qs: 6.10.4 safe-buffer: 5.2.1 - tough-cookie: 4.1.3 + tough-cookie: 4.1.4 tunnel-agent: 0.6.0 uuid: 8.3.2 @@ -12938,10 +13813,10 @@ snapshots: transitivePeerDependencies: - supports-color - '@digitalbazaar/http-client@3.4.1(web-streams-polyfill@3.2.1)': + '@digitalbazaar/http-client@3.4.1(web-streams-polyfill@4.0.0)': dependencies: ky: 0.33.3 - ky-universal: 0.11.0(ky@0.33.3)(web-streams-polyfill@3.2.1) + ky-universal: 0.11.0(ky@0.33.3)(web-streams-polyfill@4.0.0) undici: 5.28.2 transitivePeerDependencies: - web-streams-polyfill @@ -12967,7 +13842,10 @@ snapshots: '@esbuild/aix-ppc64@0.19.11': optional: true - '@esbuild/aix-ppc64@0.20.2': + '@esbuild/aix-ppc64@0.21.5': + optional: true + + '@esbuild/aix-ppc64@0.22.0': optional: true '@esbuild/android-arm64@0.18.20': @@ -12976,7 +13854,10 @@ snapshots: '@esbuild/android-arm64@0.19.11': optional: true - '@esbuild/android-arm64@0.20.2': + '@esbuild/android-arm64@0.21.5': + optional: true + + '@esbuild/android-arm64@0.22.0': optional: true '@esbuild/android-arm@0.18.20': @@ -12985,7 +13866,10 @@ snapshots: '@esbuild/android-arm@0.19.11': optional: true - '@esbuild/android-arm@0.20.2': + '@esbuild/android-arm@0.21.5': + optional: true + + '@esbuild/android-arm@0.22.0': optional: true '@esbuild/android-x64@0.18.20': @@ -12994,7 +13878,10 @@ snapshots: '@esbuild/android-x64@0.19.11': optional: true - '@esbuild/android-x64@0.20.2': + '@esbuild/android-x64@0.21.5': + optional: true + + '@esbuild/android-x64@0.22.0': optional: true '@esbuild/darwin-arm64@0.18.20': @@ -13003,7 +13890,10 @@ snapshots: '@esbuild/darwin-arm64@0.19.11': optional: true - '@esbuild/darwin-arm64@0.20.2': + '@esbuild/darwin-arm64@0.21.5': + optional: true + + '@esbuild/darwin-arm64@0.22.0': optional: true '@esbuild/darwin-x64@0.18.20': @@ -13012,7 +13902,10 @@ snapshots: '@esbuild/darwin-x64@0.19.11': optional: true - '@esbuild/darwin-x64@0.20.2': + '@esbuild/darwin-x64@0.21.5': + optional: true + + '@esbuild/darwin-x64@0.22.0': optional: true '@esbuild/freebsd-arm64@0.18.20': @@ -13021,7 +13914,10 @@ snapshots: '@esbuild/freebsd-arm64@0.19.11': optional: true - '@esbuild/freebsd-arm64@0.20.2': + '@esbuild/freebsd-arm64@0.21.5': + optional: true + + '@esbuild/freebsd-arm64@0.22.0': optional: true '@esbuild/freebsd-x64@0.18.20': @@ -13030,7 +13926,10 @@ snapshots: '@esbuild/freebsd-x64@0.19.11': optional: true - '@esbuild/freebsd-x64@0.20.2': + '@esbuild/freebsd-x64@0.21.5': + optional: true + + '@esbuild/freebsd-x64@0.22.0': optional: true '@esbuild/linux-arm64@0.18.20': @@ -13039,7 +13938,10 @@ snapshots: '@esbuild/linux-arm64@0.19.11': optional: true - '@esbuild/linux-arm64@0.20.2': + '@esbuild/linux-arm64@0.21.5': + optional: true + + '@esbuild/linux-arm64@0.22.0': optional: true '@esbuild/linux-arm@0.18.20': @@ -13048,7 +13950,10 @@ snapshots: '@esbuild/linux-arm@0.19.11': optional: true - '@esbuild/linux-arm@0.20.2': + '@esbuild/linux-arm@0.21.5': + optional: true + + '@esbuild/linux-arm@0.22.0': optional: true '@esbuild/linux-ia32@0.18.20': @@ -13057,7 +13962,10 @@ snapshots: '@esbuild/linux-ia32@0.19.11': optional: true - '@esbuild/linux-ia32@0.20.2': + '@esbuild/linux-ia32@0.21.5': + optional: true + + '@esbuild/linux-ia32@0.22.0': optional: true '@esbuild/linux-loong64@0.18.20': @@ -13066,7 +13974,10 @@ snapshots: '@esbuild/linux-loong64@0.19.11': optional: true - '@esbuild/linux-loong64@0.20.2': + '@esbuild/linux-loong64@0.21.5': + optional: true + + '@esbuild/linux-loong64@0.22.0': optional: true '@esbuild/linux-mips64el@0.18.20': @@ -13075,7 +13986,10 @@ snapshots: '@esbuild/linux-mips64el@0.19.11': optional: true - '@esbuild/linux-mips64el@0.20.2': + '@esbuild/linux-mips64el@0.21.5': + optional: true + + '@esbuild/linux-mips64el@0.22.0': optional: true '@esbuild/linux-ppc64@0.18.20': @@ -13084,7 +13998,10 @@ snapshots: '@esbuild/linux-ppc64@0.19.11': optional: true - '@esbuild/linux-ppc64@0.20.2': + '@esbuild/linux-ppc64@0.21.5': + optional: true + + '@esbuild/linux-ppc64@0.22.0': optional: true '@esbuild/linux-riscv64@0.18.20': @@ -13093,7 +14010,10 @@ snapshots: '@esbuild/linux-riscv64@0.19.11': optional: true - '@esbuild/linux-riscv64@0.20.2': + '@esbuild/linux-riscv64@0.21.5': + optional: true + + '@esbuild/linux-riscv64@0.22.0': optional: true '@esbuild/linux-s390x@0.18.20': @@ -13102,7 +14022,10 @@ snapshots: '@esbuild/linux-s390x@0.19.11': optional: true - '@esbuild/linux-s390x@0.20.2': + '@esbuild/linux-s390x@0.21.5': + optional: true + + '@esbuild/linux-s390x@0.22.0': optional: true '@esbuild/linux-x64@0.18.20': @@ -13111,7 +14034,10 @@ snapshots: '@esbuild/linux-x64@0.19.11': optional: true - '@esbuild/linux-x64@0.20.2': + '@esbuild/linux-x64@0.21.5': + optional: true + + '@esbuild/linux-x64@0.22.0': optional: true '@esbuild/netbsd-x64@0.18.20': @@ -13120,7 +14046,13 @@ snapshots: '@esbuild/netbsd-x64@0.19.11': optional: true - '@esbuild/netbsd-x64@0.20.2': + '@esbuild/netbsd-x64@0.21.5': + optional: true + + '@esbuild/netbsd-x64@0.22.0': + optional: true + + '@esbuild/openbsd-arm64@0.22.0': optional: true '@esbuild/openbsd-x64@0.18.20': @@ -13129,7 +14061,10 @@ snapshots: '@esbuild/openbsd-x64@0.19.11': optional: true - '@esbuild/openbsd-x64@0.20.2': + '@esbuild/openbsd-x64@0.21.5': + optional: true + + '@esbuild/openbsd-x64@0.22.0': optional: true '@esbuild/sunos-x64@0.18.20': @@ -13138,7 +14073,10 @@ snapshots: '@esbuild/sunos-x64@0.19.11': optional: true - '@esbuild/sunos-x64@0.20.2': + '@esbuild/sunos-x64@0.21.5': + optional: true + + '@esbuild/sunos-x64@0.22.0': optional: true '@esbuild/win32-arm64@0.18.20': @@ -13147,7 +14085,10 @@ snapshots: '@esbuild/win32-arm64@0.19.11': optional: true - '@esbuild/win32-arm64@0.20.2': + '@esbuild/win32-arm64@0.21.5': + optional: true + + '@esbuild/win32-arm64@0.22.0': optional: true '@esbuild/win32-ia32@0.18.20': @@ -13156,7 +14097,10 @@ snapshots: '@esbuild/win32-ia32@0.19.11': optional: true - '@esbuild/win32-ia32@0.20.2': + '@esbuild/win32-ia32@0.21.5': + optional: true + + '@esbuild/win32-ia32@0.22.0': optional: true '@esbuild/win32-x64@0.18.20': @@ -13165,30 +14109,45 @@ snapshots: '@esbuild/win32-x64@0.19.11': optional: true - '@esbuild/win32-x64@0.20.2': + '@esbuild/win32-x64@0.21.5': optional: true - '@eslint-community/eslint-utils@4.4.0(eslint@8.53.0)': + '@esbuild/win32-x64@0.22.0': + optional: true + + '@eslint-community/eslint-utils@4.4.0(eslint@9.6.0)': dependencies: - eslint: 8.53.0 + eslint: 9.6.0 eslint-visitor-keys: 3.4.3 - '@eslint-community/eslint-utils@4.4.0(eslint@8.57.0)': + '@eslint-community/eslint-utils@4.4.0(eslint@9.7.0)': dependencies: - eslint: 8.57.0 + eslint: 9.7.0 eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.10.0': {} + '@eslint-community/regexpp@4.11.0': {} + '@eslint-community/regexpp@4.6.2': {} - '@eslint/eslintrc@2.1.4': + '@eslint/compat@1.1.1': {} + + '@eslint/config-array@0.17.0': + dependencies: + '@eslint/object-schema': 2.1.4 + debug: 4.3.5(supports-color@8.1.1) + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + + '@eslint/eslintrc@3.1.0': dependencies: ajv: 6.12.6 - debug: 4.3.4(supports-color@8.1.1) - espree: 9.6.1 - globals: 13.19.0 - ignore: 5.2.4 + debug: 4.3.5(supports-color@8.1.1) + espree: 10.1.0 + globals: 14.0.0 + ignore: 5.3.1 import-fresh: 3.3.0 js-yaml: 4.1.0 minimatch: 3.1.2 @@ -13196,9 +14155,11 @@ snapshots: transitivePeerDependencies: - supports-color - '@eslint/js@8.53.0': {} + '@eslint/js@9.6.0': {} - '@eslint/js@8.57.0': {} + '@eslint/js@9.7.0': {} + + '@eslint/object-schema@2.1.4': {} '@fal-works/esbuild-plugin-global-externals@2.1.2': {} @@ -13211,8 +14172,8 @@ snapshots: '@fastify/ajv-compiler@3.5.0': dependencies: - ajv: 8.13.0 - ajv-formats: 2.1.1(ajv@8.13.0) + ajv: 8.16.0 + ajv-formats: 2.1.1(ajv@8.16.0) fast-uri: 2.2.0 '@fastify/busboy@2.1.0': {} @@ -13242,17 +14203,17 @@ snapshots: dependencies: fast-json-stringify: 5.8.0 - '@fastify/http-proxy@9.5.0(bufferutil@4.0.7)(utf-8-validate@6.0.3)': + '@fastify/http-proxy@9.5.0(bufferutil@4.0.8)(utf-8-validate@6.0.4)': dependencies: '@fastify/reply-from': 9.0.1 fast-querystring: 1.1.2 fastify-plugin: 4.5.0 - ws: 8.17.0(bufferutil@4.0.7)(utf-8-validate@6.0.3) + ws: 8.17.1(bufferutil@4.0.8)(utf-8-validate@6.0.4) transitivePeerDependencies: - bufferutil - utf-8-validate - '@fastify/multipart@8.2.0': + '@fastify/multipart@8.3.0': dependencies: '@fastify/busboy': 2.1.0 '@fastify/deepmerge': 1.3.0 @@ -13288,14 +14249,14 @@ snapshots: glob: 8.1.0 p-limit: 3.1.0 - '@fastify/static@7.0.3': + '@fastify/static@7.0.4': dependencies: '@fastify/accept-negotiator': 1.0.0 '@fastify/send': 2.0.1 content-disposition: 0.5.4 fastify-plugin: 4.5.0 fastq: 1.17.1 - glob: 10.3.12 + glob: 10.4.2 '@fastify/view@8.2.0': dependencies: @@ -13311,13 +14272,11 @@ snapshots: '@hapi/boom@10.0.1': dependencies: - '@hapi/hoek': 11.0.2 + '@hapi/hoek': 11.0.4 '@hapi/bourne@3.0.0': {} - '@hapi/hoek@10.0.1': {} - - '@hapi/hoek@11.0.2': {} + '@hapi/hoek@11.0.4': {} '@hapi/hoek@9.3.0': {} @@ -13329,40 +14288,22 @@ snapshots: dependencies: '@hapi/boom': 10.0.1 '@hapi/bourne': 3.0.0 - '@hapi/hoek': 11.0.2 + '@hapi/hoek': 11.0.4 '@hexagon/base64@1.1.27': {} - '@humanwhocodes/config-array@0.11.13': - dependencies: - '@humanwhocodes/object-schema': 2.0.1 - debug: 4.3.4(supports-color@8.1.1) - minimatch: 3.1.2 - transitivePeerDependencies: - - supports-color - - '@humanwhocodes/config-array@0.11.14': - dependencies: - '@humanwhocodes/object-schema': 2.0.2 - debug: 4.3.4(supports-color@8.1.1) - minimatch: 3.1.2 - transitivePeerDependencies: - - supports-color - '@humanwhocodes/module-importer@1.0.1': {} '@humanwhocodes/momoa@2.0.4': {} - '@humanwhocodes/object-schema@2.0.1': {} + '@humanwhocodes/retry@0.3.0': {} - '@humanwhocodes/object-schema@2.0.2': {} - - '@img/sharp-darwin-arm64@0.33.3': + '@img/sharp-darwin-arm64@0.33.4': optionalDependencies: '@img/sharp-libvips-darwin-arm64': 1.0.2 optional: true - '@img/sharp-darwin-x64@0.33.3': + '@img/sharp-darwin-x64@0.33.4': optionalDependencies: '@img/sharp-libvips-darwin-x64': 1.0.2 optional: true @@ -13391,45 +14332,45 @@ snapshots: '@img/sharp-libvips-linuxmusl-x64@1.0.2': optional: true - '@img/sharp-linux-arm64@0.33.3': + '@img/sharp-linux-arm64@0.33.4': optionalDependencies: '@img/sharp-libvips-linux-arm64': 1.0.2 optional: true - '@img/sharp-linux-arm@0.33.3': + '@img/sharp-linux-arm@0.33.4': optionalDependencies: '@img/sharp-libvips-linux-arm': 1.0.2 optional: true - '@img/sharp-linux-s390x@0.33.3': + '@img/sharp-linux-s390x@0.33.4': optionalDependencies: '@img/sharp-libvips-linux-s390x': 1.0.2 optional: true - '@img/sharp-linux-x64@0.33.3': + '@img/sharp-linux-x64@0.33.4': optionalDependencies: '@img/sharp-libvips-linux-x64': 1.0.2 optional: true - '@img/sharp-linuxmusl-arm64@0.33.3': + '@img/sharp-linuxmusl-arm64@0.33.4': optionalDependencies: '@img/sharp-libvips-linuxmusl-arm64': 1.0.2 optional: true - '@img/sharp-linuxmusl-x64@0.33.3': + '@img/sharp-linuxmusl-x64@0.33.4': optionalDependencies: '@img/sharp-libvips-linuxmusl-x64': 1.0.2 optional: true - '@img/sharp-wasm32@0.33.3': + '@img/sharp-wasm32@0.33.4': dependencies: '@emnapi/runtime': 1.1.1 optional: true - '@img/sharp-win32-ia32@0.33.3': + '@img/sharp-win32-ia32@0.33.4': optional: true - '@img/sharp-win32-x64@0.33.3': + '@img/sharp-win32-x64@0.33.4': optional: true '@inquirer/confirm@3.1.6': @@ -13442,7 +14383,7 @@ snapshots: '@inquirer/figures': 1.0.1 '@inquirer/type': 1.3.1 '@types/mute-stream': 0.0.4 - '@types/node': 20.12.7 + '@types/node': 20.14.9 '@types/wrap-ansi': 3.0.0 ansi-escapes: 4.3.2 chalk: 4.1.2 @@ -13465,7 +14406,7 @@ snapshots: '@intlify/message-compiler@9.13.1': dependencies: '@intlify/shared': 9.13.1 - source-map-js: 1.0.2 + source-map-js: 1.2.0 '@intlify/shared@9.13.1': {} @@ -13493,7 +14434,7 @@ snapshots: '@jest/console@29.7.0': dependencies: '@jest/types': 29.6.3 - '@types/node': 20.12.7 + '@types/node': 20.14.9 chalk: 4.1.2 jest-message-util: 29.7.0 jest-util: 29.7.0 @@ -13506,14 +14447,14 @@ snapshots: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.12.7 + '@types/node': 20.14.9 ansi-escapes: 4.3.2 chalk: 4.1.2 ci-info: 3.7.1 exit: 0.1.2 graceful-fs: 4.2.11 jest-changed-files: 29.7.0 - jest-config: 29.7.0(@types/node@20.12.7) + jest-config: 29.7.0(@types/node@20.14.9) jest-haste-map: 29.7.0 jest-message-util: 29.7.0 jest-regex-util: 29.6.3 @@ -13525,7 +14466,7 @@ snapshots: jest-util: 29.7.0 jest-validate: 29.7.0 jest-watcher: 29.7.0 - micromatch: 4.0.5 + micromatch: 4.0.7 pretty-format: 29.7.0 slash: 3.0.0 strip-ansi: 6.0.1 @@ -13542,7 +14483,7 @@ snapshots: dependencies: '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.12.7 + '@types/node': 20.14.9 jest-mock: 29.7.0 '@jest/expect-utils@29.7.0': @@ -13560,7 +14501,7 @@ snapshots: dependencies: '@jest/types': 29.6.3 '@sinonjs/fake-timers': 10.3.0 - '@types/node': 20.12.7 + '@types/node': 20.14.9 jest-message-util: 29.7.0 jest-mock: 29.7.0 jest-util: 29.7.0 @@ -13582,7 +14523,7 @@ snapshots: '@jest/transform': 29.7.0 '@jest/types': 29.6.3 '@jridgewell/trace-mapping': 0.3.18 - '@types/node': 20.12.7 + '@types/node': 20.14.9 chalk: 4.1.2 collect-v8-coverage: 1.0.1 exit: 0.1.2 @@ -13640,7 +14581,7 @@ snapshots: jest-haste-map: 29.7.0 jest-regex-util: 29.6.3 jest-util: 29.7.0 - micromatch: 4.0.5 + micromatch: 4.0.7 pirates: 4.0.5 slash: 3.0.0 write-file-atomic: 4.0.2 @@ -13652,19 +14593,19 @@ snapshots: '@jest/schemas': 29.6.3 '@types/istanbul-lib-coverage': 2.0.4 '@types/istanbul-reports': 3.0.1 - '@types/node': 20.12.7 + '@types/node': 20.14.9 '@types/yargs': 17.0.19 chalk: 4.1.2 - '@joshwooding/vite-plugin-react-docgen-typescript@0.3.0(typescript@5.4.5)(vite@5.2.11(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3))': + '@joshwooding/vite-plugin-react-docgen-typescript@0.3.1(typescript@5.5.3)(vite@5.3.2(@types/node@20.14.9)(sass@1.77.6)(terser@5.31.2))': dependencies: glob: 7.2.3 glob-promise: 4.2.2(glob@7.2.3) magic-string: 0.27.0 - react-docgen-typescript: 2.2.2(typescript@5.4.5) - vite: 5.2.11(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3) + react-docgen-typescript: 2.2.2(typescript@5.5.3) + vite: 5.3.2(@types/node@20.14.9)(sass@1.77.6)(terser@5.31.2) optionalDependencies: - typescript: 5.4.5 + typescript: 5.5.3 '@jridgewell/gen-mapping@0.3.2': dependencies: @@ -13672,14 +14613,28 @@ snapshots: '@jridgewell/sourcemap-codec': 1.4.15 '@jridgewell/trace-mapping': 0.3.18 + '@jridgewell/gen-mapping@0.3.5': + dependencies: + '@jridgewell/set-array': 1.2.1 + '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/trace-mapping': 0.3.25 + '@jridgewell/resolve-uri@3.1.0': {} '@jridgewell/set-array@1.1.2': {} + '@jridgewell/set-array@1.2.1': {} + '@jridgewell/source-map@0.3.5': dependencies: - '@jridgewell/gen-mapping': 0.3.2 - '@jridgewell/trace-mapping': 0.3.18 + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 + + '@jridgewell/source-map@0.3.6': + dependencies: + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 + optional: true '@jridgewell/sourcemap-codec@1.4.14': {} @@ -13690,10 +14645,17 @@ snapshots: '@jridgewell/resolve-uri': 3.1.0 '@jridgewell/sourcemap-codec': 1.4.14 + '@jridgewell/trace-mapping@0.3.25': + dependencies: + '@jridgewell/resolve-uri': 3.1.0 + '@jridgewell/sourcemap-codec': 1.4.15 + '@jsdevtools/ono@7.1.3': {} '@kurkle/color@0.3.2': {} + '@lapo/asn1js@2.0.4': {} + '@levischuck/tiny-cbor@0.2.2': {} '@lukeed/csprng@1.0.1': {} @@ -13728,23 +14690,23 @@ snapshots: '@types/react': 18.0.28 react: 18.3.1 - '@microsoft/api-extractor-model@7.28.14(@types/node@20.12.7)': + '@microsoft/api-extractor-model@7.29.2(@types/node@20.14.9)': dependencies: - '@microsoft/tsdoc': 0.14.2 - '@microsoft/tsdoc-config': 0.16.2 - '@rushstack/node-core-library': 4.1.0(@types/node@20.12.7) + '@microsoft/tsdoc': 0.15.0 + '@microsoft/tsdoc-config': 0.17.0 + '@rushstack/node-core-library': 5.4.1(@types/node@20.14.9) transitivePeerDependencies: - '@types/node' - '@microsoft/api-extractor@7.43.1(@types/node@20.12.7)': + '@microsoft/api-extractor@7.47.0(@types/node@20.14.9)': dependencies: - '@microsoft/api-extractor-model': 7.28.14(@types/node@20.12.7) - '@microsoft/tsdoc': 0.14.2 - '@microsoft/tsdoc-config': 0.16.2 - '@rushstack/node-core-library': 4.1.0(@types/node@20.12.7) + '@microsoft/api-extractor-model': 7.29.2(@types/node@20.14.9) + '@microsoft/tsdoc': 0.15.0 + '@microsoft/tsdoc-config': 0.17.0 + '@rushstack/node-core-library': 5.4.1(@types/node@20.14.9) '@rushstack/rig-package': 0.5.2 - '@rushstack/terminal': 0.10.1(@types/node@20.12.7) - '@rushstack/ts-command-line': 4.19.2(@types/node@20.12.7) + '@rushstack/terminal': 0.13.0(@types/node@20.14.9) + '@rushstack/ts-command-line': 4.22.0(@types/node@20.14.9) lodash: 4.17.21 minimatch: 3.0.8 resolve: 1.22.8 @@ -13754,43 +14716,37 @@ snapshots: transitivePeerDependencies: - '@types/node' - '@microsoft/tsdoc-config@0.16.2': + '@microsoft/tsdoc-config@0.17.0': dependencies: - '@microsoft/tsdoc': 0.14.2 - ajv: 6.12.6 + '@microsoft/tsdoc': 0.15.0 + ajv: 8.12.0 jju: 1.4.0 - resolve: 1.19.0 + resolve: 1.22.8 - '@microsoft/tsdoc@0.14.2': {} + '@microsoft/tsdoc@0.15.0': {} '@misskey-dev/browser-image-resizer@2024.1.0': {} - '@misskey-dev/eslint-plugin@1.0.0(@typescript-eslint/eslint-plugin@6.11.0(@typescript-eslint/parser@6.11.0(eslint@8.53.0)(typescript@5.3.3))(eslint@8.53.0)(typescript@5.3.3))(@typescript-eslint/parser@6.11.0(eslint@8.53.0)(typescript@5.3.3))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.11.0(eslint@8.53.0)(typescript@5.3.3))(eslint@8.53.0))(eslint@8.53.0)': + '@misskey-dev/eslint-plugin@2.0.2(@eslint/compat@1.1.1)(@typescript-eslint/eslint-plugin@7.15.0(@typescript-eslint/parser@7.15.0(eslint@9.6.0)(typescript@5.5.3))(eslint@9.6.0)(typescript@5.5.3))(@typescript-eslint/parser@7.15.0(eslint@9.6.0)(typescript@5.5.3))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.15.0(eslint@9.6.0)(typescript@5.5.3))(eslint@9.6.0))(eslint@9.6.0)(globals@15.7.0)': dependencies: - '@typescript-eslint/eslint-plugin': 6.11.0(@typescript-eslint/parser@6.11.0(eslint@8.53.0)(typescript@5.3.3))(eslint@8.53.0)(typescript@5.3.3) - '@typescript-eslint/parser': 6.11.0(eslint@8.53.0)(typescript@5.3.3) - eslint: 8.53.0 - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.11.0(eslint@8.53.0)(typescript@5.3.3))(eslint@8.53.0) + '@eslint/compat': 1.1.1 + '@typescript-eslint/eslint-plugin': 7.15.0(@typescript-eslint/parser@7.15.0(eslint@9.6.0)(typescript@5.5.3))(eslint@9.6.0)(typescript@5.5.3) + '@typescript-eslint/parser': 7.15.0(eslint@9.6.0)(typescript@5.5.3) + eslint: 9.6.0 + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.15.0(eslint@9.6.0)(typescript@5.5.3))(eslint@9.6.0) + globals: 15.7.0 - '@misskey-dev/eslint-plugin@1.0.0(@typescript-eslint/eslint-plugin@7.1.0(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint@8.57.0)(typescript@5.3.3))(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint@8.57.0))(eslint@8.57.0)': + '@misskey-dev/node-http-message-signatures@0.0.10': dependencies: - '@typescript-eslint/eslint-plugin': 7.1.0(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint@8.57.0)(typescript@5.3.3) - '@typescript-eslint/parser': 7.1.0(eslint@8.57.0)(typescript@5.3.3) - eslint: 8.57.0 - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint@8.57.0) - - '@misskey-dev/eslint-plugin@1.0.0(@typescript-eslint/eslint-plugin@7.7.1(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5))(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0))(eslint@8.57.0)': - dependencies: - '@typescript-eslint/eslint-plugin': 7.7.1(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5) - '@typescript-eslint/parser': 7.7.1(eslint@8.57.0)(typescript@5.4.5) - eslint: 8.57.0 - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0) + '@lapo/asn1js': 2.0.4 + rfc4648: 1.5.3 + structured-headers: 1.0.1 '@misskey-dev/sharp-read-bmp@1.2.0': dependencies: decode-bmp: 0.2.1 decode-ico: 0.4.1 - sharp: 0.33.3 + sharp: 0.33.4 '@misskey-dev/summaly@5.1.0': dependencies: @@ -13834,7 +14790,7 @@ snapshots: '@mswjs/cookies@1.1.0': {} - '@mswjs/interceptors@0.26.15': + '@mswjs/interceptors@0.29.1': dependencies: '@open-draft/deferred-promise': 2.2.0 '@open-draft/logger': 0.3.0 @@ -13843,44 +14799,44 @@ snapshots: outvariant: 1.4.2 strict-event-emitter: 0.5.1 - '@napi-rs/canvas-android-arm64@0.1.52': + '@napi-rs/canvas-android-arm64@0.1.53': optional: true - '@napi-rs/canvas-darwin-arm64@0.1.52': + '@napi-rs/canvas-darwin-arm64@0.1.53': optional: true - '@napi-rs/canvas-darwin-x64@0.1.52': + '@napi-rs/canvas-darwin-x64@0.1.53': optional: true - '@napi-rs/canvas-linux-arm-gnueabihf@0.1.52': + '@napi-rs/canvas-linux-arm-gnueabihf@0.1.53': optional: true - '@napi-rs/canvas-linux-arm64-gnu@0.1.52': + '@napi-rs/canvas-linux-arm64-gnu@0.1.53': optional: true - '@napi-rs/canvas-linux-arm64-musl@0.1.52': + '@napi-rs/canvas-linux-arm64-musl@0.1.53': optional: true - '@napi-rs/canvas-linux-x64-gnu@0.1.52': + '@napi-rs/canvas-linux-x64-gnu@0.1.53': optional: true - '@napi-rs/canvas-linux-x64-musl@0.1.52': + '@napi-rs/canvas-linux-x64-musl@0.1.53': optional: true - '@napi-rs/canvas-win32-x64-msvc@0.1.52': + '@napi-rs/canvas-win32-x64-msvc@0.1.53': optional: true - '@napi-rs/canvas@0.1.52': + '@napi-rs/canvas@0.1.53': optionalDependencies: - '@napi-rs/canvas-android-arm64': 0.1.52 - '@napi-rs/canvas-darwin-arm64': 0.1.52 - '@napi-rs/canvas-darwin-x64': 0.1.52 - '@napi-rs/canvas-linux-arm-gnueabihf': 0.1.52 - '@napi-rs/canvas-linux-arm64-gnu': 0.1.52 - '@napi-rs/canvas-linux-arm64-musl': 0.1.52 - '@napi-rs/canvas-linux-x64-gnu': 0.1.52 - '@napi-rs/canvas-linux-x64-musl': 0.1.52 - '@napi-rs/canvas-win32-x64-msvc': 0.1.52 + '@napi-rs/canvas-android-arm64': 0.1.53 + '@napi-rs/canvas-darwin-arm64': 0.1.53 + '@napi-rs/canvas-darwin-x64': 0.1.53 + '@napi-rs/canvas-linux-arm-gnueabihf': 0.1.53 + '@napi-rs/canvas-linux-arm64-gnu': 0.1.53 + '@napi-rs/canvas-linux-arm64-musl': 0.1.53 + '@napi-rs/canvas-linux-x64-gnu': 0.1.53 + '@napi-rs/canvas-linux-x64-musl': 0.1.53 + '@napi-rs/canvas-win32-x64-msvc': 0.1.53 '@ndelangen/get-tarball@3.0.7': dependencies: @@ -13888,49 +14844,51 @@ snapshots: pump: 3.0.0 tar-fs: 2.1.1 - '@nestjs/common@10.3.8(reflect-metadata@0.2.2)(rxjs@7.8.1)': + '@nestjs/common@10.3.10(reflect-metadata@0.2.2)(rxjs@7.8.1)': dependencies: iterare: 1.2.1 reflect-metadata: 0.2.2 rxjs: 7.8.1 - tslib: 2.6.2 + tslib: 2.6.3 uid: 2.0.2 - '@nestjs/core@10.3.8(@nestjs/common@10.3.8(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.3.8)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1)': + '@nestjs/core@10.3.10(@nestjs/common@10.3.10(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.3.10)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1)': dependencies: - '@nestjs/common': 10.3.8(reflect-metadata@0.2.2)(rxjs@7.8.1) + '@nestjs/common': 10.3.10(reflect-metadata@0.2.2)(rxjs@7.8.1) '@nuxtjs/opencollective': 0.3.2(encoding@0.1.13) fast-safe-stringify: 2.1.1 iterare: 1.2.1 path-to-regexp: 3.2.0 reflect-metadata: 0.2.2 rxjs: 7.8.1 - tslib: 2.6.2 + tslib: 2.6.3 uid: 2.0.2 optionalDependencies: - '@nestjs/platform-express': 10.3.8(@nestjs/common@10.3.8(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.3.8) + '@nestjs/platform-express': 10.3.10(@nestjs/common@10.3.10(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.3.10) transitivePeerDependencies: - encoding - '@nestjs/platform-express@10.3.8(@nestjs/common@10.3.8(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.3.8)': + '@nestjs/platform-express@10.3.10(@nestjs/common@10.3.10(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.3.10)': dependencies: - '@nestjs/common': 10.3.8(reflect-metadata@0.2.2)(rxjs@7.8.1) - '@nestjs/core': 10.3.8(@nestjs/common@10.3.8(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.3.8)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1) + '@nestjs/common': 10.3.10(reflect-metadata@0.2.2)(rxjs@7.8.1) + '@nestjs/core': 10.3.10(@nestjs/common@10.3.10(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.3.10)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1) body-parser: 1.20.2 cors: 2.8.5 express: 4.19.2 multer: 1.4.4-lts.1 - tslib: 2.6.2 + tslib: 2.6.3 transitivePeerDependencies: - supports-color - '@nestjs/testing@10.3.8(@nestjs/common@10.3.8(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.3.8(@nestjs/common@10.3.8(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.3.8)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.3.8(@nestjs/common@10.3.8(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.3.8))': + '@nestjs/testing@10.3.10(@nestjs/common@10.3.10(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.3.10(@nestjs/common@10.3.10(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.3.10)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.3.10(@nestjs/common@10.3.10(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.3.10))': dependencies: - '@nestjs/common': 10.3.8(reflect-metadata@0.2.2)(rxjs@7.8.1) - '@nestjs/core': 10.3.8(@nestjs/common@10.3.8(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.3.8)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1) - tslib: 2.6.2 + '@nestjs/common': 10.3.10(reflect-metadata@0.2.2)(rxjs@7.8.1) + '@nestjs/core': 10.3.10(@nestjs/common@10.3.10(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.3.10)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1) + tslib: 2.6.3 optionalDependencies: - '@nestjs/platform-express': 10.3.8(@nestjs/common@10.3.8(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.3.8) + '@nestjs/platform-express': 10.3.10(@nestjs/common@10.3.10(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.3.10) + + '@noble/hashes@1.4.0': {} '@nodelib/fs.scandir@2.1.5': dependencies: @@ -13942,14 +14900,14 @@ snapshots: '@nodelib/fs.walk@1.2.8': dependencies: '@nodelib/fs.scandir': 2.1.5 - fastq: 1.15.0 + fastq: 1.17.1 '@npmcli/agent@2.2.0': dependencies: agent-base: 7.1.0 http-proxy-agent: 7.0.0 https-proxy-agent: 7.0.2 - lru-cache: 10.0.2 + lru-cache: 10.2.2 socks-proxy-agent: 8.0.2 transitivePeerDependencies: - supports-color @@ -13991,153 +14949,167 @@ snapshots: '@open-draft/until@2.1.0': {} - '@opentelemetry/api-logs@0.51.1': + '@opentelemetry/api-logs@0.52.1': dependencies: - '@opentelemetry/api': 1.8.0 + '@opentelemetry/api': 1.9.0 - '@opentelemetry/api@1.8.0': {} + '@opentelemetry/api@1.9.0': {} - '@opentelemetry/context-async-hooks@1.24.1(@opentelemetry/api@1.8.0)': + '@opentelemetry/context-async-hooks@1.25.1(@opentelemetry/api@1.9.0)': dependencies: - '@opentelemetry/api': 1.8.0 + '@opentelemetry/api': 1.9.0 - '@opentelemetry/core@1.24.1(@opentelemetry/api@1.8.0)': + '@opentelemetry/core@1.24.1(@opentelemetry/api@1.9.0)': dependencies: - '@opentelemetry/api': 1.8.0 + '@opentelemetry/api': 1.9.0 '@opentelemetry/semantic-conventions': 1.24.1 - '@opentelemetry/instrumentation-connect@0.36.0(@opentelemetry/api@1.8.0)': + '@opentelemetry/core@1.25.1(@opentelemetry/api@1.9.0)': dependencies: - '@opentelemetry/api': 1.8.0 - '@opentelemetry/core': 1.24.1(@opentelemetry/api@1.8.0) - '@opentelemetry/instrumentation': 0.51.1(@opentelemetry/api@1.8.0) - '@opentelemetry/semantic-conventions': 1.24.1 + '@opentelemetry/api': 1.9.0 + '@opentelemetry/semantic-conventions': 1.25.1 + + '@opentelemetry/instrumentation-connect@0.37.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 1.25.1(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.52.1(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.25.1 '@types/connect': 3.4.36 transitivePeerDependencies: - supports-color - '@opentelemetry/instrumentation-express@0.39.0(@opentelemetry/api@1.8.0)': + '@opentelemetry/instrumentation-express@0.40.1(@opentelemetry/api@1.9.0)': dependencies: - '@opentelemetry/api': 1.8.0 - '@opentelemetry/core': 1.24.1(@opentelemetry/api@1.8.0) - '@opentelemetry/instrumentation': 0.51.1(@opentelemetry/api@1.8.0) - '@opentelemetry/semantic-conventions': 1.24.1 + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 1.25.1(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.52.1(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.25.1 transitivePeerDependencies: - supports-color - '@opentelemetry/instrumentation-fastify@0.36.1(@opentelemetry/api@1.8.0)': + '@opentelemetry/instrumentation-fastify@0.37.0(@opentelemetry/api@1.9.0)': dependencies: - '@opentelemetry/api': 1.8.0 - '@opentelemetry/core': 1.24.1(@opentelemetry/api@1.8.0) - '@opentelemetry/instrumentation': 0.51.1(@opentelemetry/api@1.8.0) - '@opentelemetry/semantic-conventions': 1.24.1 + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 1.25.1(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.52.1(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.25.1 transitivePeerDependencies: - supports-color - '@opentelemetry/instrumentation-graphql@0.40.0(@opentelemetry/api@1.8.0)': + '@opentelemetry/instrumentation-graphql@0.41.0(@opentelemetry/api@1.9.0)': dependencies: - '@opentelemetry/api': 1.8.0 - '@opentelemetry/instrumentation': 0.51.1(@opentelemetry/api@1.8.0) + '@opentelemetry/api': 1.9.0 + '@opentelemetry/instrumentation': 0.52.1(@opentelemetry/api@1.9.0) transitivePeerDependencies: - supports-color - '@opentelemetry/instrumentation-hapi@0.38.0(@opentelemetry/api@1.8.0)': + '@opentelemetry/instrumentation-hapi@0.39.0(@opentelemetry/api@1.9.0)': dependencies: - '@opentelemetry/api': 1.8.0 - '@opentelemetry/core': 1.24.1(@opentelemetry/api@1.8.0) - '@opentelemetry/instrumentation': 0.51.1(@opentelemetry/api@1.8.0) - '@opentelemetry/semantic-conventions': 1.24.1 + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 1.25.1(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.52.1(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.25.1 transitivePeerDependencies: - supports-color - '@opentelemetry/instrumentation-http@0.51.1(@opentelemetry/api@1.8.0)': + '@opentelemetry/instrumentation-http@0.52.1(@opentelemetry/api@1.9.0)': dependencies: - '@opentelemetry/api': 1.8.0 - '@opentelemetry/core': 1.24.1(@opentelemetry/api@1.8.0) - '@opentelemetry/instrumentation': 0.51.1(@opentelemetry/api@1.8.0) - '@opentelemetry/semantic-conventions': 1.24.1 + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 1.25.1(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.52.1(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.25.1 semver: 7.6.0 transitivePeerDependencies: - supports-color - '@opentelemetry/instrumentation-ioredis@0.40.0(@opentelemetry/api@1.8.0)': + '@opentelemetry/instrumentation-ioredis@0.41.0(@opentelemetry/api@1.9.0)': dependencies: - '@opentelemetry/api': 1.8.0 - '@opentelemetry/instrumentation': 0.51.1(@opentelemetry/api@1.8.0) + '@opentelemetry/api': 1.9.0 + '@opentelemetry/instrumentation': 0.52.1(@opentelemetry/api@1.9.0) '@opentelemetry/redis-common': 0.36.2 - '@opentelemetry/semantic-conventions': 1.24.1 + '@opentelemetry/semantic-conventions': 1.25.1 transitivePeerDependencies: - supports-color - '@opentelemetry/instrumentation-koa@0.40.0(@opentelemetry/api@1.8.0)': + '@opentelemetry/instrumentation-koa@0.41.0(@opentelemetry/api@1.9.0)': dependencies: - '@opentelemetry/api': 1.8.0 - '@opentelemetry/core': 1.24.1(@opentelemetry/api@1.8.0) - '@opentelemetry/instrumentation': 0.51.1(@opentelemetry/api@1.8.0) - '@opentelemetry/semantic-conventions': 1.24.1 + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 1.25.1(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.52.1(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.25.1 '@types/koa': 2.14.0 '@types/koa__router': 12.0.3 transitivePeerDependencies: - supports-color - '@opentelemetry/instrumentation-mongodb@0.43.0(@opentelemetry/api@1.8.0)': + '@opentelemetry/instrumentation-mongodb@0.45.0(@opentelemetry/api@1.9.0)': dependencies: - '@opentelemetry/api': 1.8.0 - '@opentelemetry/instrumentation': 0.51.1(@opentelemetry/api@1.8.0) - '@opentelemetry/sdk-metrics': 1.24.1(@opentelemetry/api@1.8.0) - '@opentelemetry/semantic-conventions': 1.24.1 + '@opentelemetry/api': 1.9.0 + '@opentelemetry/instrumentation': 0.52.1(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-metrics': 1.24.1(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.25.1 transitivePeerDependencies: - supports-color - '@opentelemetry/instrumentation-mongoose@0.38.1(@opentelemetry/api@1.8.0)': + '@opentelemetry/instrumentation-mongoose@0.39.0(@opentelemetry/api@1.9.0)': dependencies: - '@opentelemetry/api': 1.8.0 - '@opentelemetry/core': 1.24.1(@opentelemetry/api@1.8.0) - '@opentelemetry/instrumentation': 0.51.1(@opentelemetry/api@1.8.0) - '@opentelemetry/semantic-conventions': 1.24.1 + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 1.25.1(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.52.1(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.25.1 transitivePeerDependencies: - supports-color - '@opentelemetry/instrumentation-mysql2@0.38.1(@opentelemetry/api@1.8.0)': + '@opentelemetry/instrumentation-mysql2@0.39.0(@opentelemetry/api@1.9.0)': dependencies: - '@opentelemetry/api': 1.8.0 - '@opentelemetry/instrumentation': 0.51.1(@opentelemetry/api@1.8.0) - '@opentelemetry/semantic-conventions': 1.24.1 - '@opentelemetry/sql-common': 0.40.1(@opentelemetry/api@1.8.0) + '@opentelemetry/api': 1.9.0 + '@opentelemetry/instrumentation': 0.52.1(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.25.1 + '@opentelemetry/sql-common': 0.40.1(@opentelemetry/api@1.9.0) transitivePeerDependencies: - supports-color - '@opentelemetry/instrumentation-mysql@0.38.1(@opentelemetry/api@1.8.0)': + '@opentelemetry/instrumentation-mysql@0.39.0(@opentelemetry/api@1.9.0)': dependencies: - '@opentelemetry/api': 1.8.0 - '@opentelemetry/instrumentation': 0.51.1(@opentelemetry/api@1.8.0) - '@opentelemetry/semantic-conventions': 1.24.1 + '@opentelemetry/api': 1.9.0 + '@opentelemetry/instrumentation': 0.52.1(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.25.1 '@types/mysql': 2.15.22 transitivePeerDependencies: - supports-color - '@opentelemetry/instrumentation-nestjs-core@0.37.1(@opentelemetry/api@1.8.0)': + '@opentelemetry/instrumentation-nestjs-core@0.38.0(@opentelemetry/api@1.9.0)': dependencies: - '@opentelemetry/api': 1.8.0 - '@opentelemetry/instrumentation': 0.51.1(@opentelemetry/api@1.8.0) - '@opentelemetry/semantic-conventions': 1.24.1 + '@opentelemetry/api': 1.9.0 + '@opentelemetry/instrumentation': 0.52.1(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.25.1 transitivePeerDependencies: - supports-color - '@opentelemetry/instrumentation-pg@0.41.0(@opentelemetry/api@1.8.0)': + '@opentelemetry/instrumentation-pg@0.42.0(@opentelemetry/api@1.9.0)': dependencies: - '@opentelemetry/api': 1.8.0 - '@opentelemetry/instrumentation': 0.51.1(@opentelemetry/api@1.8.0) - '@opentelemetry/semantic-conventions': 1.24.1 - '@opentelemetry/sql-common': 0.40.1(@opentelemetry/api@1.8.0) + '@opentelemetry/api': 1.9.0 + '@opentelemetry/instrumentation': 0.52.1(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.25.1 + '@opentelemetry/sql-common': 0.40.1(@opentelemetry/api@1.9.0) '@types/pg': 8.6.1 '@types/pg-pool': 2.0.4 transitivePeerDependencies: - supports-color - '@opentelemetry/instrumentation@0.43.0(@opentelemetry/api@1.8.0)': + '@opentelemetry/instrumentation-redis-4@0.40.0(@opentelemetry/api@1.9.0)': dependencies: - '@opentelemetry/api': 1.8.0 + '@opentelemetry/api': 1.9.0 + '@opentelemetry/instrumentation': 0.52.1(@opentelemetry/api@1.9.0) + '@opentelemetry/redis-common': 0.36.2 + '@opentelemetry/semantic-conventions': 1.25.1 + transitivePeerDependencies: + - supports-color + + '@opentelemetry/instrumentation@0.43.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 '@types/shimmer': 1.0.5 import-in-the-middle: 1.4.2 require-in-the-middle: 7.3.0 @@ -14147,12 +15119,12 @@ snapshots: - supports-color optional: true - '@opentelemetry/instrumentation@0.51.1(@opentelemetry/api@1.8.0)': + '@opentelemetry/instrumentation@0.52.1(@opentelemetry/api@1.9.0)': dependencies: - '@opentelemetry/api': 1.8.0 - '@opentelemetry/api-logs': 0.51.1 + '@opentelemetry/api': 1.9.0 + '@opentelemetry/api-logs': 0.52.1 '@types/shimmer': 1.0.5 - import-in-the-middle: 1.7.4 + import-in-the-middle: 1.8.1 require-in-the-middle: 7.3.0 semver: 7.6.0 shimmer: 1.2.1 @@ -14161,32 +15133,40 @@ snapshots: '@opentelemetry/redis-common@0.36.2': {} - '@opentelemetry/resources@1.24.1(@opentelemetry/api@1.8.0)': + '@opentelemetry/resources@1.24.1(@opentelemetry/api@1.9.0)': dependencies: - '@opentelemetry/api': 1.8.0 - '@opentelemetry/core': 1.24.1(@opentelemetry/api@1.8.0) + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 1.24.1(@opentelemetry/api@1.9.0) '@opentelemetry/semantic-conventions': 1.24.1 - '@opentelemetry/sdk-metrics@1.24.1(@opentelemetry/api@1.8.0)': + '@opentelemetry/resources@1.25.1(@opentelemetry/api@1.9.0)': dependencies: - '@opentelemetry/api': 1.8.0 - '@opentelemetry/core': 1.24.1(@opentelemetry/api@1.8.0) - '@opentelemetry/resources': 1.24.1(@opentelemetry/api@1.8.0) + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 1.25.1(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.25.1 + + '@opentelemetry/sdk-metrics@1.24.1(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 1.24.1(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 1.24.1(@opentelemetry/api@1.9.0) lodash.merge: 4.6.2 - '@opentelemetry/sdk-trace-base@1.24.1(@opentelemetry/api@1.8.0)': + '@opentelemetry/sdk-trace-base@1.25.1(@opentelemetry/api@1.9.0)': dependencies: - '@opentelemetry/api': 1.8.0 - '@opentelemetry/core': 1.24.1(@opentelemetry/api@1.8.0) - '@opentelemetry/resources': 1.24.1(@opentelemetry/api@1.8.0) - '@opentelemetry/semantic-conventions': 1.24.1 + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 1.25.1(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 1.25.1(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.25.1 '@opentelemetry/semantic-conventions@1.24.1': {} - '@opentelemetry/sql-common@0.40.1(@opentelemetry/api@1.8.0)': + '@opentelemetry/semantic-conventions@1.25.1': {} + + '@opentelemetry/sql-common@0.40.1(@opentelemetry/api@1.9.0)': dependencies: - '@opentelemetry/api': 1.8.0 - '@opentelemetry/core': 1.24.1(@opentelemetry/api@1.8.0) + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 1.25.1(@opentelemetry/api@1.9.0) '@peculiar/asn1-android@2.3.10': dependencies: @@ -14222,44 +15202,152 @@ snapshots: pvtsutils: 1.3.5 tslib: 2.6.2 - '@peertube/http-signature@1.7.0': - dependencies: - assert-plus: 1.0.0 - jsprim: 1.4.2 - sshpk: 1.17.0 - '@pkgjs/parseargs@0.11.0': optional: true - '@prisma/instrumentation@5.14.0': + '@prisma/instrumentation@5.16.0': dependencies: - '@opentelemetry/api': 1.8.0 - '@opentelemetry/instrumentation': 0.51.1(@opentelemetry/api@1.8.0) - '@opentelemetry/sdk-trace-base': 1.24.1(@opentelemetry/api@1.8.0) + '@opentelemetry/api': 1.9.0 + '@opentelemetry/instrumentation': 0.52.1(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-base': 1.25.1(@opentelemetry/api@1.9.0) transitivePeerDependencies: - supports-color - '@radix-ui/react-compose-refs@1.0.1(@types/react@18.0.28)(react@18.3.1)': + '@radix-ui/primitive@1.1.0': {} + + '@radix-ui/react-compose-refs@1.1.0(@types/react@18.0.28)(react@18.3.1)': dependencies: - '@babel/runtime': 7.23.4 react: 18.3.1 optionalDependencies: '@types/react': 18.0.28 - '@radix-ui/react-slot@1.0.2(@types/react@18.0.28)(react@18.3.1)': + '@radix-ui/react-context@1.1.0(@types/react@18.0.28)(react@18.3.1)': dependencies: - '@babel/runtime': 7.23.4 - '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.0.28)(react@18.3.1) react: 18.3.1 optionalDependencies: '@types/react': 18.0.28 - '@readme/better-ajv-errors@1.6.0(ajv@8.13.0)': + '@radix-ui/react-dialog@1.1.1(@types/react@18.0.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/primitive': 1.1.0 + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.0.28)(react@18.3.1) + '@radix-ui/react-context': 1.1.0(@types/react@18.0.28)(react@18.3.1) + '@radix-ui/react-dismissable-layer': 1.1.0(@types/react@18.0.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-focus-guards': 1.1.0(@types/react@18.0.28)(react@18.3.1) + '@radix-ui/react-focus-scope': 1.1.0(@types/react@18.0.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-id': 1.1.0(@types/react@18.0.28)(react@18.3.1) + '@radix-ui/react-portal': 1.1.1(@types/react@18.0.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-presence': 1.1.0(@types/react@18.0.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.0.0(@types/react@18.0.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-slot': 1.1.0(@types/react@18.0.28)(react@18.3.1) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.0.28)(react@18.3.1) + aria-hidden: 1.2.4 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + react-remove-scroll: 2.5.7(@types/react@18.0.28)(react@18.3.1) + optionalDependencies: + '@types/react': 18.0.28 + + '@radix-ui/react-dismissable-layer@1.1.0(@types/react@18.0.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/primitive': 1.1.0 + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.0.28)(react@18.3.1) + '@radix-ui/react-primitive': 2.0.0(@types/react@18.0.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.0.28)(react@18.3.1) + '@radix-ui/react-use-escape-keydown': 1.1.0(@types/react@18.0.28)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.0.28 + + '@radix-ui/react-focus-guards@1.1.0(@types/react@18.0.28)(react@18.3.1)': + dependencies: + react: 18.3.1 + optionalDependencies: + '@types/react': 18.0.28 + + '@radix-ui/react-focus-scope@1.1.0(@types/react@18.0.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.0.28)(react@18.3.1) + '@radix-ui/react-primitive': 2.0.0(@types/react@18.0.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.0.28)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.0.28 + + '@radix-ui/react-id@1.1.0(@types/react@18.0.28)(react@18.3.1)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.0.28)(react@18.3.1) + react: 18.3.1 + optionalDependencies: + '@types/react': 18.0.28 + + '@radix-ui/react-portal@1.1.1(@types/react@18.0.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/react-primitive': 2.0.0(@types/react@18.0.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.0.28)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.0.28 + + '@radix-ui/react-presence@1.1.0(@types/react@18.0.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.0.28)(react@18.3.1) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.0.28)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.0.28 + + '@radix-ui/react-primitive@2.0.0(@types/react@18.0.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/react-slot': 1.1.0(@types/react@18.0.28)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.0.28 + + '@radix-ui/react-slot@1.1.0(@types/react@18.0.28)(react@18.3.1)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.0.28)(react@18.3.1) + react: 18.3.1 + optionalDependencies: + '@types/react': 18.0.28 + + '@radix-ui/react-use-callback-ref@1.1.0(@types/react@18.0.28)(react@18.3.1)': + dependencies: + react: 18.3.1 + optionalDependencies: + '@types/react': 18.0.28 + + '@radix-ui/react-use-controllable-state@1.1.0(@types/react@18.0.28)(react@18.3.1)': + dependencies: + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.0.28)(react@18.3.1) + react: 18.3.1 + optionalDependencies: + '@types/react': 18.0.28 + + '@radix-ui/react-use-escape-keydown@1.1.0(@types/react@18.0.28)(react@18.3.1)': + dependencies: + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.0.28)(react@18.3.1) + react: 18.3.1 + optionalDependencies: + '@types/react': 18.0.28 + + '@radix-ui/react-use-layout-effect@1.1.0(@types/react@18.0.28)(react@18.3.1)': + dependencies: + react: 18.3.1 + optionalDependencies: + '@types/react': 18.0.28 + + '@readme/better-ajv-errors@1.6.0(ajv@8.16.0)': dependencies: '@babel/code-frame': 7.23.5 '@babel/runtime': 7.23.4 '@humanwhocodes/momoa': 2.0.4 - ajv: 8.13.0 + ajv: 8.16.0 chalk: 4.1.2 json-to-ast: 2.1.0 jsonpointer: 5.0.1 @@ -14277,181 +15365,186 @@ snapshots: '@apidevtools/openapi-schemas': 2.1.0 '@apidevtools/swagger-methods': 3.0.2 '@jsdevtools/ono': 7.1.3 - '@readme/better-ajv-errors': 1.6.0(ajv@8.13.0) + '@readme/better-ajv-errors': 1.6.0(ajv@8.16.0) '@readme/json-schema-ref-parser': 1.2.0 - ajv: 8.13.0 - ajv-draft-04: 1.0.0(ajv@8.13.0) + ajv: 8.16.0 + ajv-draft-04: 1.0.0(ajv@8.16.0) call-me-maybe: 1.0.2 openapi-types: 12.1.3 - '@rollup/plugin-json@6.1.0(rollup@4.17.2)': + '@rollup/plugin-json@6.1.0(rollup@4.18.0)': dependencies: - '@rollup/pluginutils': 5.1.0(rollup@4.17.2) + '@rollup/pluginutils': 5.1.0(rollup@4.18.0) optionalDependencies: - rollup: 4.17.2 + rollup: 4.18.0 - '@rollup/plugin-replace@5.0.5(rollup@4.17.2)': + '@rollup/plugin-replace@5.0.7(rollup@4.18.0)': dependencies: - '@rollup/pluginutils': 5.1.0(rollup@4.17.2) - magic-string: 0.30.7 + '@rollup/pluginutils': 5.1.0(rollup@4.18.0) + magic-string: 0.30.10 optionalDependencies: - rollup: 4.17.2 + rollup: 4.18.0 - '@rollup/pluginutils@5.1.0(rollup@4.17.2)': + '@rollup/pluginutils@5.1.0(rollup@4.18.0)': dependencies: '@types/estree': 1.0.5 estree-walker: 2.0.2 picomatch: 2.3.1 optionalDependencies: - rollup: 4.17.2 + rollup: 4.18.0 - '@rollup/rollup-android-arm-eabi@4.17.2': + '@rollup/rollup-android-arm-eabi@4.18.0': optional: true - '@rollup/rollup-android-arm64@4.17.2': + '@rollup/rollup-android-arm64@4.18.0': optional: true - '@rollup/rollup-darwin-arm64@4.17.2': + '@rollup/rollup-darwin-arm64@4.18.0': optional: true - '@rollup/rollup-darwin-x64@4.17.2': + '@rollup/rollup-darwin-x64@4.18.0': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.17.2': + '@rollup/rollup-linux-arm-gnueabihf@4.18.0': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.17.2': + '@rollup/rollup-linux-arm-musleabihf@4.18.0': optional: true - '@rollup/rollup-linux-arm64-gnu@4.17.2': + '@rollup/rollup-linux-arm64-gnu@4.18.0': optional: true - '@rollup/rollup-linux-arm64-musl@4.17.2': + '@rollup/rollup-linux-arm64-musl@4.18.0': optional: true - '@rollup/rollup-linux-powerpc64le-gnu@4.17.2': + '@rollup/rollup-linux-powerpc64le-gnu@4.18.0': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.17.2': + '@rollup/rollup-linux-riscv64-gnu@4.18.0': optional: true - '@rollup/rollup-linux-s390x-gnu@4.17.2': + '@rollup/rollup-linux-s390x-gnu@4.18.0': optional: true - '@rollup/rollup-linux-x64-gnu@4.17.2': + '@rollup/rollup-linux-x64-gnu@4.18.0': optional: true - '@rollup/rollup-linux-x64-musl@4.17.2': + '@rollup/rollup-linux-x64-musl@4.18.0': optional: true - '@rollup/rollup-win32-arm64-msvc@4.17.2': + '@rollup/rollup-win32-arm64-msvc@4.18.0': optional: true - '@rollup/rollup-win32-ia32-msvc@4.17.2': + '@rollup/rollup-win32-ia32-msvc@4.18.0': optional: true - '@rollup/rollup-win32-x64-msvc@4.17.2': + '@rollup/rollup-win32-x64-msvc@4.18.0': optional: true - '@rushstack/node-core-library@4.1.0(@types/node@20.12.7)': + '@rushstack/node-core-library@5.4.1(@types/node@20.14.9)': 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 - z-schema: 5.0.5 optionalDependencies: - '@types/node': 20.12.7 + '@types/node': 20.14.9 '@rushstack/rig-package@0.5.2': dependencies: resolve: 1.22.8 strip-json-comments: 3.1.1 - '@rushstack/terminal@0.10.1(@types/node@20.12.7)': + '@rushstack/terminal@0.13.0(@types/node@20.14.9)': dependencies: - '@rushstack/node-core-library': 4.1.0(@types/node@20.12.7) + '@rushstack/node-core-library': 5.4.1(@types/node@20.14.9) supports-color: 8.1.1 optionalDependencies: - '@types/node': 20.12.7 + '@types/node': 20.14.9 - '@rushstack/ts-command-line@4.19.2(@types/node@20.12.7)': + '@rushstack/ts-command-line@4.22.0(@types/node@20.14.9)': dependencies: - '@rushstack/terminal': 0.10.1(@types/node@20.12.7) + '@rushstack/terminal': 0.13.0(@types/node@20.14.9) '@types/argparse': 1.0.38 argparse: 1.0.10 string-argv: 0.3.1 transitivePeerDependencies: - '@types/node' - '@sentry/core@8.5.0': - dependencies: - '@sentry/types': 8.5.0 - '@sentry/utils': 8.5.0 + '@sec-ant/readable-stream@0.4.1': {} - '@sentry/node@8.5.0': + '@sentry/core@8.13.0': dependencies: - '@opentelemetry/api': 1.8.0 - '@opentelemetry/context-async-hooks': 1.24.1(@opentelemetry/api@1.8.0) - '@opentelemetry/core': 1.24.1(@opentelemetry/api@1.8.0) - '@opentelemetry/instrumentation': 0.51.1(@opentelemetry/api@1.8.0) - '@opentelemetry/instrumentation-connect': 0.36.0(@opentelemetry/api@1.8.0) - '@opentelemetry/instrumentation-express': 0.39.0(@opentelemetry/api@1.8.0) - '@opentelemetry/instrumentation-fastify': 0.36.1(@opentelemetry/api@1.8.0) - '@opentelemetry/instrumentation-graphql': 0.40.0(@opentelemetry/api@1.8.0) - '@opentelemetry/instrumentation-hapi': 0.38.0(@opentelemetry/api@1.8.0) - '@opentelemetry/instrumentation-http': 0.51.1(@opentelemetry/api@1.8.0) - '@opentelemetry/instrumentation-ioredis': 0.40.0(@opentelemetry/api@1.8.0) - '@opentelemetry/instrumentation-koa': 0.40.0(@opentelemetry/api@1.8.0) - '@opentelemetry/instrumentation-mongodb': 0.43.0(@opentelemetry/api@1.8.0) - '@opentelemetry/instrumentation-mongoose': 0.38.1(@opentelemetry/api@1.8.0) - '@opentelemetry/instrumentation-mysql': 0.38.1(@opentelemetry/api@1.8.0) - '@opentelemetry/instrumentation-mysql2': 0.38.1(@opentelemetry/api@1.8.0) - '@opentelemetry/instrumentation-nestjs-core': 0.37.1(@opentelemetry/api@1.8.0) - '@opentelemetry/instrumentation-pg': 0.41.0(@opentelemetry/api@1.8.0) - '@opentelemetry/resources': 1.24.1(@opentelemetry/api@1.8.0) - '@opentelemetry/sdk-trace-base': 1.24.1(@opentelemetry/api@1.8.0) - '@opentelemetry/semantic-conventions': 1.24.1 - '@prisma/instrumentation': 5.14.0 - '@sentry/core': 8.5.0 - '@sentry/opentelemetry': 8.5.0(@opentelemetry/api@1.8.0)(@opentelemetry/core@1.24.1(@opentelemetry/api@1.8.0))(@opentelemetry/instrumentation@0.51.1(@opentelemetry/api@1.8.0))(@opentelemetry/sdk-trace-base@1.24.1(@opentelemetry/api@1.8.0))(@opentelemetry/semantic-conventions@1.24.1) - '@sentry/types': 8.5.0 - '@sentry/utils': 8.5.0 + '@sentry/types': 8.13.0 + '@sentry/utils': 8.13.0 + + '@sentry/node@8.13.0': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/context-async-hooks': 1.25.1(@opentelemetry/api@1.9.0) + '@opentelemetry/core': 1.25.1(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.52.1(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-connect': 0.37.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-express': 0.40.1(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-fastify': 0.37.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-graphql': 0.41.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-hapi': 0.39.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-http': 0.52.1(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-ioredis': 0.41.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-koa': 0.41.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-mongodb': 0.45.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-mongoose': 0.39.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-mysql': 0.39.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-mysql2': 0.39.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-nestjs-core': 0.38.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-pg': 0.42.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation-redis-4': 0.40.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 1.25.1(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-base': 1.25.1(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.25.1 + '@prisma/instrumentation': 5.16.0 + '@sentry/core': 8.13.0 + '@sentry/opentelemetry': 8.13.0(@opentelemetry/api@1.9.0)(@opentelemetry/core@1.25.1(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.52.1(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.25.1(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.25.1) + '@sentry/types': 8.13.0 + '@sentry/utils': 8.13.0 optionalDependencies: opentelemetry-instrumentation-fetch-node: 1.2.0 transitivePeerDependencies: - supports-color - '@sentry/opentelemetry@8.5.0(@opentelemetry/api@1.8.0)(@opentelemetry/core@1.24.1(@opentelemetry/api@1.8.0))(@opentelemetry/instrumentation@0.51.1(@opentelemetry/api@1.8.0))(@opentelemetry/sdk-trace-base@1.24.1(@opentelemetry/api@1.8.0))(@opentelemetry/semantic-conventions@1.24.1)': + '@sentry/opentelemetry@8.13.0(@opentelemetry/api@1.9.0)(@opentelemetry/core@1.25.1(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.52.1(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.25.1(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.25.1)': dependencies: - '@opentelemetry/api': 1.8.0 - '@opentelemetry/core': 1.24.1(@opentelemetry/api@1.8.0) - '@opentelemetry/instrumentation': 0.51.1(@opentelemetry/api@1.8.0) - '@opentelemetry/sdk-trace-base': 1.24.1(@opentelemetry/api@1.8.0) - '@opentelemetry/semantic-conventions': 1.24.1 - '@sentry/core': 8.5.0 - '@sentry/types': 8.5.0 - '@sentry/utils': 8.5.0 + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 1.25.1(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.52.1(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-base': 1.25.1(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.25.1 + '@sentry/core': 8.13.0 + '@sentry/types': 8.13.0 + '@sentry/utils': 8.13.0 - '@sentry/profiling-node@8.5.0': + '@sentry/profiling-node@8.13.0': dependencies: - '@sentry/core': 8.5.0 - '@sentry/node': 8.5.0 - '@sentry/types': 8.5.0 - '@sentry/utils': 8.5.0 + '@sentry/core': 8.13.0 + '@sentry/node': 8.13.0 + '@sentry/types': 8.13.0 + '@sentry/utils': 8.13.0 detect-libc: 2.0.3 node-abi: 3.62.0 transitivePeerDependencies: - supports-color - '@sentry/types@8.5.0': {} + '@sentry/types@8.13.0': {} - '@sentry/utils@8.5.0': + '@sentry/utils@8.13.0': dependencies: - '@sentry/types': 8.5.0 + '@sentry/types': 8.13.0 - '@shikijs/core@1.4.0': {} + '@shikijs/core@1.10.0': {} '@sideway/address@4.1.4': dependencies: @@ -14483,7 +15576,11 @@ snapshots: '@sindresorhus/is@5.3.0': {} - '@sindresorhus/is@6.1.0': {} + '@sindresorhus/is@6.3.1': {} + + '@sindresorhus/merge-streams@2.3.0': {} + + '@sindresorhus/merge-streams@4.0.0': {} '@sinonjs/commons@2.0.0': dependencies: @@ -14509,154 +15606,172 @@ snapshots: '@sinonjs/text-encoding@0.7.2': {} - '@smithy/abort-controller@2.0.14': - dependencies: - '@smithy/types': 2.6.0 - tslib: 2.6.2 - '@smithy/abort-controller@2.2.0': dependencies: '@smithy/types': 2.12.0 tslib: 2.6.2 - '@smithy/chunked-blob-reader-native@2.0.0': + '@smithy/abort-controller@3.1.1': dependencies: - '@smithy/util-base64': 2.0.0 + '@smithy/types': 3.3.0 tslib: 2.6.2 - '@smithy/chunked-blob-reader@2.0.0': + '@smithy/chunked-blob-reader-native@3.0.0': + dependencies: + '@smithy/util-base64': 3.0.0 + tslib: 2.6.2 + + '@smithy/chunked-blob-reader@3.0.0': dependencies: tslib: 2.6.2 - '@smithy/config-resolver@2.0.9': + '@smithy/config-resolver@3.0.4': dependencies: - '@smithy/node-config-provider': 2.0.11 - '@smithy/types': 2.6.0 - '@smithy/util-config-provider': 2.0.0 - '@smithy/util-middleware': 2.0.1 + '@smithy/node-config-provider': 3.1.3 + '@smithy/types': 3.3.0 + '@smithy/util-config-provider': 3.0.0 + '@smithy/util-middleware': 3.0.3 tslib: 2.6.2 - '@smithy/credential-provider-imds@2.0.11': + '@smithy/core@2.2.4': dependencies: - '@smithy/node-config-provider': 2.0.11 - '@smithy/property-provider': 2.0.9 - '@smithy/types': 2.6.0 - '@smithy/url-parser': 2.0.8 + '@smithy/middleware-endpoint': 3.0.4 + '@smithy/middleware-retry': 3.0.7 + '@smithy/middleware-serde': 3.0.3 + '@smithy/protocol-http': 4.0.3 + '@smithy/smithy-client': 3.1.5 + '@smithy/types': 3.3.0 + '@smithy/util-middleware': 3.0.3 tslib: 2.6.2 - '@smithy/eventstream-codec@2.0.8': + '@smithy/credential-provider-imds@3.1.3': dependencies: - '@aws-crypto/crc32': 3.0.0 - '@smithy/types': 2.6.0 - '@smithy/util-hex-encoding': 2.0.0 + '@smithy/node-config-provider': 3.1.3 + '@smithy/property-provider': 3.1.3 + '@smithy/types': 3.3.0 + '@smithy/url-parser': 3.0.3 tslib: 2.6.2 - '@smithy/eventstream-serde-browser@2.0.8': + '@smithy/eventstream-codec@3.1.2': dependencies: - '@smithy/eventstream-serde-universal': 2.0.8 - '@smithy/types': 2.6.0 + '@aws-crypto/crc32': 5.2.0 + '@smithy/types': 3.3.0 + '@smithy/util-hex-encoding': 3.0.0 tslib: 2.6.2 - '@smithy/eventstream-serde-config-resolver@2.0.8': + '@smithy/eventstream-serde-browser@3.0.4': dependencies: - '@smithy/types': 2.6.0 + '@smithy/eventstream-serde-universal': 3.0.4 + '@smithy/types': 3.3.0 tslib: 2.6.2 - '@smithy/eventstream-serde-node@2.0.8': + '@smithy/eventstream-serde-config-resolver@3.0.3': dependencies: - '@smithy/eventstream-serde-universal': 2.0.8 - '@smithy/types': 2.6.0 + '@smithy/types': 3.3.0 tslib: 2.6.2 - '@smithy/eventstream-serde-universal@2.0.8': + '@smithy/eventstream-serde-node@3.0.4': dependencies: - '@smithy/eventstream-codec': 2.0.8 - '@smithy/types': 2.6.0 + '@smithy/eventstream-serde-universal': 3.0.4 + '@smithy/types': 3.3.0 tslib: 2.6.2 - '@smithy/fetch-http-handler@2.1.4': + '@smithy/eventstream-serde-universal@3.0.4': dependencies: - '@smithy/protocol-http': 3.0.10 - '@smithy/querystring-builder': 2.0.14 - '@smithy/types': 2.6.0 - '@smithy/util-base64': 2.0.0 + '@smithy/eventstream-codec': 3.1.2 + '@smithy/types': 3.3.0 tslib: 2.6.2 - '@smithy/hash-blob-browser@2.0.8': + '@smithy/fetch-http-handler@3.2.0': dependencies: - '@smithy/chunked-blob-reader': 2.0.0 - '@smithy/chunked-blob-reader-native': 2.0.0 - '@smithy/types': 2.6.0 + '@smithy/protocol-http': 4.0.3 + '@smithy/querystring-builder': 3.0.3 + '@smithy/types': 3.3.0 + '@smithy/util-base64': 3.0.0 tslib: 2.6.2 - '@smithy/hash-node@2.0.8': + '@smithy/hash-blob-browser@3.1.2': dependencies: - '@smithy/types': 2.6.0 - '@smithy/util-buffer-from': 2.0.0 - '@smithy/util-utf8': 2.0.0 + '@smithy/chunked-blob-reader': 3.0.0 + '@smithy/chunked-blob-reader-native': 3.0.0 + '@smithy/types': 3.3.0 tslib: 2.6.2 - '@smithy/hash-stream-node@2.0.8': + '@smithy/hash-node@3.0.3': dependencies: - '@smithy/types': 2.6.0 - '@smithy/util-utf8': 2.0.0 + '@smithy/types': 3.3.0 + '@smithy/util-buffer-from': 3.0.0 + '@smithy/util-utf8': 3.0.0 tslib: 2.6.2 - '@smithy/invalid-dependency@2.0.8': + '@smithy/hash-stream-node@3.1.2': dependencies: - '@smithy/types': 2.6.0 + '@smithy/types': 3.3.0 + '@smithy/util-utf8': 3.0.0 + tslib: 2.6.2 + + '@smithy/invalid-dependency@3.0.3': + dependencies: + '@smithy/types': 3.3.0 tslib: 2.6.2 '@smithy/is-array-buffer@2.0.0': dependencies: tslib: 2.6.2 - '@smithy/md5-js@2.0.8': + '@smithy/is-array-buffer@3.0.0': dependencies: - '@smithy/types': 2.6.0 - '@smithy/util-utf8': 2.0.0 tslib: 2.6.2 - '@smithy/middleware-content-length@2.0.10': + '@smithy/md5-js@3.0.3': dependencies: - '@smithy/protocol-http': 3.0.10 - '@smithy/types': 2.6.0 + '@smithy/types': 3.3.0 + '@smithy/util-utf8': 3.0.0 tslib: 2.6.2 - '@smithy/middleware-endpoint@2.0.8': + '@smithy/middleware-content-length@3.0.3': dependencies: - '@smithy/middleware-serde': 2.0.8 - '@smithy/types': 2.6.0 - '@smithy/url-parser': 2.0.8 - '@smithy/util-middleware': 2.0.1 + '@smithy/protocol-http': 4.0.3 + '@smithy/types': 3.3.0 tslib: 2.6.2 - '@smithy/middleware-retry@2.0.11': + '@smithy/middleware-endpoint@3.0.4': dependencies: - '@smithy/node-config-provider': 2.0.11 - '@smithy/protocol-http': 3.0.10 - '@smithy/service-error-classification': 2.0.1 - '@smithy/types': 2.6.0 - '@smithy/util-middleware': 2.0.1 - '@smithy/util-retry': 2.0.1 - tslib: 2.6.2 - uuid: 8.3.2 - - '@smithy/middleware-serde@2.0.8': - dependencies: - '@smithy/types': 2.6.0 + '@smithy/middleware-serde': 3.0.3 + '@smithy/node-config-provider': 3.1.3 + '@smithy/shared-ini-file-loader': 3.1.3 + '@smithy/types': 3.3.0 + '@smithy/url-parser': 3.0.3 + '@smithy/util-middleware': 3.0.3 tslib: 2.6.2 - '@smithy/middleware-stack@2.0.1': + '@smithy/middleware-retry@3.0.7': dependencies: - '@smithy/types': 2.6.0 + '@smithy/node-config-provider': 3.1.3 + '@smithy/protocol-http': 4.0.3 + '@smithy/service-error-classification': 3.0.3 + '@smithy/smithy-client': 3.1.5 + '@smithy/types': 3.3.0 + '@smithy/util-middleware': 3.0.3 + '@smithy/util-retry': 3.0.3 + tslib: 2.6.2 + uuid: 9.0.1 + + '@smithy/middleware-serde@3.0.3': + dependencies: + '@smithy/types': 3.3.0 tslib: 2.6.2 - '@smithy/node-config-provider@2.0.11': + '@smithy/middleware-stack@3.0.3': dependencies: - '@smithy/property-provider': 2.0.9 - '@smithy/shared-ini-file-loader': 2.0.10 - '@smithy/types': 2.6.0 + '@smithy/types': 3.3.0 + tslib: 2.6.2 + + '@smithy/node-config-provider@3.1.3': + dependencies: + '@smithy/property-provider': 3.1.3 + '@smithy/shared-ini-file-loader': 3.1.3 + '@smithy/types': 3.3.0 tslib: 2.6.2 '@smithy/node-http-handler@2.5.0': @@ -14667,14 +15782,17 @@ snapshots: '@smithy/types': 2.12.0 tslib: 2.6.2 - '@smithy/property-provider@2.0.9': + '@smithy/node-http-handler@3.1.1': dependencies: - '@smithy/types': 2.6.0 + '@smithy/abort-controller': 3.1.1 + '@smithy/protocol-http': 4.0.3 + '@smithy/querystring-builder': 3.0.3 + '@smithy/types': 3.3.0 tslib: 2.6.2 - '@smithy/protocol-http@3.0.10': + '@smithy/property-provider@3.1.3': dependencies: - '@smithy/types': 2.6.0 + '@smithy/types': 3.3.0 tslib: 2.6.2 '@smithy/protocol-http@3.3.0': @@ -14682,10 +15800,9 @@ snapshots: '@smithy/types': 2.12.0 tslib: 2.6.2 - '@smithy/querystring-builder@2.0.14': + '@smithy/protocol-http@4.0.3': dependencies: - '@smithy/types': 2.6.0 - '@smithy/util-uri-escape': 2.0.0 + '@smithy/types': 3.3.0 tslib: 2.6.2 '@smithy/querystring-builder@2.2.0': @@ -14694,62 +15811,70 @@ snapshots: '@smithy/util-uri-escape': 2.2.0 tslib: 2.6.2 - '@smithy/querystring-parser@2.0.8': + '@smithy/querystring-builder@3.0.3': dependencies: - '@smithy/types': 2.6.0 + '@smithy/types': 3.3.0 + '@smithy/util-uri-escape': 3.0.0 tslib: 2.6.2 - '@smithy/service-error-classification@2.0.1': + '@smithy/querystring-parser@3.0.3': dependencies: - '@smithy/types': 2.6.0 - - '@smithy/shared-ini-file-loader@2.0.10': - dependencies: - '@smithy/types': 2.6.0 + '@smithy/types': 3.3.0 tslib: 2.6.2 - '@smithy/signature-v4@2.0.5': + '@smithy/service-error-classification@3.0.3': dependencies: - '@smithy/eventstream-codec': 2.0.8 - '@smithy/is-array-buffer': 2.0.0 - '@smithy/types': 2.6.0 - '@smithy/util-hex-encoding': 2.0.0 - '@smithy/util-middleware': 2.0.1 - '@smithy/util-uri-escape': 2.0.0 - '@smithy/util-utf8': 2.0.0 + '@smithy/types': 3.3.0 + + '@smithy/shared-ini-file-loader@3.1.3': + dependencies: + '@smithy/types': 3.3.0 tslib: 2.6.2 - '@smithy/smithy-client@2.1.5': + '@smithy/signature-v4@3.1.2': dependencies: - '@smithy/middleware-stack': 2.0.1 - '@smithy/types': 2.6.0 - '@smithy/util-stream': 2.0.11 + '@smithy/is-array-buffer': 3.0.0 + '@smithy/types': 3.3.0 + '@smithy/util-hex-encoding': 3.0.0 + '@smithy/util-middleware': 3.0.3 + '@smithy/util-uri-escape': 3.0.0 + '@smithy/util-utf8': 3.0.0 + tslib: 2.6.2 + + '@smithy/smithy-client@3.1.5': + dependencies: + '@smithy/middleware-endpoint': 3.0.4 + '@smithy/middleware-stack': 3.0.3 + '@smithy/protocol-http': 4.0.3 + '@smithy/types': 3.3.0 + '@smithy/util-stream': 3.0.5 tslib: 2.6.2 '@smithy/types@2.12.0': dependencies: tslib: 2.6.2 - '@smithy/types@2.6.0': + '@smithy/types@3.3.0': dependencies: tslib: 2.6.2 - '@smithy/url-parser@2.0.8': + '@smithy/url-parser@3.0.3': dependencies: - '@smithy/querystring-parser': 2.0.8 - '@smithy/types': 2.6.0 + '@smithy/querystring-parser': 3.0.3 + '@smithy/types': 3.3.0 tslib: 2.6.2 - '@smithy/util-base64@2.0.0': + '@smithy/util-base64@3.0.0': dependencies: - '@smithy/util-buffer-from': 2.0.0 + '@smithy/util-buffer-from': 3.0.0 + '@smithy/util-utf8': 3.0.0 tslib: 2.6.2 - '@smithy/util-body-length-browser@2.0.0': + '@smithy/util-body-length-browser@3.0.0': dependencies: tslib: 2.6.2 - '@smithy/util-body-length-node@2.1.0': + '@smithy/util-body-length-node@3.0.0': dependencies: tslib: 2.6.2 @@ -14758,117 +15883,136 @@ snapshots: '@smithy/is-array-buffer': 2.0.0 tslib: 2.6.2 - '@smithy/util-config-provider@2.0.0': + '@smithy/util-buffer-from@3.0.0': + dependencies: + '@smithy/is-array-buffer': 3.0.0 + tslib: 2.6.2 + + '@smithy/util-config-provider@3.0.0': dependencies: tslib: 2.6.2 - '@smithy/util-defaults-mode-browser@2.0.9': + '@smithy/util-defaults-mode-browser@3.0.7': dependencies: - '@smithy/property-provider': 2.0.9 - '@smithy/smithy-client': 2.1.5 - '@smithy/types': 2.6.0 + '@smithy/property-provider': 3.1.3 + '@smithy/smithy-client': 3.1.5 + '@smithy/types': 3.3.0 bowser: 2.11.0 tslib: 2.6.2 - '@smithy/util-defaults-mode-node@2.0.11': + '@smithy/util-defaults-mode-node@3.0.7': dependencies: - '@smithy/config-resolver': 2.0.9 - '@smithy/credential-provider-imds': 2.0.11 - '@smithy/node-config-provider': 2.0.11 - '@smithy/property-provider': 2.0.9 - '@smithy/smithy-client': 2.1.5 - '@smithy/types': 2.6.0 + '@smithy/config-resolver': 3.0.4 + '@smithy/credential-provider-imds': 3.1.3 + '@smithy/node-config-provider': 3.1.3 + '@smithy/property-provider': 3.1.3 + '@smithy/smithy-client': 3.1.5 + '@smithy/types': 3.3.0 tslib: 2.6.2 - '@smithy/util-hex-encoding@2.0.0': + '@smithy/util-endpoints@2.0.4': + dependencies: + '@smithy/node-config-provider': 3.1.3 + '@smithy/types': 3.3.0 + tslib: 2.6.2 + + '@smithy/util-hex-encoding@3.0.0': dependencies: tslib: 2.6.2 - '@smithy/util-middleware@2.0.1': + '@smithy/util-middleware@3.0.3': dependencies: - '@smithy/types': 2.6.0 + '@smithy/types': 3.3.0 tslib: 2.6.2 - '@smithy/util-retry@2.0.1': + '@smithy/util-retry@3.0.3': dependencies: - '@smithy/service-error-classification': 2.0.1 - '@smithy/types': 2.6.0 + '@smithy/service-error-classification': 3.0.3 + '@smithy/types': 3.3.0 tslib: 2.6.2 - '@smithy/util-stream@2.0.11': - dependencies: - '@smithy/fetch-http-handler': 2.1.4 - '@smithy/node-http-handler': 2.5.0 - '@smithy/types': 2.6.0 - '@smithy/util-base64': 2.0.0 - '@smithy/util-buffer-from': 2.0.0 - '@smithy/util-hex-encoding': 2.0.0 - '@smithy/util-utf8': 2.0.0 - tslib: 2.6.2 - - '@smithy/util-uri-escape@2.0.0': + '@smithy/util-stream@3.0.5': dependencies: + '@smithy/fetch-http-handler': 3.2.0 + '@smithy/node-http-handler': 3.1.1 + '@smithy/types': 3.3.0 + '@smithy/util-base64': 3.0.0 + '@smithy/util-buffer-from': 3.0.0 + '@smithy/util-hex-encoding': 3.0.0 + '@smithy/util-utf8': 3.0.0 tslib: 2.6.2 '@smithy/util-uri-escape@2.2.0': dependencies: tslib: 2.6.2 + '@smithy/util-uri-escape@3.0.0': + dependencies: + tslib: 2.6.2 + '@smithy/util-utf8@2.0.0': dependencies: '@smithy/util-buffer-from': 2.0.0 tslib: 2.6.2 - '@smithy/util-waiter@2.0.8': + '@smithy/util-utf8@3.0.0': dependencies: - '@smithy/abort-controller': 2.0.14 - '@smithy/types': 2.6.0 + '@smithy/util-buffer-from': 3.0.0 + tslib: 2.6.2 + + '@smithy/util-waiter@3.1.2': + dependencies: + '@smithy/abort-controller': 3.1.1 + '@smithy/types': 3.3.0 tslib: 2.6.2 '@sqltools/formatter@1.2.5': {} - '@storybook/addon-actions@8.0.9': + '@storybook/addon-actions@8.1.11': dependencies: - '@storybook/core-events': 8.0.9 + '@storybook/core-events': 8.1.11 '@storybook/global': 5.0.0 '@types/uuid': 9.0.8 dequal: 2.0.3 polished: 4.2.2 uuid: 9.0.1 - '@storybook/addon-backgrounds@8.0.9': + '@storybook/addon-backgrounds@8.1.11': dependencies: '@storybook/global': 5.0.0 memoizerific: 1.11.3 ts-dedent: 2.2.0 - '@storybook/addon-controls@8.0.9(@types/react@18.0.28)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@storybook/addon-controls@8.1.11(@types/react@18.0.28)(encoding@0.1.13)(prettier@3.3.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@storybook/blocks': 8.0.9(@types/react@18.0.28)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@storybook/blocks': 8.1.11(@types/react@18.0.28)(encoding@0.1.13)(prettier@3.3.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + dequal: 2.0.3 lodash: 4.17.21 ts-dedent: 2.2.0 transitivePeerDependencies: - '@types/react' + - '@types/react-dom' - encoding + - prettier - react - react-dom - supports-color - '@storybook/addon-docs@8.0.9(encoding@0.1.13)': + '@storybook/addon-docs@8.1.11(encoding@0.1.13)(prettier@3.3.2)': dependencies: - '@babel/core': 7.24.0 + '@babel/core': 7.24.7 '@mdx-js/react': 3.0.1(@types/react@18.0.28)(react@18.3.1) - '@storybook/blocks': 8.0.9(@types/react@18.0.28)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@storybook/client-logger': 8.0.9 - '@storybook/components': 8.0.9(@types/react@18.0.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@storybook/csf-plugin': 8.0.9 - '@storybook/csf-tools': 8.0.9 + '@storybook/blocks': 8.1.11(@types/react@18.0.28)(encoding@0.1.13)(prettier@3.3.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@storybook/client-logger': 8.1.11 + '@storybook/components': 8.1.11(@types/react@18.0.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@storybook/csf-plugin': 8.1.11 + '@storybook/csf-tools': 8.1.11 '@storybook/global': 5.0.0 - '@storybook/node-logger': 8.0.9 - '@storybook/preview-api': 8.0.9 - '@storybook/react-dom-shim': 8.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@storybook/theming': 8.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@storybook/types': 8.0.9 + '@storybook/node-logger': 8.1.11 + '@storybook/preview-api': 8.1.11 + '@storybook/react-dom-shim': 8.1.11(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@storybook/theming': 8.1.11(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@storybook/types': 8.1.11 '@types/react': 18.0.28 fs-extra: 11.1.1 react: 18.3.1 @@ -14877,42 +16021,46 @@ snapshots: rehype-slug: 6.0.0 ts-dedent: 2.2.0 transitivePeerDependencies: + - '@types/react-dom' - encoding + - prettier - supports-color - '@storybook/addon-essentials@8.0.9(@types/react@18.0.28)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@storybook/addon-essentials@8.1.11(@types/react@18.0.28)(encoding@0.1.13)(prettier@3.3.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@storybook/addon-actions': 8.0.9 - '@storybook/addon-backgrounds': 8.0.9 - '@storybook/addon-controls': 8.0.9(@types/react@18.0.28)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@storybook/addon-docs': 8.0.9(encoding@0.1.13) - '@storybook/addon-highlight': 8.0.9 - '@storybook/addon-measure': 8.0.9 - '@storybook/addon-outline': 8.0.9 - '@storybook/addon-toolbars': 8.0.9 - '@storybook/addon-viewport': 8.0.9 - '@storybook/core-common': 8.0.9(encoding@0.1.13) - '@storybook/manager-api': 8.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@storybook/node-logger': 8.0.9 - '@storybook/preview-api': 8.0.9 + '@storybook/addon-actions': 8.1.11 + '@storybook/addon-backgrounds': 8.1.11 + '@storybook/addon-controls': 8.1.11(@types/react@18.0.28)(encoding@0.1.13)(prettier@3.3.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@storybook/addon-docs': 8.1.11(encoding@0.1.13)(prettier@3.3.2) + '@storybook/addon-highlight': 8.1.11 + '@storybook/addon-measure': 8.1.11 + '@storybook/addon-outline': 8.1.11 + '@storybook/addon-toolbars': 8.1.11 + '@storybook/addon-viewport': 8.1.11 + '@storybook/core-common': 8.1.11(encoding@0.1.13)(prettier@3.3.2) + '@storybook/manager-api': 8.1.11(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@storybook/node-logger': 8.1.11 + '@storybook/preview-api': 8.1.11 ts-dedent: 2.2.0 transitivePeerDependencies: - '@types/react' + - '@types/react-dom' - encoding + - prettier - react - react-dom - supports-color - '@storybook/addon-highlight@8.0.9': + '@storybook/addon-highlight@8.1.11': dependencies: '@storybook/global': 5.0.0 - '@storybook/addon-interactions@8.0.9(@jest/globals@29.7.0)(@types/jest@29.5.12)(jest@29.7.0(@types/node@20.12.7))(vitest@0.34.6(happy-dom@10.0.3)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3))': + '@storybook/addon-interactions@8.1.11(@jest/globals@29.7.0)(@types/jest@29.5.12)(jest@29.7.0(@types/node@20.14.9))(vitest@1.6.0(@types/node@20.14.9)(happy-dom@10.0.3)(jsdom@24.1.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))(sass@1.77.6)(terser@5.31.2))': dependencies: '@storybook/global': 5.0.0 - '@storybook/instrumenter': 8.0.9 - '@storybook/test': 8.0.9(@jest/globals@29.7.0)(@types/jest@29.5.12)(jest@29.7.0(@types/node@20.12.7))(vitest@0.34.6(happy-dom@10.0.3)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3)) - '@storybook/types': 8.0.9 + '@storybook/instrumenter': 8.1.11 + '@storybook/test': 8.1.11(@jest/globals@29.7.0)(@types/jest@29.5.12)(jest@29.7.0(@types/node@20.14.9))(vitest@1.6.0(@types/node@20.14.9)(happy-dom@10.0.3)(jsdom@24.1.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))(sass@1.77.6)(terser@5.31.2)) + '@storybook/types': 8.1.11 polished: 4.2.2 ts-dedent: 2.2.0 transitivePeerDependencies: @@ -14922,58 +16070,58 @@ snapshots: - jest - vitest - '@storybook/addon-links@8.0.9(react@18.3.1)': + '@storybook/addon-links@8.1.11(react@18.3.1)': dependencies: - '@storybook/csf': 0.1.6 + '@storybook/csf': 0.1.9 '@storybook/global': 5.0.0 ts-dedent: 2.2.0 optionalDependencies: react: 18.3.1 - '@storybook/addon-mdx-gfm@8.0.9': + '@storybook/addon-mdx-gfm@8.1.11': dependencies: - '@storybook/node-logger': 8.0.9 + '@storybook/node-logger': 8.1.11 remark-gfm: 4.0.0 ts-dedent: 2.2.0 transitivePeerDependencies: - supports-color - '@storybook/addon-measure@8.0.9': + '@storybook/addon-measure@8.1.11': dependencies: '@storybook/global': 5.0.0 - tiny-invariant: 1.3.1 + tiny-invariant: 1.3.3 - '@storybook/addon-outline@8.0.9': + '@storybook/addon-outline@8.1.11': dependencies: '@storybook/global': 5.0.0 ts-dedent: 2.2.0 - '@storybook/addon-storysource@8.0.9': + '@storybook/addon-storysource@8.1.11': dependencies: - '@storybook/source-loader': 8.0.9 + '@storybook/source-loader': 8.1.11 estraverse: 5.3.0 - tiny-invariant: 1.3.1 + tiny-invariant: 1.3.3 - '@storybook/addon-toolbars@8.0.9': {} + '@storybook/addon-toolbars@8.1.11': {} - '@storybook/addon-viewport@8.0.9': + '@storybook/addon-viewport@8.1.11': dependencies: memoizerific: 1.11.3 - '@storybook/blocks@8.0.9(@types/react@18.0.28)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@storybook/blocks@8.1.11(@types/react@18.0.28)(encoding@0.1.13)(prettier@3.3.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@storybook/channels': 8.0.9 - '@storybook/client-logger': 8.0.9 - '@storybook/components': 8.0.9(@types/react@18.0.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@storybook/core-events': 8.0.9 - '@storybook/csf': 0.1.6 - '@storybook/docs-tools': 8.0.9(encoding@0.1.13) + '@storybook/channels': 8.1.11 + '@storybook/client-logger': 8.1.11 + '@storybook/components': 8.1.11(@types/react@18.0.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@storybook/core-events': 8.1.11 + '@storybook/csf': 0.1.9 + '@storybook/docs-tools': 8.1.11(encoding@0.1.13)(prettier@3.3.2) '@storybook/global': 5.0.0 '@storybook/icons': 1.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@storybook/manager-api': 8.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@storybook/preview-api': 8.0.9 - '@storybook/theming': 8.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@storybook/types': 8.0.9 + '@storybook/manager-api': 8.1.11(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@storybook/preview-api': 8.1.11 + '@storybook/theming': 8.1.11(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@storybook/types': 8.1.11 '@types/lodash': 4.14.191 color-convert: 2.0.1 dequal: 2.0.3 @@ -14991,20 +16139,22 @@ snapshots: react-dom: 18.3.1(react@18.3.1) transitivePeerDependencies: - '@types/react' + - '@types/react-dom' - encoding + - prettier - supports-color - '@storybook/builder-manager@8.0.9(encoding@0.1.13)': + '@storybook/builder-manager@8.1.11(encoding@0.1.13)(prettier@3.3.2)': dependencies: '@fal-works/esbuild-plugin-global-externals': 2.1.2 - '@storybook/core-common': 8.0.9(encoding@0.1.13) - '@storybook/manager': 8.0.9 - '@storybook/node-logger': 8.0.9 + '@storybook/core-common': 8.1.11(encoding@0.1.13)(prettier@3.3.2) + '@storybook/manager': 8.1.11 + '@storybook/node-logger': 8.1.11 '@types/ejs': 3.1.2 - '@yarnpkg/esbuild-plugin-pnp': 3.0.0-rc.15(esbuild@0.20.2) + '@yarnpkg/esbuild-plugin-pnp': 3.0.0-rc.15(esbuild@0.19.11) browser-assert: 1.2.1 - ejs: 3.1.9 - esbuild: 0.20.2 + ejs: 3.1.10 + esbuild: 0.19.11 esbuild-plugin-alias: 0.2.1 express: 4.19.2 fs-extra: 11.1.1 @@ -15012,55 +16162,57 @@ snapshots: util: 0.12.5 transitivePeerDependencies: - encoding + - prettier - supports-color - '@storybook/builder-vite@8.0.9(encoding@0.1.13)(typescript@5.4.5)(vite@5.2.11(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3))': + '@storybook/builder-vite@8.1.11(encoding@0.1.13)(prettier@3.3.2)(typescript@5.5.3)(vite@5.3.2(@types/node@20.14.9)(sass@1.77.6)(terser@5.31.2))': dependencies: - '@storybook/channels': 8.0.9 - '@storybook/client-logger': 8.0.9 - '@storybook/core-common': 8.0.9(encoding@0.1.13) - '@storybook/core-events': 8.0.9 - '@storybook/csf-plugin': 8.0.9 - '@storybook/node-logger': 8.0.9 - '@storybook/preview': 8.0.9 - '@storybook/preview-api': 8.0.9 - '@storybook/types': 8.0.9 + '@storybook/channels': 8.1.11 + '@storybook/client-logger': 8.1.11 + '@storybook/core-common': 8.1.11(encoding@0.1.13)(prettier@3.3.2) + '@storybook/core-events': 8.1.11 + '@storybook/csf-plugin': 8.1.11 + '@storybook/node-logger': 8.1.11 + '@storybook/preview': 8.1.11 + '@storybook/preview-api': 8.1.11 + '@storybook/types': 8.1.11 '@types/find-cache-dir': 3.2.1 browser-assert: 1.2.1 - es-module-lexer: 0.9.3 - express: 4.18.2 + es-module-lexer: 1.5.4 + express: 4.19.2 find-cache-dir: 3.3.2 fs-extra: 11.1.1 - magic-string: 0.30.7 + magic-string: 0.30.10 ts-dedent: 2.2.0 - vite: 5.2.11(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3) + vite: 5.3.2(@types/node@20.14.9)(sass@1.77.6)(terser@5.31.2) optionalDependencies: - typescript: 5.4.5 + typescript: 5.5.3 transitivePeerDependencies: - encoding + - prettier - supports-color - '@storybook/channels@8.0.9': + '@storybook/channels@8.1.11': dependencies: - '@storybook/client-logger': 8.0.9 - '@storybook/core-events': 8.0.9 + '@storybook/client-logger': 8.1.11 + '@storybook/core-events': 8.1.11 '@storybook/global': 5.0.0 telejson: 7.2.0 - tiny-invariant: 1.3.1 + tiny-invariant: 1.3.3 - '@storybook/cli@8.0.9(@babel/preset-env@7.23.5(@babel/core@7.24.0))(bufferutil@4.0.7)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(utf-8-validate@6.0.3)': + '@storybook/cli@8.1.11(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(utf-8-validate@6.0.4)': dependencies: - '@babel/core': 7.24.0 - '@babel/types': 7.24.0 + '@babel/core': 7.24.7 + '@babel/types': 7.24.7 '@ndelangen/get-tarball': 3.0.7 - '@storybook/codemod': 8.0.9 - '@storybook/core-common': 8.0.9(encoding@0.1.13) - '@storybook/core-events': 8.0.9 - '@storybook/core-server': 8.0.9(bufferutil@4.0.7)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(utf-8-validate@6.0.3) - '@storybook/csf-tools': 8.0.9 - '@storybook/node-logger': 8.0.9 - '@storybook/telemetry': 8.0.9(encoding@0.1.13) - '@storybook/types': 8.0.9 + '@storybook/codemod': 8.1.11 + '@storybook/core-common': 8.1.11(encoding@0.1.13)(prettier@3.3.2) + '@storybook/core-events': 8.1.11 + '@storybook/core-server': 8.1.11(bufferutil@4.0.8)(encoding@0.1.13)(prettier@3.3.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(utf-8-validate@6.0.4) + '@storybook/csf-tools': 8.1.11 + '@storybook/node-logger': 8.1.11 + '@storybook/telemetry': 8.1.11(encoding@0.1.13)(prettier@3.3.2) + '@storybook/types': 8.1.11 '@types/semver': 7.5.8 '@yarnpkg/fslib': 2.10.3 '@yarnpkg/libzip': 2.3.0 @@ -15074,17 +16226,17 @@ snapshots: fs-extra: 11.1.1 get-npm-tarball-url: 2.0.3 giget: 1.1.2 - globby: 11.1.0 - jscodeshift: 0.15.1(@babel/preset-env@7.23.5(@babel/core@7.24.0)) + globby: 14.0.1 + jscodeshift: 0.15.1(@babel/preset-env@7.24.7(@babel/core@7.24.7)) leven: 3.1.0 ora: 5.4.1 - prettier: 3.2.5 + prettier: 3.3.2 prompts: 2.4.2 read-pkg-up: 7.0.1 semver: 7.6.0 strip-json-comments: 3.1.1 - tempy: 1.0.1 - tiny-invariant: 1.3.1 + tempy: 3.1.0 + tiny-invariant: 1.3.3 ts-dedent: 2.2.0 transitivePeerDependencies: - '@babel/preset-env' @@ -15095,104 +16247,112 @@ snapshots: - supports-color - utf-8-validate - '@storybook/client-logger@8.0.9': + '@storybook/client-logger@8.1.11': dependencies: '@storybook/global': 5.0.0 - '@storybook/codemod@8.0.9': + '@storybook/codemod@8.1.11': dependencies: - '@babel/core': 7.24.0 - '@babel/preset-env': 7.23.5(@babel/core@7.24.0) - '@babel/types': 7.24.0 - '@storybook/csf': 0.1.6 - '@storybook/csf-tools': 8.0.9 - '@storybook/node-logger': 8.0.9 - '@storybook/types': 8.0.9 + '@babel/core': 7.24.7 + '@babel/preset-env': 7.24.7(@babel/core@7.24.7) + '@babel/types': 7.24.7 + '@storybook/csf': 0.1.9 + '@storybook/csf-tools': 8.1.11 + '@storybook/node-logger': 8.1.11 + '@storybook/types': 8.1.11 '@types/cross-spawn': 6.0.2 cross-spawn: 7.0.3 - globby: 11.1.0 - jscodeshift: 0.15.1(@babel/preset-env@7.23.5(@babel/core@7.24.0)) + globby: 14.0.1 + jscodeshift: 0.15.1(@babel/preset-env@7.24.7(@babel/core@7.24.7)) lodash: 4.17.21 - prettier: 3.2.5 + prettier: 3.3.2 recast: 0.23.6 - tiny-invariant: 1.3.1 + tiny-invariant: 1.3.3 transitivePeerDependencies: - supports-color - '@storybook/components@8.0.9(@types/react@18.0.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@storybook/components@8.1.11(@types/react@18.0.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@radix-ui/react-slot': 1.0.2(@types/react@18.0.28)(react@18.3.1) - '@storybook/client-logger': 8.0.9 - '@storybook/csf': 0.1.6 + '@radix-ui/react-dialog': 1.1.1(@types/react@18.0.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-slot': 1.1.0(@types/react@18.0.28)(react@18.3.1) + '@storybook/client-logger': 8.1.11 + '@storybook/csf': 0.1.9 '@storybook/global': 5.0.0 '@storybook/icons': 1.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@storybook/theming': 8.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@storybook/types': 8.0.9 + '@storybook/theming': 8.1.11(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@storybook/types': 8.1.11 memoizerific: 1.11.3 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) util-deprecate: 1.0.2 transitivePeerDependencies: - '@types/react' + - '@types/react-dom' - '@storybook/core-common@8.0.9(encoding@0.1.13)': + '@storybook/core-common@8.1.11(encoding@0.1.13)(prettier@3.3.2)': dependencies: - '@storybook/core-events': 8.0.9 - '@storybook/csf-tools': 8.0.9 - '@storybook/node-logger': 8.0.9 - '@storybook/types': 8.0.9 + '@storybook/core-events': 8.1.11 + '@storybook/csf-tools': 8.1.11 + '@storybook/node-logger': 8.1.11 + '@storybook/types': 8.1.11 '@yarnpkg/fslib': 2.10.3 '@yarnpkg/libzip': 2.3.0 chalk: 4.1.2 cross-spawn: 7.0.3 - esbuild: 0.20.2 - esbuild-register: 3.5.0(esbuild@0.20.2) + esbuild: 0.19.11 + esbuild-register: 3.5.0(esbuild@0.19.11) execa: 5.1.1 file-system-cache: 2.3.0 find-cache-dir: 3.3.2 find-up: 5.0.0 fs-extra: 11.1.1 - glob: 10.3.12 + glob: 10.4.2 handlebars: 4.7.7 lazy-universal-dotenv: 4.0.0 node-fetch: 2.7.0(encoding@0.1.13) picomatch: 2.3.1 pkg-dir: 5.0.0 + prettier-fallback: prettier@3.3.2 pretty-hrtime: 1.0.3 resolve-from: 5.0.0 semver: 7.6.0 - tempy: 1.0.1 - tiny-invariant: 1.3.1 + tempy: 3.1.0 + tiny-invariant: 1.3.3 ts-dedent: 2.2.0 util: 0.12.5 + optionalDependencies: + prettier: 3.3.2 transitivePeerDependencies: - encoding - supports-color - '@storybook/core-events@8.0.9': + '@storybook/core-events@8.1.11': dependencies: + '@storybook/csf': 0.1.9 ts-dedent: 2.2.0 - '@storybook/core-server@8.0.9(bufferutil@4.0.7)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(utf-8-validate@6.0.3)': + '@storybook/core-server@8.1.11(bufferutil@4.0.8)(encoding@0.1.13)(prettier@3.3.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(utf-8-validate@6.0.4)': dependencies: '@aw-web-design/x-default-browser': 1.4.126 - '@babel/core': 7.24.0 + '@babel/core': 7.24.7 + '@babel/parser': 7.24.7 '@discoveryjs/json-ext': 0.5.7 - '@storybook/builder-manager': 8.0.9(encoding@0.1.13) - '@storybook/channels': 8.0.9 - '@storybook/core-common': 8.0.9(encoding@0.1.13) - '@storybook/core-events': 8.0.9 - '@storybook/csf': 0.1.6 - '@storybook/csf-tools': 8.0.9 - '@storybook/docs-mdx': 3.0.0 + '@storybook/builder-manager': 8.1.11(encoding@0.1.13)(prettier@3.3.2) + '@storybook/channels': 8.1.11 + '@storybook/core-common': 8.1.11(encoding@0.1.13)(prettier@3.3.2) + '@storybook/core-events': 8.1.11 + '@storybook/csf': 0.1.9 + '@storybook/csf-tools': 8.1.11 + '@storybook/docs-mdx': 3.1.0-next.0 '@storybook/global': 5.0.0 - '@storybook/manager': 8.0.9 - '@storybook/manager-api': 8.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@storybook/node-logger': 8.0.9 - '@storybook/preview-api': 8.0.9 - '@storybook/telemetry': 8.0.9(encoding@0.1.13) - '@storybook/types': 8.0.9 + '@storybook/manager': 8.1.11 + '@storybook/manager-api': 8.1.11(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@storybook/node-logger': 8.1.11 + '@storybook/preview-api': 8.1.11 + '@storybook/telemetry': 8.1.11(encoding@0.1.13)(prettier@3.3.2) + '@storybook/types': 8.1.11 '@types/detect-port': 1.3.2 + '@types/diff': 5.2.1 '@types/node': 18.17.15 '@types/pretty-hrtime': 1.0.1 '@types/semver': 7.5.8 @@ -15201,10 +16361,10 @@ snapshots: cli-table3: 0.6.3 compression: 1.7.4 detect-port: 1.5.1 - express: 4.18.2 + diff: 5.2.0 + express: 4.19.2 fs-extra: 11.1.1 - globby: 11.1.0 - ip: 2.0.1 + globby: 14.0.1 lodash: 4.17.21 open: 8.4.2 pretty-hrtime: 1.0.3 @@ -15212,59 +16372,61 @@ snapshots: read-pkg-up: 7.0.1 semver: 7.6.0 telejson: 7.2.0 - tiny-invariant: 1.3.1 + tiny-invariant: 1.3.3 ts-dedent: 2.2.0 util: 0.12.5 util-deprecate: 1.0.2 watchpack: 2.4.0 - ws: 8.17.0(bufferutil@4.0.7)(utf-8-validate@6.0.3) + ws: 8.17.1(bufferutil@4.0.8)(utf-8-validate@6.0.4) transitivePeerDependencies: - bufferutil - encoding + - prettier - react - react-dom - supports-color - utf-8-validate - '@storybook/csf-plugin@8.0.9': + '@storybook/csf-plugin@8.1.11': dependencies: - '@storybook/csf-tools': 8.0.9 + '@storybook/csf-tools': 8.1.11 unplugin: 1.4.0 transitivePeerDependencies: - supports-color - '@storybook/csf-tools@8.0.9': + '@storybook/csf-tools@8.1.11': dependencies: - '@babel/generator': 7.23.6 - '@babel/parser': 7.24.0 - '@babel/traverse': 7.24.0 - '@babel/types': 7.24.0 - '@storybook/csf': 0.1.6 - '@storybook/types': 8.0.9 + '@babel/generator': 7.24.7 + '@babel/parser': 7.24.7 + '@babel/traverse': 7.24.7 + '@babel/types': 7.24.7 + '@storybook/csf': 0.1.9 + '@storybook/types': 8.1.11 fs-extra: 11.1.1 recast: 0.23.6 ts-dedent: 2.2.0 transitivePeerDependencies: - supports-color - '@storybook/csf@0.1.6': + '@storybook/csf@0.1.9': dependencies: type-fest: 2.19.0 - '@storybook/docs-mdx@3.0.0': {} + '@storybook/docs-mdx@3.1.0-next.0': {} - '@storybook/docs-tools@8.0.9(encoding@0.1.13)': + '@storybook/docs-tools@8.1.11(encoding@0.1.13)(prettier@3.3.2)': dependencies: - '@storybook/core-common': 8.0.9(encoding@0.1.13) - '@storybook/core-events': 8.0.9 - '@storybook/preview-api': 8.0.9 - '@storybook/types': 8.0.9 + '@storybook/core-common': 8.1.11(encoding@0.1.13)(prettier@3.3.2) + '@storybook/core-events': 8.1.11 + '@storybook/preview-api': 8.1.11 + '@storybook/types': 8.1.11 '@types/doctrine': 0.0.3 assert: 2.1.0 doctrine: 3.0.0 lodash: 4.17.21 transitivePeerDependencies: - encoding + - prettier - supports-color '@storybook/global@5.0.0': {} @@ -15274,27 +16436,27 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - '@storybook/instrumenter@8.0.9': + '@storybook/instrumenter@8.1.11': dependencies: - '@storybook/channels': 8.0.9 - '@storybook/client-logger': 8.0.9 - '@storybook/core-events': 8.0.9 + '@storybook/channels': 8.1.11 + '@storybook/client-logger': 8.1.11 + '@storybook/core-events': 8.1.11 '@storybook/global': 5.0.0 - '@storybook/preview-api': 8.0.9 + '@storybook/preview-api': 8.1.11 '@vitest/utils': 1.6.0 util: 0.12.5 - '@storybook/manager-api@8.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@storybook/manager-api@8.1.11(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@storybook/channels': 8.0.9 - '@storybook/client-logger': 8.0.9 - '@storybook/core-events': 8.0.9 - '@storybook/csf': 0.1.6 + '@storybook/channels': 8.1.11 + '@storybook/client-logger': 8.1.11 + '@storybook/core-events': 8.1.11 + '@storybook/csf': 0.1.9 '@storybook/global': 5.0.0 '@storybook/icons': 1.2.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@storybook/router': 8.0.9 - '@storybook/theming': 8.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@storybook/types': 8.0.9 + '@storybook/router': 8.1.11 + '@storybook/theming': 8.1.11(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@storybook/types': 8.1.11 dequal: 2.0.3 lodash: 4.17.21 memoizerific: 1.11.3 @@ -15305,65 +16467,67 @@ snapshots: - react - react-dom - '@storybook/manager@8.0.9': {} + '@storybook/manager@8.1.11': {} - '@storybook/node-logger@8.0.9': {} + '@storybook/node-logger@8.1.11': {} - '@storybook/preview-api@8.0.9': + '@storybook/preview-api@8.1.11': dependencies: - '@storybook/channels': 8.0.9 - '@storybook/client-logger': 8.0.9 - '@storybook/core-events': 8.0.9 - '@storybook/csf': 0.1.6 + '@storybook/channels': 8.1.11 + '@storybook/client-logger': 8.1.11 + '@storybook/core-events': 8.1.11 + '@storybook/csf': 0.1.9 '@storybook/global': 5.0.0 - '@storybook/types': 8.0.9 + '@storybook/types': 8.1.11 '@types/qs': 6.9.7 dequal: 2.0.3 lodash: 4.17.21 memoizerific: 1.11.3 qs: 6.11.1 - tiny-invariant: 1.3.1 + tiny-invariant: 1.3.3 ts-dedent: 2.2.0 util-deprecate: 1.0.2 - '@storybook/preview@8.0.9': {} + '@storybook/preview@8.1.11': {} - '@storybook/react-dom-shim@8.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@storybook/react-dom-shim@8.1.11(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - '@storybook/react-vite@8.0.9(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@4.17.2)(typescript@5.4.5)(vite@5.2.11(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3))': + '@storybook/react-vite@8.1.11(encoding@0.1.13)(prettier@3.3.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@4.18.0)(typescript@5.5.3)(vite@5.3.2(@types/node@20.14.9)(sass@1.77.6)(terser@5.31.2))': dependencies: - '@joshwooding/vite-plugin-react-docgen-typescript': 0.3.0(typescript@5.4.5)(vite@5.2.11(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3)) - '@rollup/pluginutils': 5.1.0(rollup@4.17.2) - '@storybook/builder-vite': 8.0.9(encoding@0.1.13)(typescript@5.4.5)(vite@5.2.11(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3)) - '@storybook/node-logger': 8.0.9 - '@storybook/react': 8.0.9(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5) + '@joshwooding/vite-plugin-react-docgen-typescript': 0.3.1(typescript@5.5.3)(vite@5.3.2(@types/node@20.14.9)(sass@1.77.6)(terser@5.31.2)) + '@rollup/pluginutils': 5.1.0(rollup@4.18.0) + '@storybook/builder-vite': 8.1.11(encoding@0.1.13)(prettier@3.3.2)(typescript@5.5.3)(vite@5.3.2(@types/node@20.14.9)(sass@1.77.6)(terser@5.31.2)) + '@storybook/node-logger': 8.1.11 + '@storybook/react': 8.1.11(encoding@0.1.13)(prettier@3.3.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.3) + '@storybook/types': 8.1.11 find-up: 5.0.0 - magic-string: 0.30.7 + magic-string: 0.30.10 react: 18.3.1 react-docgen: 7.0.1 react-dom: 18.3.1(react@18.3.1) resolve: 1.22.8 tsconfig-paths: 4.2.0 - vite: 5.2.11(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3) + vite: 5.3.2(@types/node@20.14.9)(sass@1.77.6)(terser@5.31.2) transitivePeerDependencies: - '@preact/preset-vite' - encoding + - prettier - rollup - supports-color - typescript - vite-plugin-glimmerx - '@storybook/react@8.0.9(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.4.5)': + '@storybook/react@8.1.11(encoding@0.1.13)(prettier@3.3.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.3)': dependencies: - '@storybook/client-logger': 8.0.9 - '@storybook/docs-tools': 8.0.9(encoding@0.1.13) + '@storybook/client-logger': 8.1.11 + '@storybook/docs-tools': 8.1.11(encoding@0.1.13)(prettier@3.3.2) '@storybook/global': 5.0.0 - '@storybook/preview-api': 8.0.9 - '@storybook/react-dom-shim': 8.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@storybook/types': 8.0.9 + '@storybook/preview-api': 8.1.11 + '@storybook/react-dom-shim': 8.1.11(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@storybook/types': 8.1.11 '@types/escodegen': 0.0.6 '@types/estree': 0.0.51 '@types/node': 18.17.15 @@ -15382,30 +16546,31 @@ snapshots: type-fest: 2.19.0 util-deprecate: 1.0.2 optionalDependencies: - typescript: 5.4.5 + typescript: 5.5.3 transitivePeerDependencies: - encoding + - prettier - supports-color - '@storybook/router@8.0.9': + '@storybook/router@8.1.11': dependencies: - '@storybook/client-logger': 8.0.9 + '@storybook/client-logger': 8.1.11 memoizerific: 1.11.3 qs: 6.11.1 - '@storybook/source-loader@8.0.9': + '@storybook/source-loader@8.1.11': dependencies: - '@storybook/csf': 0.1.6 - '@storybook/types': 8.0.9 + '@storybook/csf': 0.1.9 + '@storybook/types': 8.1.11 estraverse: 5.3.0 lodash: 4.17.21 - prettier: 3.2.5 + prettier: 3.3.2 - '@storybook/telemetry@8.0.9(encoding@0.1.13)': + '@storybook/telemetry@8.1.11(encoding@0.1.13)(prettier@3.3.2)': dependencies: - '@storybook/client-logger': 8.0.9 - '@storybook/core-common': 8.0.9(encoding@0.1.13) - '@storybook/csf-tools': 8.0.9 + '@storybook/client-logger': 8.1.11 + '@storybook/core-common': 8.1.11(encoding@0.1.13)(prettier@3.3.2) + '@storybook/csf-tools': 8.1.11 chalk: 4.1.2 detect-package-manager: 2.0.1 fetch-retry: 5.0.4 @@ -15413,18 +16578,19 @@ snapshots: read-pkg-up: 7.0.1 transitivePeerDependencies: - encoding + - prettier - supports-color - '@storybook/test@8.0.9(@jest/globals@29.7.0)(@types/jest@29.5.12)(jest@29.7.0(@types/node@20.12.7))(vitest@0.34.6(happy-dom@10.0.3)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3))': + '@storybook/test@8.1.11(@jest/globals@29.7.0)(@types/jest@29.5.12)(jest@29.7.0(@types/node@20.14.9))(vitest@1.6.0(@types/node@20.14.9)(happy-dom@10.0.3)(jsdom@24.1.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))(sass@1.77.6)(terser@5.31.2))': dependencies: - '@storybook/client-logger': 8.0.9 - '@storybook/core-events': 8.0.9 - '@storybook/instrumenter': 8.0.9 - '@storybook/preview-api': 8.0.9 - '@testing-library/dom': 9.3.4 - '@testing-library/jest-dom': 6.4.2(@jest/globals@29.7.0)(@types/jest@29.5.12)(jest@29.7.0(@types/node@20.12.7))(vitest@0.34.6(happy-dom@10.0.3)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3)) - '@testing-library/user-event': 14.5.2(@testing-library/dom@9.3.4) - '@vitest/expect': 1.3.1 + '@storybook/client-logger': 8.1.11 + '@storybook/core-events': 8.1.11 + '@storybook/instrumenter': 8.1.11 + '@storybook/preview-api': 8.1.11 + '@testing-library/dom': 10.1.0 + '@testing-library/jest-dom': 6.4.5(@jest/globals@29.7.0)(@types/jest@29.5.12)(jest@29.7.0(@types/node@20.14.9))(vitest@1.6.0(@types/node@20.14.9)(happy-dom@10.0.3)(jsdom@24.1.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))(sass@1.77.6)(terser@5.31.2)) + '@testing-library/user-event': 14.5.2(@testing-library/dom@10.1.0) + '@vitest/expect': 1.6.0 '@vitest/spy': 1.6.0 util: 0.12.5 transitivePeerDependencies: @@ -15434,37 +16600,39 @@ snapshots: - jest - vitest - '@storybook/theming@8.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@storybook/theming@8.1.11(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@emotion/use-insertion-effect-with-fallbacks': 1.0.1(react@18.3.1) - '@storybook/client-logger': 8.0.9 + '@storybook/client-logger': 8.1.11 '@storybook/global': 5.0.0 memoizerific: 1.11.3 optionalDependencies: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - '@storybook/types@8.0.9': + '@storybook/types@8.1.11': dependencies: - '@storybook/channels': 8.0.9 + '@storybook/channels': 8.1.11 '@types/express': 4.17.17 file-system-cache: 2.3.0 - '@storybook/vue3-vite@8.0.9(bufferutil@4.0.7)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(utf-8-validate@6.0.3)(vite@5.2.11(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3))(vue@3.4.26(typescript@5.4.5))': + '@storybook/vue3-vite@8.1.11(bufferutil@4.0.8)(encoding@0.1.13)(prettier@3.3.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(utf-8-validate@6.0.4)(vite@5.3.2(@types/node@20.14.9)(sass@1.77.6)(terser@5.31.2))(vue@3.4.31(typescript@5.5.3))': dependencies: - '@storybook/builder-vite': 8.0.9(encoding@0.1.13)(typescript@5.4.5)(vite@5.2.11(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3)) - '@storybook/core-server': 8.0.9(bufferutil@4.0.7)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(utf-8-validate@6.0.3) - '@storybook/vue3': 8.0.9(encoding@0.1.13)(vue@3.4.26(typescript@5.4.5)) + '@storybook/builder-vite': 8.1.11(encoding@0.1.13)(prettier@3.3.2)(typescript@5.5.3)(vite@5.3.2(@types/node@20.14.9)(sass@1.77.6)(terser@5.31.2)) + '@storybook/core-server': 8.1.11(bufferutil@4.0.8)(encoding@0.1.13)(prettier@3.3.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(utf-8-validate@6.0.4) + '@storybook/types': 8.1.11 + '@storybook/vue3': 8.1.11(encoding@0.1.13)(prettier@3.3.2)(vue@3.4.31(typescript@5.5.3)) find-package-json: 1.2.0 - magic-string: 0.30.7 - typescript: 5.4.5 - vite: 5.2.11(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3) - vue-component-meta: 2.0.16(typescript@5.4.5) - vue-docgen-api: 4.75.1(vue@3.4.26(typescript@5.4.5)) + magic-string: 0.30.10 + typescript: 5.5.3 + vite: 5.3.2(@types/node@20.14.9)(sass@1.77.6)(terser@5.31.2) + vue-component-meta: 2.0.16(typescript@5.5.3) + vue-docgen-api: 4.75.1(vue@3.4.31(typescript@5.5.3)) transitivePeerDependencies: - '@preact/preset-vite' - bufferutil - encoding + - prettier - react - react-dom - supports-color @@ -15472,26 +16640,27 @@ snapshots: - vite-plugin-glimmerx - vue - '@storybook/vue3@8.0.9(encoding@0.1.13)(vue@3.4.26(typescript@5.4.5))': + '@storybook/vue3@8.1.11(encoding@0.1.13)(prettier@3.3.2)(vue@3.4.31(typescript@5.5.3))': dependencies: - '@storybook/docs-tools': 8.0.9(encoding@0.1.13) + '@storybook/docs-tools': 8.1.11(encoding@0.1.13)(prettier@3.3.2) '@storybook/global': 5.0.0 - '@storybook/preview-api': 8.0.9 - '@storybook/types': 8.0.9 - '@vue/compiler-core': 3.4.21 + '@storybook/preview-api': 8.1.11 + '@storybook/types': 8.1.11 + '@vue/compiler-core': 3.4.29 lodash: 4.17.21 ts-dedent: 2.2.0 type-fest: 2.19.0 - vue: 3.4.26(typescript@5.4.5) - vue-component-type-helpers: 2.0.19 + vue: 3.4.31(typescript@5.5.3) + vue-component-type-helpers: 2.0.26 transitivePeerDependencies: - encoding + - prettier - supports-color - '@swc/cli@0.3.12(@swc/core@1.4.17)(chokidar@3.5.3)': + '@swc/cli@0.3.12(@swc/core@1.6.6)(chokidar@3.5.3)': dependencies: '@mole-inc/bin-wrapper': 8.0.1 - '@swc/core': 1.4.17 + '@swc/core': 1.6.6 '@swc/counter': 0.1.3 commander: 8.3.0 fast-glob: 3.3.2 @@ -15508,16 +16677,22 @@ snapshots: '@swc/wasm': 1.2.130 optional: true - '@swc/core-darwin-arm64@1.3.56': + '@swc/core-darwin-arm64@1.6.13': optional: true - '@swc/core-darwin-arm64@1.4.17': + '@swc/core-darwin-arm64@1.6.6': optional: true - '@swc/core-darwin-x64@1.3.56': + '@swc/core-darwin-arm64@1.7.0-nightly-20240715.2': optional: true - '@swc/core-darwin-x64@1.4.17': + '@swc/core-darwin-x64@1.6.13': + optional: true + + '@swc/core-darwin-x64@1.6.6': + optional: true + + '@swc/core-darwin-x64@1.7.0-nightly-20240715.2': optional: true '@swc/core-freebsd-x64@1.3.11': @@ -15525,85 +16700,134 @@ snapshots: '@swc/wasm': 1.2.130 optional: true - '@swc/core-linux-arm-gnueabihf@1.3.56': + '@swc/core-linux-arm-gnueabihf@1.6.13': optional: true - '@swc/core-linux-arm-gnueabihf@1.4.17': + '@swc/core-linux-arm-gnueabihf@1.6.6': optional: true - '@swc/core-linux-arm64-gnu@1.3.56': + '@swc/core-linux-arm-gnueabihf@1.7.0-nightly-20240715.2': optional: true - '@swc/core-linux-arm64-gnu@1.4.17': + '@swc/core-linux-arm64-gnu@1.6.13': optional: true - '@swc/core-linux-arm64-musl@1.3.56': + '@swc/core-linux-arm64-gnu@1.6.6': optional: true - '@swc/core-linux-arm64-musl@1.4.17': + '@swc/core-linux-arm64-gnu@1.7.0-nightly-20240715.2': optional: true - '@swc/core-linux-x64-gnu@1.3.56': + '@swc/core-linux-arm64-musl@1.6.13': optional: true - '@swc/core-linux-x64-gnu@1.4.17': + '@swc/core-linux-arm64-musl@1.6.6': optional: true - '@swc/core-linux-x64-musl@1.3.56': + '@swc/core-linux-arm64-musl@1.7.0-nightly-20240715.2': optional: true - '@swc/core-linux-x64-musl@1.4.17': + '@swc/core-linux-x64-gnu@1.6.13': optional: true - '@swc/core-win32-arm64-msvc@1.3.56': + '@swc/core-linux-x64-gnu@1.6.6': optional: true - '@swc/core-win32-arm64-msvc@1.4.17': + '@swc/core-linux-x64-gnu@1.7.0-nightly-20240715.2': optional: true - '@swc/core-win32-ia32-msvc@1.3.56': + '@swc/core-linux-x64-musl@1.6.13': optional: true - '@swc/core-win32-ia32-msvc@1.4.17': + '@swc/core-linux-x64-musl@1.6.6': optional: true - '@swc/core-win32-x64-msvc@1.3.56': + '@swc/core-linux-x64-musl@1.7.0-nightly-20240715.2': optional: true - '@swc/core-win32-x64-msvc@1.4.17': + '@swc/core-win32-arm64-msvc@1.6.13': optional: true - '@swc/core@1.4.17': + '@swc/core-win32-arm64-msvc@1.6.6': + optional: true + + '@swc/core-win32-arm64-msvc@1.7.0-nightly-20240715.2': + optional: true + + '@swc/core-win32-ia32-msvc@1.6.13': + optional: true + + '@swc/core-win32-ia32-msvc@1.6.6': + optional: true + + '@swc/core-win32-ia32-msvc@1.7.0-nightly-20240715.2': + optional: true + + '@swc/core-win32-x64-msvc@1.6.13': + optional: true + + '@swc/core-win32-x64-msvc@1.6.6': + optional: true + + '@swc/core-win32-x64-msvc@1.7.0-nightly-20240715.2': + optional: true + + '@swc/core@1.6.13': dependencies: '@swc/counter': 0.1.3 - '@swc/types': 0.1.5 + '@swc/types': 0.1.9 optionalDependencies: - '@swc/core-darwin-arm64': 1.4.17 - '@swc/core-darwin-x64': 1.4.17 - '@swc/core-linux-arm-gnueabihf': 1.4.17 - '@swc/core-linux-arm64-gnu': 1.4.17 - '@swc/core-linux-arm64-musl': 1.4.17 - '@swc/core-linux-x64-gnu': 1.4.17 - '@swc/core-linux-x64-musl': 1.4.17 - '@swc/core-win32-arm64-msvc': 1.4.17 - '@swc/core-win32-ia32-msvc': 1.4.17 - '@swc/core-win32-x64-msvc': 1.4.17 + '@swc/core-darwin-arm64': 1.6.13 + '@swc/core-darwin-x64': 1.6.13 + '@swc/core-linux-arm-gnueabihf': 1.6.13 + '@swc/core-linux-arm64-gnu': 1.6.13 + '@swc/core-linux-arm64-musl': 1.6.13 + '@swc/core-linux-x64-gnu': 1.6.13 + '@swc/core-linux-x64-musl': 1.6.13 + '@swc/core-win32-arm64-msvc': 1.6.13 + '@swc/core-win32-ia32-msvc': 1.6.13 + '@swc/core-win32-x64-msvc': 1.6.13 + + '@swc/core@1.6.6': + dependencies: + '@swc/counter': 0.1.3 + '@swc/types': 0.1.9 + optionalDependencies: + '@swc/core-darwin-arm64': 1.6.6 + '@swc/core-darwin-x64': 1.6.6 + '@swc/core-linux-arm-gnueabihf': 1.6.6 + '@swc/core-linux-arm64-gnu': 1.6.6 + '@swc/core-linux-arm64-musl': 1.6.6 + '@swc/core-linux-x64-gnu': 1.6.6 + '@swc/core-linux-x64-musl': 1.6.6 + '@swc/core-win32-arm64-msvc': 1.6.6 + '@swc/core-win32-ia32-msvc': 1.6.6 + '@swc/core-win32-x64-msvc': 1.6.6 '@swc/counter@0.1.3': {} - '@swc/jest@0.2.36(@swc/core@1.4.17)': + '@swc/jest@0.2.36(@swc/core@1.6.13)': dependencies: '@jest/create-cache-key-function': 29.7.0 - '@swc/core': 1.4.17 + '@swc/core': 1.6.13 '@swc/counter': 0.1.3 jsonc-parser: 3.2.0 - '@swc/types@0.1.5': {} + '@swc/jest@0.2.36(@swc/core@1.6.6)': + dependencies: + '@jest/create-cache-key-function': 29.7.0 + '@swc/core': 1.6.6 + '@swc/counter': 0.1.3 + jsonc-parser: 3.2.0 + + '@swc/types@0.1.9': + dependencies: + '@swc/counter': 0.1.3 '@swc/wasm@1.2.130': optional: true - '@syuilo/aiscript@0.18.0': + '@syuilo/aiscript@0.19.0': dependencies: seedrandom: 3.0.5 stringz: 2.1.0 @@ -15623,76 +16847,74 @@ snapshots: '@tabler/icons@3.3.0': {} - '@tensorflow/tfjs-backend-cpu@4.4.0(@tensorflow/tfjs-core@4.4.0(encoding@0.1.13))': + '@tensorflow/tfjs-backend-cpu@4.20.0(@tensorflow/tfjs-core@4.20.0(encoding@0.1.13))': dependencies: - '@tensorflow/tfjs-core': 4.4.0(encoding@0.1.13) - '@types/seedrandom': 2.4.30 + '@tensorflow/tfjs-core': 4.20.0(encoding@0.1.13) + '@types/seedrandom': 2.4.34 seedrandom: 3.0.5 - '@tensorflow/tfjs-backend-webgl@4.4.0(@tensorflow/tfjs-core@4.4.0(encoding@0.1.13))': + '@tensorflow/tfjs-backend-webgl@4.20.0(@tensorflow/tfjs-core@4.20.0(encoding@0.1.13))': dependencies: - '@tensorflow/tfjs-backend-cpu': 4.4.0(@tensorflow/tfjs-core@4.4.0(encoding@0.1.13)) - '@tensorflow/tfjs-core': 4.4.0(encoding@0.1.13) + '@tensorflow/tfjs-backend-cpu': 4.20.0(@tensorflow/tfjs-core@4.20.0(encoding@0.1.13)) + '@tensorflow/tfjs-core': 4.20.0(encoding@0.1.13) '@types/offscreencanvas': 2019.3.0 - '@types/seedrandom': 2.4.30 - '@types/webgl-ext': 0.0.30 + '@types/seedrandom': 2.4.34 seedrandom: 3.0.5 - '@tensorflow/tfjs-converter@4.4.0(@tensorflow/tfjs-core@4.4.0(encoding@0.1.13))': + '@tensorflow/tfjs-converter@4.20.0(@tensorflow/tfjs-core@4.20.0(encoding@0.1.13))': dependencies: - '@tensorflow/tfjs-core': 4.4.0(encoding@0.1.13) + '@tensorflow/tfjs-core': 4.20.0(encoding@0.1.13) - '@tensorflow/tfjs-core@4.4.0(encoding@0.1.13)': + '@tensorflow/tfjs-core@4.20.0(encoding@0.1.13)': dependencies: '@types/long': 4.0.2 '@types/offscreencanvas': 2019.7.0 '@types/seedrandom': 2.4.30 - '@types/webgl-ext': 0.0.30 - '@webgpu/types': 0.1.30 + '@webgpu/types': 0.1.38 long: 4.0.0 node-fetch: 2.6.11(encoding@0.1.13) seedrandom: 3.0.5 transitivePeerDependencies: - encoding - '@tensorflow/tfjs-data@4.4.0(@tensorflow/tfjs-core@4.4.0(encoding@0.1.13))(encoding@0.1.13)(seedrandom@3.0.5)': + '@tensorflow/tfjs-data@4.20.0(@tensorflow/tfjs-core@4.20.0(encoding@0.1.13))(encoding@0.1.13)(seedrandom@3.0.5)': dependencies: - '@tensorflow/tfjs-core': 4.4.0(encoding@0.1.13) - '@types/node-fetch': 2.6.4 - node-fetch: 2.6.11(encoding@0.1.13) + '@tensorflow/tfjs-core': 4.20.0(encoding@0.1.13) + '@types/node-fetch': 2.6.11 + node-fetch: 2.6.13(encoding@0.1.13) seedrandom: 3.0.5 string_decoder: 1.3.0 transitivePeerDependencies: - encoding - '@tensorflow/tfjs-layers@4.4.0(@tensorflow/tfjs-core@4.4.0(encoding@0.1.13))': + '@tensorflow/tfjs-layers@4.20.0(@tensorflow/tfjs-core@4.20.0(encoding@0.1.13))': dependencies: - '@tensorflow/tfjs-core': 4.4.0(encoding@0.1.13) + '@tensorflow/tfjs-core': 4.20.0(encoding@0.1.13) - '@tensorflow/tfjs-node@4.4.0(encoding@0.1.13)(seedrandom@3.0.5)': + '@tensorflow/tfjs-node@4.20.0(encoding@0.1.13)(seedrandom@3.0.5)': dependencies: '@mapbox/node-pre-gyp': 1.0.9(encoding@0.1.13) - '@tensorflow/tfjs': 4.4.0(encoding@0.1.13)(seedrandom@3.0.5) + '@tensorflow/tfjs': 4.20.0(encoding@0.1.13)(seedrandom@3.0.5) adm-zip: 0.5.10 google-protobuf: 3.21.2 https-proxy-agent: 2.2.4 progress: 2.0.3 rimraf: 2.7.1 - tar: 4.4.19 + tar: 6.2.1 transitivePeerDependencies: - encoding - seedrandom - supports-color optional: true - '@tensorflow/tfjs@4.4.0(encoding@0.1.13)(seedrandom@3.0.5)': + '@tensorflow/tfjs@4.20.0(encoding@0.1.13)(seedrandom@3.0.5)': dependencies: - '@tensorflow/tfjs-backend-cpu': 4.4.0(@tensorflow/tfjs-core@4.4.0(encoding@0.1.13)) - '@tensorflow/tfjs-backend-webgl': 4.4.0(@tensorflow/tfjs-core@4.4.0(encoding@0.1.13)) - '@tensorflow/tfjs-converter': 4.4.0(@tensorflow/tfjs-core@4.4.0(encoding@0.1.13)) - '@tensorflow/tfjs-core': 4.4.0(encoding@0.1.13) - '@tensorflow/tfjs-data': 4.4.0(@tensorflow/tfjs-core@4.4.0(encoding@0.1.13))(encoding@0.1.13)(seedrandom@3.0.5) - '@tensorflow/tfjs-layers': 4.4.0(@tensorflow/tfjs-core@4.4.0(encoding@0.1.13)) + '@tensorflow/tfjs-backend-cpu': 4.20.0(@tensorflow/tfjs-core@4.20.0(encoding@0.1.13)) + '@tensorflow/tfjs-backend-webgl': 4.20.0(@tensorflow/tfjs-core@4.20.0(encoding@0.1.13)) + '@tensorflow/tfjs-converter': 4.20.0(@tensorflow/tfjs-core@4.20.0(encoding@0.1.13)) + '@tensorflow/tfjs-core': 4.20.0(encoding@0.1.13) + '@tensorflow/tfjs-data': 4.20.0(@tensorflow/tfjs-core@4.20.0(encoding@0.1.13))(encoding@0.1.13)(seedrandom@3.0.5) + '@tensorflow/tfjs-layers': 4.20.0(@tensorflow/tfjs-core@4.20.0(encoding@0.1.13)) argparse: 1.0.10 chalk: 4.1.2 core-js: 3.29.1 @@ -15702,12 +16924,12 @@ snapshots: - encoding - seedrandom - '@testing-library/dom@9.3.3': + '@testing-library/dom@10.1.0': dependencies: - '@babel/code-frame': 7.23.5 + '@babel/code-frame': 7.24.7 '@babel/runtime': 7.23.4 '@types/aria-query': 5.0.1 - aria-query: 5.1.3 + aria-query: 5.3.0 chalk: 4.1.2 dom-accessibility-api: 0.5.16 lz-string: 1.5.0 @@ -15724,7 +16946,7 @@ snapshots: lz-string: 1.5.0 pretty-format: 27.5.1 - '@testing-library/jest-dom@6.4.2(@jest/globals@29.7.0)(@types/jest@29.5.12)(jest@29.7.0(@types/node@20.12.7))(vitest@0.34.6(happy-dom@10.0.3)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3))': + '@testing-library/jest-dom@6.4.5(@jest/globals@29.7.0)(@types/jest@29.5.12)(jest@29.7.0(@types/node@20.14.9))(vitest@1.6.0(@types/node@20.14.9)(happy-dom@10.0.3)(jsdom@24.1.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))(sass@1.77.6)(terser@5.31.2))': dependencies: '@adobe/css-tools': 4.3.3 '@babel/runtime': 7.23.4 @@ -15737,21 +16959,21 @@ snapshots: optionalDependencies: '@jest/globals': 29.7.0 '@types/jest': 29.5.12 - jest: 29.7.0(@types/node@20.12.7) - vitest: 0.34.6(happy-dom@10.0.3)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3) + jest: 29.7.0(@types/node@20.14.9) + vitest: 1.6.0(@types/node@20.14.9)(happy-dom@10.0.3)(jsdom@24.1.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))(sass@1.77.6)(terser@5.31.2) - '@testing-library/user-event@14.5.2(@testing-library/dom@9.3.4)': + '@testing-library/user-event@14.5.2(@testing-library/dom@10.1.0)': dependencies: - '@testing-library/dom': 9.3.4 + '@testing-library/dom': 10.1.0 - '@testing-library/vue@8.0.3(@vue/compiler-sfc@3.4.26)(@vue/server-renderer@3.4.26(vue@3.4.26(typescript@5.4.5)))(vue@3.4.26(typescript@5.4.5))': + '@testing-library/vue@8.1.0(@vue/compiler-sfc@3.4.31)(@vue/server-renderer@3.4.31(vue@3.4.31(typescript@5.5.3)))(vue@3.4.31(typescript@5.5.3))': dependencies: '@babel/runtime': 7.23.4 - '@testing-library/dom': 9.3.3 - '@vue/test-utils': 2.4.1(@vue/server-renderer@3.4.26(vue@3.4.26(typescript@5.4.5)))(vue@3.4.26(typescript@5.4.5)) - vue: 3.4.26(typescript@5.4.5) + '@testing-library/dom': 9.3.4 + '@vue/test-utils': 2.4.1(@vue/server-renderer@3.4.31(vue@3.4.31(typescript@5.5.3)))(vue@3.4.31(typescript@5.5.3)) + vue: 3.4.31(typescript@5.5.3) optionalDependencies: - '@vue/compiler-sfc': 3.4.26 + '@vue/compiler-sfc': 3.4.31 transitivePeerDependencies: - '@vue/server-renderer' @@ -15759,7 +16981,7 @@ snapshots: '@trysound/sax@0.2.0': {} - '@tsd/typescript@5.3.3': {} + '@tsd/typescript@5.4.5': {} '@twemoji/parser@15.0.0': {} @@ -15767,7 +16989,7 @@ snapshots: '@types/accepts@1.3.7': dependencies: - '@types/node': 20.12.7 + '@types/node': 20.14.9 '@types/archiver@6.0.2': dependencies: @@ -15779,31 +17001,31 @@ snapshots: '@types/babel__core@7.20.0': dependencies: - '@babel/parser': 7.24.0 - '@babel/types': 7.24.0 + '@babel/parser': 7.24.7 + '@babel/types': 7.24.7 '@types/babel__generator': 7.6.4 '@types/babel__template': 7.4.1 '@types/babel__traverse': 7.20.0 '@types/babel__generator@7.6.4': dependencies: - '@babel/types': 7.24.0 + '@babel/types': 7.24.7 '@types/babel__template@7.4.1': dependencies: - '@babel/parser': 7.24.0 - '@babel/types': 7.24.0 + '@babel/parser': 7.24.7 + '@babel/types': 7.24.7 '@types/babel__traverse@7.20.0': dependencies: - '@babel/types': 7.24.0 + '@babel/types': 7.24.7 '@types/bcryptjs@2.4.6': {} '@types/body-parser@1.19.5': dependencies: '@types/connect': 3.4.35 - '@types/node': 20.12.7 + '@types/node': 20.14.9 '@types/braces@3.0.1': {} @@ -15811,15 +17033,9 @@ snapshots: dependencies: '@types/http-cache-semantics': 4.0.4 '@types/keyv': 3.1.4 - '@types/node': 20.12.7 + '@types/node': 20.14.9 '@types/responselike': 1.0.0 - '@types/chai-subset@1.3.5': - dependencies: - '@types/chai': 4.3.11 - - '@types/chai@4.3.11': {} - '@types/color-convert@2.0.3': dependencies: '@types/color-name': 1.1.1 @@ -15828,11 +17044,11 @@ snapshots: '@types/connect@3.4.35': dependencies: - '@types/node': 20.12.7 + '@types/node': 20.14.9 '@types/connect@3.4.36': dependencies: - '@types/node': 20.12.7 + '@types/node': 20.14.9 '@types/content-disposition@0.5.8': {} @@ -15840,14 +17056,14 @@ snapshots: '@types/cookies@0.9.0': dependencies: - '@types/connect': 3.4.35 + '@types/connect': 3.4.36 '@types/express': 4.17.17 '@types/keygrip': 1.0.6 - '@types/node': 20.12.7 + '@types/node': 20.14.9 '@types/cross-spawn@6.0.2': dependencies: - '@types/node': 20.12.7 + '@types/node': 20.14.9 '@types/debug@4.1.12': dependencies: @@ -15855,6 +17071,8 @@ snapshots: '@types/detect-port@1.3.2': {} + '@types/diff@5.2.1': {} + '@types/disposable-email-domains@1.0.2': {} '@types/doctrine@0.0.3': {} @@ -15872,7 +17090,7 @@ snapshots: '@types/eslint@7.29.0': dependencies: '@types/estree': 1.0.5 - '@types/json-schema': 7.0.12 + '@types/json-schema': 7.0.15 '@types/estree@0.0.51': {} @@ -15880,7 +17098,7 @@ snapshots: '@types/express-serve-static-core@4.17.33': dependencies: - '@types/node': 20.12.7 + '@types/node': 20.14.9 '@types/qs': 6.9.7 '@types/range-parser': 1.2.4 @@ -15895,16 +17113,16 @@ snapshots: '@types/fluent-ffmpeg@2.1.24': dependencies: - '@types/node': 20.12.7 + '@types/node': 20.14.9 '@types/glob@7.2.0': dependencies: '@types/minimatch': 5.1.2 - '@types/node': 20.12.7 + '@types/node': 20.14.9 '@types/graceful-fs@4.1.6': dependencies: - '@types/node': 20.12.7 + '@types/node': 20.14.9 '@types/hast@3.0.4': dependencies: @@ -15918,9 +17136,9 @@ snapshots: '@types/http-errors@2.0.4': {} - '@types/http-link-header@1.0.5': + '@types/http-link-header@1.0.7': dependencies: - '@types/node': 20.12.7 + '@types/node': 20.14.9 '@types/istanbul-lib-coverage@2.0.4': {} @@ -15939,9 +17157,9 @@ snapshots: '@types/js-yaml@4.0.9': {} - '@types/jsdom@21.1.6': + '@types/jsdom@21.1.7': dependencies: - '@types/node': 20.12.7 + '@types/node': 20.14.9 '@types/tough-cookie': 4.0.2 parse5: 7.1.2 @@ -15951,7 +17169,7 @@ snapshots: '@types/json5@0.0.29': {} - '@types/jsonld@1.5.13': {} + '@types/jsonld@1.5.14': {} '@types/jsrsasign@10.5.14': {} @@ -15959,7 +17177,7 @@ snapshots: '@types/keyv@3.1.4': dependencies: - '@types/node': 20.12.7 + '@types/node': 20.14.9 '@types/koa-compose@3.2.8': dependencies: @@ -15974,7 +17192,7 @@ snapshots: '@types/http-errors': 2.0.4 '@types/keygrip': 1.0.6 '@types/koa-compose': 3.2.8 - '@types/node': 20.12.7 + '@types/node': 20.14.9 '@types/koa__router@12.0.3': dependencies: @@ -15992,7 +17210,7 @@ snapshots: '@types/mdx@2.0.3': {} - '@types/micromatch@4.0.7': + '@types/micromatch@4.0.9': dependencies: '@types/braces': 3.0.1 @@ -16008,20 +17226,16 @@ snapshots: '@types/mute-stream@0.0.4': dependencies: - '@types/node': 20.12.7 + '@types/node': 20.14.9 '@types/mysql@2.15.22': dependencies: - '@types/node': 20.12.7 + '@types/node': 20.14.9 - '@types/node-fetch@2.6.4': + '@types/node-fetch@2.6.11': dependencies: - '@types/node': 20.12.7 - form-data: 3.0.1 - - '@types/node-fetch@3.0.3': - dependencies: - node-fetch: 3.3.2 + '@types/node': 20.14.9 + form-data: 4.0.0 '@types/node@18.17.15': {} @@ -16029,7 +17243,7 @@ snapshots: dependencies: undici-types: 5.26.5 - '@types/node@20.12.7': + '@types/node@20.14.9': dependencies: undici-types: 5.26.5 @@ -16039,7 +17253,7 @@ snapshots: '@types/nodemailer@6.4.15': dependencies: - '@types/node': 20.12.7 + '@types/node': 20.14.9 '@types/normalize-package-data@2.4.1': {} @@ -16050,11 +17264,11 @@ snapshots: '@types/oauth2orize@1.11.5': dependencies: '@types/express': 4.17.17 - '@types/node': 20.12.7 + '@types/node': 20.14.9 - '@types/oauth@0.9.4': + '@types/oauth@0.9.5': dependencies: - '@types/node': 20.12.7 + '@types/node': 20.14.9 '@types/offscreencanvas@2019.3.0': {} @@ -16062,17 +17276,17 @@ snapshots: '@types/pg-pool@2.0.4': dependencies: - '@types/pg': 8.11.5 + '@types/pg': 8.11.6 - '@types/pg@8.11.5': + '@types/pg@8.11.6': dependencies: - '@types/node': 20.12.7 - pg-protocol: 1.6.0 + '@types/node': 20.14.9 + pg-protocol: 1.6.1 pg-types: 4.0.1 '@types/pg@8.6.1': dependencies: - '@types/node': 20.12.7 + '@types/node': 20.14.9 pg-protocol: 1.6.1 pg-types: 2.2.0 @@ -16086,7 +17300,7 @@ snapshots: '@types/qrcode@1.5.5': dependencies: - '@types/node': 20.12.7 + '@types/node': 20.14.9 '@types/qs@6.9.7': {} @@ -16104,7 +17318,7 @@ snapshots: '@types/readdir-glob@1.1.1': dependencies: - '@types/node': 20.12.7 + '@types/node': 20.14.9 '@types/rename@1.0.7': {} @@ -16112,7 +17326,7 @@ snapshots: '@types/responselike@1.0.0': dependencies: - '@types/node': 20.12.7 + '@types/node': 20.14.9 '@types/sanitize-html@2.11.0': dependencies: @@ -16122,6 +17336,8 @@ snapshots: '@types/seedrandom@2.4.30': {} + '@types/seedrandom@2.4.34': {} + '@types/seedrandom@3.0.8': {} '@types/semver@7.5.8': {} @@ -16129,7 +17345,7 @@ snapshots: '@types/serve-static@1.15.1': dependencies: '@types/mime': 3.0.1 - '@types/node': 20.12.7 + '@types/node': 20.14.9 '@types/serviceworker@0.0.67': {} @@ -16161,23 +17377,23 @@ snapshots: '@types/unist@3.0.2': {} + '@types/uuid@10.0.0': {} + '@types/uuid@9.0.8': {} '@types/vary@1.1.3': dependencies: - '@types/node': 20.12.7 + '@types/node': 20.14.9 '@types/web-push@3.6.3': dependencies: - '@types/node': 20.12.7 - - '@types/webgl-ext@0.0.30': {} + '@types/node': 20.14.9 '@types/wrap-ansi@3.0.0': {} '@types/ws@8.5.10': dependencies: - '@types/node': 20.12.7 + '@types/node': 20.14.9 '@types/yargs-parser@21.0.0': {} @@ -16187,19 +17403,19 @@ snapshots: '@types/yauzl@2.10.0': dependencies: - '@types/node': 20.12.7 + '@types/node': 20.14.9 optional: true - '@typescript-eslint/eslint-plugin@6.11.0(@typescript-eslint/parser@6.11.0(eslint@8.53.0)(typescript@5.3.3))(eslint@8.53.0)(typescript@5.3.3)': + '@typescript-eslint/eslint-plugin@6.11.0(@typescript-eslint/parser@6.11.0(eslint@9.7.0)(typescript@5.3.3))(eslint@9.7.0)(typescript@5.3.3)': dependencies: '@eslint-community/regexpp': 4.6.2 - '@typescript-eslint/parser': 6.11.0(eslint@8.53.0)(typescript@5.3.3) + '@typescript-eslint/parser': 6.11.0(eslint@9.7.0)(typescript@5.3.3) '@typescript-eslint/scope-manager': 6.11.0 - '@typescript-eslint/type-utils': 6.11.0(eslint@8.53.0)(typescript@5.3.3) - '@typescript-eslint/utils': 6.11.0(eslint@8.53.0)(typescript@5.3.3) + '@typescript-eslint/type-utils': 6.11.0(eslint@9.7.0)(typescript@5.3.3) + '@typescript-eslint/utils': 6.11.0(eslint@9.7.0)(typescript@5.3.3) '@typescript-eslint/visitor-keys': 6.11.0 - debug: 4.3.4(supports-color@8.1.1) - eslint: 8.53.0 + debug: 4.3.4(supports-color@5.5.0) + eslint: 9.7.0 graphemer: 1.4.0 ignore: 5.2.4 natural-compare: 1.4.0 @@ -16210,16 +17426,16 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/eslint-plugin@7.1.0(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint@8.57.0)(typescript@5.3.3)': + '@typescript-eslint/eslint-plugin@7.1.0(@typescript-eslint/parser@7.1.0(eslint@9.7.0)(typescript@5.3.3))(eslint@9.7.0)(typescript@5.3.3)': dependencies: '@eslint-community/regexpp': 4.6.2 - '@typescript-eslint/parser': 7.1.0(eslint@8.57.0)(typescript@5.3.3) + '@typescript-eslint/parser': 7.1.0(eslint@9.7.0)(typescript@5.3.3) '@typescript-eslint/scope-manager': 7.1.0 - '@typescript-eslint/type-utils': 7.1.0(eslint@8.57.0)(typescript@5.3.3) - '@typescript-eslint/utils': 7.1.0(eslint@8.57.0)(typescript@5.3.3) + '@typescript-eslint/type-utils': 7.1.0(eslint@9.7.0)(typescript@5.3.3) + '@typescript-eslint/utils': 7.1.0(eslint@9.7.0)(typescript@5.3.3) '@typescript-eslint/visitor-keys': 7.1.0 - debug: 4.3.4(supports-color@8.1.1) - eslint: 8.57.0 + debug: 4.3.4(supports-color@5.5.0) + eslint: 9.7.0 graphemer: 1.4.0 ignore: 5.2.4 natural-compare: 1.4.0 @@ -16230,62 +17446,91 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/eslint-plugin@7.7.1(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5)': + '@typescript-eslint/eslint-plugin@7.15.0(@typescript-eslint/parser@7.15.0(eslint@9.6.0)(typescript@5.5.3))(eslint@9.6.0)(typescript@5.5.3)': dependencies: '@eslint-community/regexpp': 4.10.0 - '@typescript-eslint/parser': 7.7.1(eslint@8.57.0)(typescript@5.4.5) - '@typescript-eslint/scope-manager': 7.7.1 - '@typescript-eslint/type-utils': 7.7.1(eslint@8.57.0)(typescript@5.4.5) - '@typescript-eslint/utils': 7.7.1(eslint@8.57.0)(typescript@5.4.5) - '@typescript-eslint/visitor-keys': 7.7.1 - debug: 4.3.4(supports-color@8.1.1) - eslint: 8.57.0 + '@typescript-eslint/parser': 7.15.0(eslint@9.6.0)(typescript@5.5.3) + '@typescript-eslint/scope-manager': 7.15.0 + '@typescript-eslint/type-utils': 7.15.0(eslint@9.6.0)(typescript@5.5.3) + '@typescript-eslint/utils': 7.15.0(eslint@9.6.0)(typescript@5.5.3) + '@typescript-eslint/visitor-keys': 7.15.0 + eslint: 9.6.0 graphemer: 1.4.0 ignore: 5.3.1 natural-compare: 1.4.0 - semver: 7.6.0 - ts-api-utils: 1.3.0(typescript@5.4.5) + ts-api-utils: 1.3.0(typescript@5.5.3) optionalDependencies: - typescript: 5.4.5 + typescript: 5.5.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@6.11.0(eslint@8.53.0)(typescript@5.3.3)': + '@typescript-eslint/eslint-plugin@7.15.0(@typescript-eslint/parser@7.15.0(eslint@9.7.0)(typescript@5.5.3))(eslint@9.7.0)(typescript@5.5.3)': + dependencies: + '@eslint-community/regexpp': 4.10.0 + '@typescript-eslint/parser': 7.15.0(eslint@9.7.0)(typescript@5.5.3) + '@typescript-eslint/scope-manager': 7.15.0 + '@typescript-eslint/type-utils': 7.15.0(eslint@9.7.0)(typescript@5.5.3) + '@typescript-eslint/utils': 7.15.0(eslint@9.7.0)(typescript@5.5.3) + '@typescript-eslint/visitor-keys': 7.15.0 + eslint: 9.7.0 + graphemer: 1.4.0 + ignore: 5.3.1 + natural-compare: 1.4.0 + ts-api-utils: 1.3.0(typescript@5.5.3) + optionalDependencies: + typescript: 5.5.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/parser@6.11.0(eslint@9.7.0)(typescript@5.3.3)': dependencies: '@typescript-eslint/scope-manager': 6.11.0 '@typescript-eslint/types': 6.11.0 '@typescript-eslint/typescript-estree': 6.11.0(typescript@5.3.3) '@typescript-eslint/visitor-keys': 6.11.0 - debug: 4.3.4(supports-color@8.1.1) - eslint: 8.53.0 + debug: 4.3.4(supports-color@5.5.0) + eslint: 9.7.0 optionalDependencies: typescript: 5.3.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3)': + '@typescript-eslint/parser@7.1.0(eslint@9.7.0)(typescript@5.3.3)': dependencies: '@typescript-eslint/scope-manager': 7.1.0 '@typescript-eslint/types': 7.1.0 '@typescript-eslint/typescript-estree': 7.1.0(typescript@5.3.3) '@typescript-eslint/visitor-keys': 7.1.0 - debug: 4.3.4(supports-color@8.1.1) - eslint: 8.57.0 + debug: 4.3.4(supports-color@5.5.0) + eslint: 9.7.0 optionalDependencies: typescript: 5.3.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5)': + '@typescript-eslint/parser@7.15.0(eslint@9.6.0)(typescript@5.5.3)': dependencies: - '@typescript-eslint/scope-manager': 7.7.1 - '@typescript-eslint/types': 7.7.1 - '@typescript-eslint/typescript-estree': 7.7.1(typescript@5.4.5) - '@typescript-eslint/visitor-keys': 7.7.1 - debug: 4.3.4(supports-color@8.1.1) - eslint: 8.57.0 + '@typescript-eslint/scope-manager': 7.15.0 + '@typescript-eslint/types': 7.15.0 + '@typescript-eslint/typescript-estree': 7.15.0(typescript@5.5.3) + '@typescript-eslint/visitor-keys': 7.15.0 + debug: 4.3.5(supports-color@8.1.1) + eslint: 9.6.0 optionalDependencies: - typescript: 5.4.5 + typescript: 5.5.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/parser@7.15.0(eslint@9.7.0)(typescript@5.5.3)': + dependencies: + '@typescript-eslint/scope-manager': 7.15.0 + '@typescript-eslint/types': 7.15.0 + '@typescript-eslint/typescript-estree': 7.15.0(typescript@5.5.3) + '@typescript-eslint/visitor-keys': 7.15.0 + debug: 4.3.5(supports-color@8.1.1) + eslint: 9.7.0 + optionalDependencies: + typescript: 5.5.3 transitivePeerDependencies: - supports-color @@ -16299,44 +17544,56 @@ snapshots: '@typescript-eslint/types': 7.1.0 '@typescript-eslint/visitor-keys': 7.1.0 - '@typescript-eslint/scope-manager@7.7.1': + '@typescript-eslint/scope-manager@7.15.0': dependencies: - '@typescript-eslint/types': 7.7.1 - '@typescript-eslint/visitor-keys': 7.7.1 + '@typescript-eslint/types': 7.15.0 + '@typescript-eslint/visitor-keys': 7.15.0 - '@typescript-eslint/type-utils@6.11.0(eslint@8.53.0)(typescript@5.3.3)': + '@typescript-eslint/type-utils@6.11.0(eslint@9.7.0)(typescript@5.3.3)': dependencies: '@typescript-eslint/typescript-estree': 6.11.0(typescript@5.3.3) - '@typescript-eslint/utils': 6.11.0(eslint@8.53.0)(typescript@5.3.3) - debug: 4.3.4(supports-color@8.1.1) - eslint: 8.53.0 + '@typescript-eslint/utils': 6.11.0(eslint@9.7.0)(typescript@5.3.3) + debug: 4.3.5(supports-color@8.1.1) + eslint: 9.7.0 ts-api-utils: 1.0.1(typescript@5.3.3) optionalDependencies: typescript: 5.3.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/type-utils@7.1.0(eslint@8.57.0)(typescript@5.3.3)': + '@typescript-eslint/type-utils@7.1.0(eslint@9.7.0)(typescript@5.3.3)': dependencies: '@typescript-eslint/typescript-estree': 7.1.0(typescript@5.3.3) - '@typescript-eslint/utils': 7.1.0(eslint@8.57.0)(typescript@5.3.3) - debug: 4.3.4(supports-color@8.1.1) - eslint: 8.57.0 + '@typescript-eslint/utils': 7.1.0(eslint@9.7.0)(typescript@5.3.3) + debug: 4.3.4(supports-color@5.5.0) + eslint: 9.7.0 ts-api-utils: 1.0.1(typescript@5.3.3) optionalDependencies: typescript: 5.3.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/type-utils@7.7.1(eslint@8.57.0)(typescript@5.4.5)': + '@typescript-eslint/type-utils@7.15.0(eslint@9.6.0)(typescript@5.5.3)': dependencies: - '@typescript-eslint/typescript-estree': 7.7.1(typescript@5.4.5) - '@typescript-eslint/utils': 7.7.1(eslint@8.57.0)(typescript@5.4.5) - debug: 4.3.4(supports-color@8.1.1) - eslint: 8.57.0 - ts-api-utils: 1.3.0(typescript@5.4.5) + '@typescript-eslint/typescript-estree': 7.15.0(typescript@5.5.3) + '@typescript-eslint/utils': 7.15.0(eslint@9.6.0)(typescript@5.5.3) + debug: 4.3.5(supports-color@8.1.1) + eslint: 9.6.0 + ts-api-utils: 1.3.0(typescript@5.5.3) optionalDependencies: - typescript: 5.4.5 + typescript: 5.5.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/type-utils@7.15.0(eslint@9.7.0)(typescript@5.5.3)': + dependencies: + '@typescript-eslint/typescript-estree': 7.15.0(typescript@5.5.3) + '@typescript-eslint/utils': 7.15.0(eslint@9.7.0)(typescript@5.5.3) + debug: 4.3.5(supports-color@8.1.1) + eslint: 9.7.0 + ts-api-utils: 1.3.0(typescript@5.5.3) + optionalDependencies: + typescript: 5.5.3 transitivePeerDependencies: - supports-color @@ -16344,13 +17601,13 @@ snapshots: '@typescript-eslint/types@7.1.0': {} - '@typescript-eslint/types@7.7.1': {} + '@typescript-eslint/types@7.15.0': {} '@typescript-eslint/typescript-estree@6.11.0(typescript@5.3.3)': dependencies: '@typescript-eslint/types': 6.11.0 '@typescript-eslint/visitor-keys': 6.11.0 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.5(supports-color@8.1.1) globby: 11.1.0 is-glob: 4.0.3 semver: 7.5.4 @@ -16364,7 +17621,7 @@ snapshots: dependencies: '@typescript-eslint/types': 7.1.0 '@typescript-eslint/visitor-keys': 7.1.0 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.4(supports-color@5.5.0) globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.3 @@ -16375,59 +17632,67 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/typescript-estree@7.7.1(typescript@5.4.5)': + '@typescript-eslint/typescript-estree@7.15.0(typescript@5.5.3)': dependencies: - '@typescript-eslint/types': 7.7.1 - '@typescript-eslint/visitor-keys': 7.7.1 - debug: 4.3.4(supports-color@8.1.1) + '@typescript-eslint/types': 7.15.0 + '@typescript-eslint/visitor-keys': 7.15.0 + debug: 4.3.5(supports-color@8.1.1) globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.4 semver: 7.6.0 - ts-api-utils: 1.3.0(typescript@5.4.5) + ts-api-utils: 1.3.0(typescript@5.5.3) optionalDependencies: - typescript: 5.4.5 + typescript: 5.5.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@6.11.0(eslint@8.53.0)(typescript@5.3.3)': + '@typescript-eslint/utils@6.11.0(eslint@9.7.0)(typescript@5.3.3)': dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.53.0) + '@eslint-community/eslint-utils': 4.4.0(eslint@9.7.0) '@types/json-schema': 7.0.12 '@types/semver': 7.5.8 '@typescript-eslint/scope-manager': 6.11.0 '@typescript-eslint/types': 6.11.0 '@typescript-eslint/typescript-estree': 6.11.0(typescript@5.3.3) - eslint: 8.53.0 + eslint: 9.7.0 semver: 7.5.4 transitivePeerDependencies: - supports-color - typescript - '@typescript-eslint/utils@7.1.0(eslint@8.57.0)(typescript@5.3.3)': + '@typescript-eslint/utils@7.1.0(eslint@9.7.0)(typescript@5.3.3)': dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) + '@eslint-community/eslint-utils': 4.4.0(eslint@9.7.0) '@types/json-schema': 7.0.12 '@types/semver': 7.5.8 '@typescript-eslint/scope-manager': 7.1.0 '@typescript-eslint/types': 7.1.0 '@typescript-eslint/typescript-estree': 7.1.0(typescript@5.3.3) - eslint: 8.57.0 + eslint: 9.7.0 semver: 7.6.0 transitivePeerDependencies: - supports-color - typescript - '@typescript-eslint/utils@7.7.1(eslint@8.57.0)(typescript@5.4.5)': + '@typescript-eslint/utils@7.15.0(eslint@9.6.0)(typescript@5.5.3)': dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) - '@types/json-schema': 7.0.15 - '@types/semver': 7.5.8 - '@typescript-eslint/scope-manager': 7.7.1 - '@typescript-eslint/types': 7.7.1 - '@typescript-eslint/typescript-estree': 7.7.1(typescript@5.4.5) - eslint: 8.57.0 - semver: 7.6.0 + '@eslint-community/eslint-utils': 4.4.0(eslint@9.6.0) + '@typescript-eslint/scope-manager': 7.15.0 + '@typescript-eslint/types': 7.15.0 + '@typescript-eslint/typescript-estree': 7.15.0(typescript@5.5.3) + eslint: 9.6.0 + transitivePeerDependencies: + - supports-color + - typescript + + '@typescript-eslint/utils@7.15.0(eslint@9.7.0)(typescript@5.5.3)': + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@9.7.0) + '@typescript-eslint/scope-manager': 7.15.0 + '@typescript-eslint/types': 7.15.0 + '@typescript-eslint/typescript-estree': 7.15.0(typescript@5.5.3) + eslint: 9.7.0 transitivePeerDependencies: - supports-color - typescript @@ -16442,84 +17707,59 @@ snapshots: '@typescript-eslint/types': 7.1.0 eslint-visitor-keys: 3.4.3 - '@typescript-eslint/visitor-keys@7.7.1': + '@typescript-eslint/visitor-keys@7.15.0': dependencies: - '@typescript-eslint/types': 7.7.1 + '@typescript-eslint/types': 7.15.0 eslint-visitor-keys: 3.4.3 '@ungap/structured-clone@1.2.0': {} - '@vitejs/plugin-vue@5.0.4(vite@5.2.11(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3))(vue@3.4.26(typescript@5.4.5))': + '@vitejs/plugin-vue@5.0.5(vite@5.3.2(@types/node@20.14.9)(sass@1.77.6)(terser@5.31.2))(vue@3.4.31(typescript@5.5.3))': dependencies: - vite: 5.2.11(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3) - vue: 3.4.26(typescript@5.4.5) + vite: 5.3.2(@types/node@20.14.9)(sass@1.77.6)(terser@5.31.2) + vue: 3.4.31(typescript@5.5.3) - '@vitest/coverage-v8@0.34.6(vitest@0.34.6(happy-dom@10.0.3)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3))': + '@vitest/coverage-v8@1.6.0(vitest@1.6.0(@types/node@20.14.9)(happy-dom@10.0.3)(jsdom@24.1.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))(sass@1.77.6)(terser@5.31.2))': dependencies: '@ampproject/remapping': 2.2.1 '@bcoe/v8-coverage': 0.2.3 + debug: 4.3.4(supports-color@5.5.0) istanbul-lib-coverage: 3.2.2 istanbul-lib-report: 3.0.1 - istanbul-lib-source-maps: 4.0.1 + istanbul-lib-source-maps: 5.0.4 istanbul-reports: 3.1.6 - magic-string: 0.30.7 + magic-string: 0.30.10 + magicast: 0.3.4 picocolors: 1.0.0 std-env: 3.7.0 + strip-literal: 2.1.0 test-exclude: 6.0.0 - v8-to-istanbul: 9.2.0 - vitest: 0.34.6(happy-dom@10.0.3)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3) + vitest: 1.6.0(@types/node@20.14.9)(happy-dom@10.0.3)(jsdom@24.1.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))(sass@1.77.6)(terser@5.31.2) transitivePeerDependencies: - supports-color - '@vitest/expect@0.34.6': + '@vitest/expect@1.6.0': dependencies: - '@vitest/spy': 0.34.6 - '@vitest/utils': 0.34.6 + '@vitest/spy': 1.6.0 + '@vitest/utils': 1.6.0 chai: 4.3.10 - '@vitest/expect@1.3.1': + '@vitest/runner@1.6.0': dependencies: - '@vitest/spy': 1.3.1 - '@vitest/utils': 1.3.1 - chai: 4.3.10 - - '@vitest/runner@0.34.6': - dependencies: - '@vitest/utils': 0.34.6 - p-limit: 4.0.0 + '@vitest/utils': 1.6.0 + p-limit: 5.0.0 pathe: 1.1.2 - '@vitest/snapshot@0.34.6': + '@vitest/snapshot@1.6.0': dependencies: - magic-string: 0.30.7 + magic-string: 0.30.10 pathe: 1.1.2 pretty-format: 29.7.0 - '@vitest/spy@0.34.6': - dependencies: - tinyspy: 2.2.0 - - '@vitest/spy@1.3.1': - dependencies: - tinyspy: 2.2.0 - '@vitest/spy@1.6.0': dependencies: tinyspy: 2.2.0 - '@vitest/utils@0.34.6': - dependencies: - diff-sequences: 29.6.3 - loupe: 2.3.7 - pretty-format: 29.7.0 - - '@vitest/utils@1.3.1': - dependencies: - diff-sequences: 29.6.3 - estree-walker: 3.0.3 - loupe: 2.3.7 - pretty-format: 29.7.0 - '@vitest/utils@1.6.0': dependencies: diff-sequences: 29.6.3 @@ -16531,125 +17771,136 @@ snapshots: dependencies: '@volar/source-map': 2.2.0 + '@volar/language-core@2.4.0-alpha.11': + dependencies: + '@volar/source-map': 2.4.0-alpha.11 + '@volar/source-map@2.2.0': dependencies: muggle-string: 0.4.1 + '@volar/source-map@2.4.0-alpha.11': {} + '@volar/typescript@2.2.0': dependencies: '@volar/language-core': 2.2.0 path-browserify: 1.0.1 - '@vue/compiler-core@3.4.21': + '@volar/typescript@2.4.0-alpha.11': dependencies: - '@babel/parser': 7.24.0 - '@vue/shared': 3.4.21 - entities: 4.5.0 - estree-walker: 2.0.2 - source-map-js: 1.0.2 + '@volar/language-core': 2.4.0-alpha.11 + path-browserify: 1.0.1 + vscode-uri: 3.0.8 - '@vue/compiler-core@3.4.25': + '@vue/compiler-core@3.4.29': dependencies: - '@babel/parser': 7.24.5 - '@vue/shared': 3.4.25 + '@babel/parser': 7.24.7 + '@vue/shared': 3.4.29 entities: 4.5.0 estree-walker: 2.0.2 source-map-js: 1.2.0 - '@vue/compiler-core@3.4.26': + '@vue/compiler-core@3.4.31': dependencies: - '@babel/parser': 7.24.5 - '@vue/shared': 3.4.26 + '@babel/parser': 7.24.7 + '@vue/shared': 3.4.31 entities: 4.5.0 estree-walker: 2.0.2 source-map-js: 1.2.0 - '@vue/compiler-dom@3.4.21': + '@vue/compiler-dom@3.4.29': dependencies: - '@vue/compiler-core': 3.4.21 - '@vue/shared': 3.4.21 + '@vue/compiler-core': 3.4.29 + '@vue/shared': 3.4.29 - '@vue/compiler-dom@3.4.25': + '@vue/compiler-dom@3.4.31': dependencies: - '@vue/compiler-core': 3.4.25 - '@vue/shared': 3.4.25 + '@vue/compiler-core': 3.4.31 + '@vue/shared': 3.4.31 - '@vue/compiler-dom@3.4.26': + '@vue/compiler-sfc@3.4.31': dependencies: - '@vue/compiler-core': 3.4.26 - '@vue/shared': 3.4.26 - - '@vue/compiler-sfc@3.4.26': - dependencies: - '@babel/parser': 7.24.5 - '@vue/compiler-core': 3.4.26 - '@vue/compiler-dom': 3.4.26 - '@vue/compiler-ssr': 3.4.26 - '@vue/shared': 3.4.26 + '@babel/parser': 7.24.7 + '@vue/compiler-core': 3.4.31 + '@vue/compiler-dom': 3.4.31 + '@vue/compiler-ssr': 3.4.31 + '@vue/shared': 3.4.31 estree-walker: 2.0.2 magic-string: 0.30.10 postcss: 8.4.38 source-map-js: 1.2.0 - '@vue/compiler-ssr@3.4.26': + '@vue/compiler-ssr@3.4.31': dependencies: - '@vue/compiler-dom': 3.4.26 - '@vue/shared': 3.4.26 + '@vue/compiler-dom': 3.4.31 + '@vue/shared': 3.4.31 '@vue/devtools-api@6.6.1': {} - '@vue/language-core@2.0.16(typescript@5.4.5)': + '@vue/language-core@2.0.16(typescript@5.5.3)': dependencies: '@volar/language-core': 2.2.0 - '@vue/compiler-dom': 3.4.25 - '@vue/shared': 3.4.25 + '@vue/compiler-dom': 3.4.29 + '@vue/shared': 3.4.29 computeds: 0.0.1 minimatch: 9.0.4 path-browserify: 1.0.1 vue-template-compiler: 2.7.14 optionalDependencies: - typescript: 5.4.5 + typescript: 5.5.3 - '@vue/reactivity@3.4.26': + '@vue/language-core@2.0.24(typescript@5.5.3)': dependencies: - '@vue/shared': 3.4.26 + '@volar/language-core': 2.4.0-alpha.11 + '@vue/compiler-dom': 3.4.29 + '@vue/shared': 3.4.29 + computeds: 0.0.1 + minimatch: 9.0.4 + muggle-string: 0.4.1 + path-browserify: 1.0.1 + vue-template-compiler: 2.7.14 + optionalDependencies: + typescript: 5.5.3 - '@vue/runtime-core@3.4.26': + '@vue/reactivity@3.4.31': dependencies: - '@vue/reactivity': 3.4.26 - '@vue/shared': 3.4.26 + '@vue/shared': 3.4.31 - '@vue/runtime-dom@3.4.26': + '@vue/runtime-core@3.4.31': dependencies: - '@vue/runtime-core': 3.4.26 - '@vue/shared': 3.4.26 + '@vue/reactivity': 3.4.31 + '@vue/shared': 3.4.31 + + '@vue/runtime-dom@3.4.31': + dependencies: + '@vue/reactivity': 3.4.31 + '@vue/runtime-core': 3.4.31 + '@vue/shared': 3.4.31 csstype: 3.1.3 - '@vue/server-renderer@3.4.26(vue@3.4.26(typescript@5.4.5))': + '@vue/server-renderer@3.4.31(vue@3.4.31(typescript@5.5.3))': dependencies: - '@vue/compiler-ssr': 3.4.26 - '@vue/shared': 3.4.26 - vue: 3.4.26(typescript@5.4.5) + '@vue/compiler-ssr': 3.4.31 + '@vue/shared': 3.4.31 + vue: 3.4.31(typescript@5.5.3) - '@vue/shared@3.4.21': {} + '@vue/shared@3.4.29': {} - '@vue/shared@3.4.25': {} + '@vue/shared@3.4.31': {} - '@vue/shared@3.4.26': {} - - '@vue/test-utils@2.4.1(@vue/server-renderer@3.4.26(vue@3.4.26(typescript@5.4.5)))(vue@3.4.26(typescript@5.4.5))': + '@vue/test-utils@2.4.1(@vue/server-renderer@3.4.31(vue@3.4.31(typescript@5.5.3)))(vue@3.4.31(typescript@5.5.3))': dependencies: js-beautify: 1.14.9 - vue: 3.4.26(typescript@5.4.5) + vue: 3.4.31(typescript@5.5.3) vue-component-type-helpers: 1.8.4 optionalDependencies: - '@vue/server-renderer': 3.4.26(vue@3.4.26(typescript@5.4.5)) + '@vue/server-renderer': 3.4.31(vue@3.4.31(typescript@5.5.3)) - '@webgpu/types@0.1.30': {} + '@webgpu/types@0.1.38': {} - '@yarnpkg/esbuild-plugin-pnp@3.0.0-rc.15(esbuild@0.20.2)': + '@yarnpkg/esbuild-plugin-pnp@3.0.0-rc.15(esbuild@0.19.11)': dependencies: - esbuild: 0.20.2 + esbuild: 0.19.11 tslib: 2.6.2 '@yarnpkg/fslib@2.10.3': @@ -16677,22 +17928,22 @@ snapshots: mime-types: 2.1.35 negotiator: 0.6.3 - acorn-import-assertions@1.9.0(acorn@8.11.3): + acorn-import-assertions@1.9.0(acorn@8.12.0): dependencies: - acorn: 8.11.3 + acorn: 8.12.0 optional: true - acorn-import-attributes@1.9.5(acorn@8.11.3): + acorn-import-attributes@1.9.5(acorn@8.12.0): dependencies: - acorn: 8.11.3 + acorn: 8.12.0 acorn-jsx@5.3.2(acorn@7.4.1): dependencies: acorn: 7.4.1 - acorn-jsx@5.3.2(acorn@8.11.3): + acorn-jsx@5.3.2(acorn@8.12.0): dependencies: - acorn: 8.11.3 + acorn: 8.12.0 acorn-walk@7.2.0: {} @@ -16700,7 +17951,7 @@ snapshots: acorn@7.4.1: {} - acorn@8.11.3: {} + acorn@8.12.0: {} address@1.2.2: {} @@ -16714,13 +17965,13 @@ snapshots: agent-base@6.0.2: dependencies: - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.5(supports-color@8.1.1) transitivePeerDependencies: - supports-color agent-base@7.1.0: dependencies: - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.5(supports-color@8.1.1) transitivePeerDependencies: - supports-color @@ -16734,7 +17985,7 @@ snapshots: clean-stack: 5.2.0 indent-string: 5.0.0 - aiscript-vscode@https://codeload.github.com/aiscript-dev/aiscript-vscode/tar.gz/34bf4e1530efcf1efa855bd04e2dab39735e1b02: + aiscript-vscode@https://codeload.github.com/aiscript-dev/aiscript-vscode/tar.gz/e1e1b27f2f72cd28a473e004b6da0d8fc0bd40d9: dependencies: '@aiscript-dev/aiscript-languageserver': https://github.com/aiscript-dev/aiscript-languageserver/releases/download/0.1.6/aiscript-dev-aiscript-languageserver-0.1.6.tgz vscode-languageclient: 9.0.1 @@ -16743,7 +17994,15 @@ snapshots: optionalDependencies: ajv: 8.13.0 - ajv-formats@2.1.1(ajv@8.13.0): + ajv-draft-04@1.0.0(ajv@8.16.0): + optionalDependencies: + ajv: 8.16.0 + + ajv-formats@2.1.1(ajv@8.16.0): + optionalDependencies: + ajv: 8.16.0 + + ajv-formats@3.0.1(ajv@8.13.0): optionalDependencies: ajv: 8.13.0 @@ -16754,6 +18013,13 @@ snapshots: json-schema-traverse: 0.4.1 uri-js: 4.4.1 + ajv@8.12.0: + dependencies: + fast-deep-equal: 3.1.3 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + uri-js: 4.4.1 + ajv@8.13.0: dependencies: fast-deep-equal: 3.1.3 @@ -16761,6 +18027,13 @@ snapshots: require-from-string: 2.0.2 uri-js: 4.4.1 + ajv@8.16.0: + dependencies: + fast-deep-equal: 3.1.3 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + uri-js: 4.4.1 + ansi-colors@4.1.3: {} ansi-escapes@4.3.2: @@ -16803,7 +18076,7 @@ snapshots: archiver-utils@5.0.2: dependencies: - glob: 10.3.12 + glob: 10.4.2 graceful-fs: 4.2.11 is-stream: 2.0.1 lazystream: 1.0.1 @@ -16837,10 +18110,18 @@ snapshots: argparse@2.0.1: {} + aria-hidden@1.2.4: + dependencies: + tslib: 2.6.2 + aria-query@5.1.3: dependencies: deep-equal: 2.2.0 + aria-query@5.3.0: + dependencies: + dequal: 2.0.3 + array-buffer-byte-length@1.0.0: dependencies: call-bind: 1.0.2 @@ -16936,6 +18217,8 @@ snapshots: dependencies: tslib: 2.6.2 + async@0.2.10: {} + async@3.2.4: {} asynckit@0.4.0: {} @@ -16950,12 +18233,12 @@ snapshots: dependencies: '@fastify/error': 3.4.0 archy: 1.0.0 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.5(supports-color@8.1.1) fastq: 1.17.1 transitivePeerDependencies: - supports-color - aws-sdk-client-mock@3.0.1: + aws-sdk-client-mock@4.0.1: dependencies: '@types/sinon': 10.0.13 sinon: 16.1.3 @@ -16967,13 +18250,13 @@ snapshots: axios@0.24.0: dependencies: - follow-redirects: 1.15.2(debug@4.3.4) + follow-redirects: 1.15.2(debug@4.3.5) transitivePeerDependencies: - debug - axios@1.6.2(debug@4.3.4): + axios@1.6.2(debug@4.3.5): dependencies: - follow-redirects: 1.15.2(debug@4.3.4) + follow-redirects: 1.15.2(debug@4.3.5) form-data: 4.0.0 proxy-from-env: 1.1.0 transitivePeerDependencies: @@ -16981,9 +18264,9 @@ snapshots: b4a@1.6.4: {} - babel-core@7.0.0-bridge.0(@babel/core@7.24.0): + babel-core@7.0.0-bridge.0(@babel/core@7.24.7): dependencies: - '@babel/core': 7.24.0 + '@babel/core': 7.24.7 babel-jest@29.7.0(@babel/core@7.23.5): dependencies: @@ -17011,31 +18294,31 @@ snapshots: babel-plugin-jest-hoist@29.6.3: dependencies: '@babel/template': 7.24.0 - '@babel/types': 7.24.0 + '@babel/types': 7.24.7 '@types/babel__core': 7.20.0 '@types/babel__traverse': 7.20.0 - babel-plugin-polyfill-corejs2@0.4.6(@babel/core@7.24.0): + babel-plugin-polyfill-corejs2@0.4.11(@babel/core@7.24.7): dependencies: - '@babel/compat-data': 7.23.5 - '@babel/core': 7.24.0 - '@babel/helper-define-polyfill-provider': 0.4.3(@babel/core@7.24.0) + '@babel/compat-data': 7.24.7 + '@babel/core': 7.24.7 + '@babel/helper-define-polyfill-provider': 0.6.2(@babel/core@7.24.7) semver: 6.3.1 transitivePeerDependencies: - supports-color - babel-plugin-polyfill-corejs3@0.8.6(@babel/core@7.24.0): + babel-plugin-polyfill-corejs3@0.10.4(@babel/core@7.24.7): dependencies: - '@babel/core': 7.24.0 - '@babel/helper-define-polyfill-provider': 0.4.3(@babel/core@7.24.0) - core-js-compat: 3.33.3 + '@babel/core': 7.24.7 + '@babel/helper-define-polyfill-provider': 0.6.2(@babel/core@7.24.7) + core-js-compat: 3.37.1 transitivePeerDependencies: - supports-color - babel-plugin-polyfill-regenerator@0.5.3(@babel/core@7.24.0): + babel-plugin-polyfill-regenerator@0.6.2(@babel/core@7.24.7): dependencies: - '@babel/core': 7.24.0 - '@babel/helper-define-polyfill-provider': 0.4.3(@babel/core@7.24.0) + '@babel/core': 7.24.7 + '@babel/helper-define-polyfill-provider': 0.6.2(@babel/core@7.24.7) transitivePeerDependencies: - supports-color @@ -17063,7 +18346,7 @@ snapshots: babel-walk@3.0.0-canary-5: dependencies: - '@babel/types': 7.23.5 + '@babel/types': 7.24.0 bail@2.0.2: {} @@ -17115,23 +18398,6 @@ snapshots: bn.js@4.12.0: {} - body-parser@1.20.1: - dependencies: - bytes: 3.1.2 - content-type: 1.0.5 - debug: 2.6.9 - depd: 2.0.0 - destroy: 1.2.0 - http-errors: 2.0.0 - iconv-lite: 0.4.24 - on-finished: 2.4.1 - qs: 6.11.0 - raw-body: 2.5.1 - type-is: 1.6.18 - unpipe: 1.0.0 - transitivePeerDependencies: - - supports-color - body-parser@1.20.2: dependencies: bytes: 3.1.2 @@ -17170,6 +18436,10 @@ snapshots: dependencies: fill-range: 7.0.1 + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + broadcast-channel@7.0.0: dependencies: '@babel/runtime': 7.23.4 @@ -17224,12 +18494,12 @@ snapshots: base64-js: 1.5.1 ieee754: 1.2.1 - bufferutil@4.0.7: + bufferutil@4.0.8: dependencies: node-gyp-build: 4.6.0 optional: true - bullmq@5.7.8: + bullmq@5.8.3: dependencies: cron-parser: 4.8.1 ioredis: 5.4.1 @@ -17256,10 +18526,10 @@ snapshots: cacache@18.0.0: dependencies: '@npmcli/fs': 3.1.0 - fs-minipass: 3.0.2 - glob: 10.3.12 - lru-cache: 10.0.2 - minipass: 7.0.4 + fs-minipass: 3.0.3 + glob: 10.4.2 + lru-cache: 10.2.2 + minipass: 7.1.2 minipass-collect: 1.0.2 minipass-flush: 1.0.5 minipass-pipeline: 1.2.4 @@ -17282,6 +18552,16 @@ snapshots: normalize-url: 8.0.0 responselike: 3.0.0 + cacheable-request@12.0.1: + dependencies: + '@types/http-cache-semantics': 4.0.4 + get-stream: 9.0.1 + http-cache-semantics: 4.1.1 + keyv: 4.5.4 + mimic-response: 4.0.0 + normalize-url: 8.0.1 + responselike: 3.0.0 + cacheable-request@7.0.2: dependencies: clone-response: 1.0.3 @@ -17376,26 +18656,26 @@ snapshots: dependencies: is-regex: 1.1.4 - chart.js@4.4.2: + chart.js@4.4.3: dependencies: '@kurkle/color': 0.3.2 - chartjs-adapter-date-fns@3.0.0(chart.js@4.4.2)(date-fns@2.30.0): + chartjs-adapter-date-fns@3.0.0(chart.js@4.4.3)(date-fns@2.30.0): dependencies: - chart.js: 4.4.2 + chart.js: 4.4.3 date-fns: 2.30.0 - chartjs-chart-matrix@2.0.1(chart.js@4.4.2): + chartjs-chart-matrix@2.0.1(chart.js@4.4.3): dependencies: - chart.js: 4.4.2 + chart.js: 4.4.3 - chartjs-plugin-gradient@0.6.1(chart.js@4.4.2): + chartjs-plugin-gradient@0.6.1(chart.js@4.4.3): dependencies: - chart.js: 4.4.2 + chart.js: 4.4.3 - chartjs-plugin-zoom@2.0.1(chart.js@4.4.2): + chartjs-plugin-zoom@2.0.1(chart.js@4.4.3): dependencies: - chart.js: 4.4.2 + chart.js: 4.4.3 hammerjs: 2.0.8 check-error@1.0.3: @@ -17439,7 +18719,7 @@ snapshots: chownr@2.0.0: {} - chromatic@11.3.0: {} + chromatic@11.5.4: {} ci-info@3.7.1: {} @@ -17464,8 +18744,6 @@ snapshots: parse5-htmlparser2-tree-adapter: 6.0.1 yargs: 16.2.0 - cli-spinners@2.7.0: {} - cli-spinners@2.9.2: {} cli-table3@0.6.3: @@ -17617,8 +18895,8 @@ snapshots: constantinople@4.0.1: dependencies: - '@babel/parser': 7.23.9 - '@babel/types': 7.23.5 + '@babel/parser': 7.24.5 + '@babel/types': 7.24.0 content-disposition@0.5.4: dependencies: @@ -17636,7 +18914,7 @@ snapshots: cookie@0.6.0: {} - core-js-compat@3.33.3: + core-js-compat@3.37.1: dependencies: browserslist: 4.23.0 @@ -17658,13 +18936,13 @@ snapshots: crc-32: 1.2.2 readable-stream: 4.3.0 - create-jest@29.7.0(@types/node@20.12.7): + create-jest@29.7.0(@types/node@20.14.9): dependencies: '@jest/types': 29.6.3 chalk: 4.1.2 exit: 0.1.2 graceful-fs: 4.2.11 - jest-config: 29.7.0(@types/node@20.12.7) + jest-config: 29.7.0(@types/node@20.14.9) jest-util: 29.7.0 prompts: 2.4.2 transitivePeerDependencies: @@ -17710,7 +18988,9 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 - crypto-random-string@2.0.0: {} + crypto-random-string@4.0.0: + dependencies: + type-fest: 1.4.0 css-declaration-sorter@7.2.0(postcss@8.4.38): dependencies: @@ -17798,7 +19078,7 @@ snapshots: dependencies: uniq: 1.0.1 - cypress@13.7.3: + cypress@13.13.0: dependencies: '@cypress/request': 3.0.0 '@cypress/xvfb': 1.2.4(supports-color@8.1.1) @@ -17816,52 +19096,7 @@ snapshots: commander: 6.2.1 common-tags: 1.8.2 dayjs: 1.11.10 - debug: 4.3.4(supports-color@8.1.1) - enquirer: 2.3.6 - eventemitter2: 6.4.7 - execa: 4.1.0 - executable: 4.1.1 - extract-zip: 2.0.1(supports-color@8.1.1) - figures: 3.2.0 - fs-extra: 9.1.0 - getos: 3.2.1 - is-ci: 3.0.1 - is-installed-globally: 0.4.0 - lazy-ass: 1.6.0 - listr2: 3.14.0(enquirer@2.3.6) - lodash: 4.17.21 - log-symbols: 4.1.0 - minimist: 1.2.8 - ospath: 1.2.2 - pretty-bytes: 5.6.0 - process: 0.11.10 - proxy-from-env: 1.0.0 - request-progress: 3.0.0 - semver: 7.6.0 - supports-color: 8.1.1 - tmp: 0.2.3 - untildify: 4.0.0 - yauzl: 2.10.0 - - cypress@13.8.1: - dependencies: - '@cypress/request': 3.0.0 - '@cypress/xvfb': 1.2.4(supports-color@8.1.1) - '@types/sinonjs__fake-timers': 8.1.1 - '@types/sizzle': 2.3.3 - arch: 2.2.0 - blob-util: 2.0.2 - bluebird: 3.7.2 - buffer: 5.7.1 - cachedir: 2.3.0 - chalk: 4.1.2 - check-more-types: 2.24.0 - cli-cursor: 3.1.0 - cli-table3: 0.6.3 - commander: 6.2.1 - common-tags: 1.8.2 - dayjs: 1.11.10 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.5(supports-color@8.1.1) enquirer: 2.3.6 eventemitter2: 6.4.7 execa: 4.1.0 @@ -17925,7 +19160,7 @@ snapshots: optionalDependencies: supports-color: 5.5.0 - debug@4.3.4(supports-color@8.1.1): + debug@4.3.5(supports-color@8.1.1): dependencies: ms: 2.1.2 optionalDependencies: @@ -18018,17 +19253,6 @@ snapshots: defu@6.1.4: {} - del@6.1.1: - dependencies: - globby: 11.1.0 - graceful-fs: 4.2.11 - is-glob: 4.0.3 - is-path-cwd: 2.2.0 - is-path-inside: 3.0.3 - p-map: 4.0.0 - rimraf: 3.0.2 - slash: 3.0.0 - delayed-stream@1.0.0: {} delegates@1.0.0: @@ -18051,6 +19275,8 @@ snapshots: detect-newline@3.1.0: {} + detect-node-es@1.1.0: {} + detect-package-manager@2.0.1: dependencies: execa: 5.1.1 @@ -18058,7 +19284,7 @@ snapshots: detect-port@1.5.1: dependencies: address: 1.2.2 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.5(supports-color@8.1.1) transitivePeerDependencies: - supports-color @@ -18072,6 +19298,8 @@ snapshots: diff@5.1.0: {} + diff@5.2.0: {} + dijkstrajs@1.0.2: {} dir-glob@3.0.1: @@ -18145,7 +19373,7 @@ snapshots: ee-first@1.1.1: {} - ejs@3.1.9: + ejs@3.1.10: dependencies: jake: 10.8.5 @@ -18244,7 +19472,7 @@ snapshots: isarray: 2.0.5 stop-iteration-iterator: 1.0.0 - es-module-lexer@0.9.3: {} + es-module-lexer@1.5.4: {} es-set-tostringtag@2.0.1: dependencies: @@ -18272,10 +19500,10 @@ snapshots: esbuild-plugin-alias@0.2.1: {} - esbuild-register@3.5.0(esbuild@0.20.2): + esbuild-register@3.5.0(esbuild@0.19.11): dependencies: - debug: 4.3.4(supports-color@8.1.1) - esbuild: 0.20.2 + debug: 4.3.5(supports-color@8.1.1) + esbuild: 0.19.11 transitivePeerDependencies: - supports-color @@ -18330,31 +19558,58 @@ snapshots: '@esbuild/win32-ia32': 0.19.11 '@esbuild/win32-x64': 0.19.11 - esbuild@0.20.2: + esbuild@0.21.5: optionalDependencies: - '@esbuild/aix-ppc64': 0.20.2 - '@esbuild/android-arm': 0.20.2 - '@esbuild/android-arm64': 0.20.2 - '@esbuild/android-x64': 0.20.2 - '@esbuild/darwin-arm64': 0.20.2 - '@esbuild/darwin-x64': 0.20.2 - '@esbuild/freebsd-arm64': 0.20.2 - '@esbuild/freebsd-x64': 0.20.2 - '@esbuild/linux-arm': 0.20.2 - '@esbuild/linux-arm64': 0.20.2 - '@esbuild/linux-ia32': 0.20.2 - '@esbuild/linux-loong64': 0.20.2 - '@esbuild/linux-mips64el': 0.20.2 - '@esbuild/linux-ppc64': 0.20.2 - '@esbuild/linux-riscv64': 0.20.2 - '@esbuild/linux-s390x': 0.20.2 - '@esbuild/linux-x64': 0.20.2 - '@esbuild/netbsd-x64': 0.20.2 - '@esbuild/openbsd-x64': 0.20.2 - '@esbuild/sunos-x64': 0.20.2 - '@esbuild/win32-arm64': 0.20.2 - '@esbuild/win32-ia32': 0.20.2 - '@esbuild/win32-x64': 0.20.2 + '@esbuild/aix-ppc64': 0.21.5 + '@esbuild/android-arm': 0.21.5 + '@esbuild/android-arm64': 0.21.5 + '@esbuild/android-x64': 0.21.5 + '@esbuild/darwin-arm64': 0.21.5 + '@esbuild/darwin-x64': 0.21.5 + '@esbuild/freebsd-arm64': 0.21.5 + '@esbuild/freebsd-x64': 0.21.5 + '@esbuild/linux-arm': 0.21.5 + '@esbuild/linux-arm64': 0.21.5 + '@esbuild/linux-ia32': 0.21.5 + '@esbuild/linux-loong64': 0.21.5 + '@esbuild/linux-mips64el': 0.21.5 + '@esbuild/linux-ppc64': 0.21.5 + '@esbuild/linux-riscv64': 0.21.5 + '@esbuild/linux-s390x': 0.21.5 + '@esbuild/linux-x64': 0.21.5 + '@esbuild/netbsd-x64': 0.21.5 + '@esbuild/openbsd-x64': 0.21.5 + '@esbuild/sunos-x64': 0.21.5 + '@esbuild/win32-arm64': 0.21.5 + '@esbuild/win32-ia32': 0.21.5 + '@esbuild/win32-x64': 0.21.5 + + esbuild@0.22.0: + optionalDependencies: + '@esbuild/aix-ppc64': 0.22.0 + '@esbuild/android-arm': 0.22.0 + '@esbuild/android-arm64': 0.22.0 + '@esbuild/android-x64': 0.22.0 + '@esbuild/darwin-arm64': 0.22.0 + '@esbuild/darwin-x64': 0.22.0 + '@esbuild/freebsd-arm64': 0.22.0 + '@esbuild/freebsd-x64': 0.22.0 + '@esbuild/linux-arm': 0.22.0 + '@esbuild/linux-arm64': 0.22.0 + '@esbuild/linux-ia32': 0.22.0 + '@esbuild/linux-loong64': 0.22.0 + '@esbuild/linux-mips64el': 0.22.0 + '@esbuild/linux-ppc64': 0.22.0 + '@esbuild/linux-riscv64': 0.22.0 + '@esbuild/linux-s390x': 0.22.0 + '@esbuild/linux-x64': 0.22.0 + '@esbuild/netbsd-x64': 0.22.0 + '@esbuild/openbsd-arm64': 0.22.0 + '@esbuild/openbsd-x64': 0.22.0 + '@esbuild/sunos-x64': 0.22.0 + '@esbuild/win32-arm64': 0.22.0 + '@esbuild/win32-ia32': 0.22.0 + '@esbuild/win32-x64': 0.22.0 escalade@3.1.1: {} @@ -18397,37 +19652,27 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.8.0(@typescript-eslint/parser@6.11.0(eslint@8.53.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint@8.53.0): + eslint-module-utils@2.8.0(@typescript-eslint/parser@7.15.0(eslint@9.6.0)(typescript@5.5.3))(eslint-import-resolver-node@0.3.9)(eslint@9.6.0): dependencies: debug: 3.2.7(supports-color@8.1.1) optionalDependencies: - '@typescript-eslint/parser': 6.11.0(eslint@8.53.0)(typescript@5.3.3) - eslint: 8.53.0 + '@typescript-eslint/parser': 7.15.0(eslint@9.6.0)(typescript@5.5.3) + eslint: 9.6.0 eslint-import-resolver-node: 0.3.9 transitivePeerDependencies: - supports-color - eslint-module-utils@2.8.0(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint@8.57.0): + eslint-module-utils@2.8.0(@typescript-eslint/parser@7.15.0(eslint@9.7.0)(typescript@5.5.3))(eslint-import-resolver-node@0.3.9)(eslint@9.7.0): dependencies: debug: 3.2.7(supports-color@8.1.1) optionalDependencies: - '@typescript-eslint/parser': 7.1.0(eslint@8.57.0)(typescript@5.3.3) - eslint: 8.57.0 + '@typescript-eslint/parser': 7.15.0(eslint@9.7.0)(typescript@5.5.3) + eslint: 9.7.0 eslint-import-resolver-node: 0.3.9 transitivePeerDependencies: - supports-color - eslint-module-utils@2.8.0(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint@8.57.0): - dependencies: - debug: 3.2.7(supports-color@8.1.1) - optionalDependencies: - '@typescript-eslint/parser': 7.7.1(eslint@8.57.0)(typescript@5.4.5) - eslint: 8.57.0 - eslint-import-resolver-node: 0.3.9 - transitivePeerDependencies: - - supports-color - - eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.11.0(eslint@8.53.0)(typescript@5.3.3))(eslint@8.53.0): + eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.15.0(eslint@9.6.0)(typescript@5.5.3))(eslint@9.6.0): dependencies: array-includes: 3.1.7 array.prototype.findlastindex: 1.2.3 @@ -18435,9 +19680,9 @@ snapshots: array.prototype.flatmap: 1.3.2 debug: 3.2.7(supports-color@8.1.1) doctrine: 2.1.0 - eslint: 8.53.0 + eslint: 9.6.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.11.0(eslint@8.53.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint@8.53.0) + eslint-module-utils: 2.8.0(@typescript-eslint/parser@7.15.0(eslint@9.6.0)(typescript@5.5.3))(eslint-import-resolver-node@0.3.9)(eslint@9.6.0) hasown: 2.0.0 is-core-module: 2.13.1 is-glob: 4.0.3 @@ -18448,13 +19693,13 @@ snapshots: semver: 6.3.1 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 6.11.0(eslint@8.53.0)(typescript@5.3.3) + '@typescript-eslint/parser': 7.15.0(eslint@9.6.0)(typescript@5.5.3) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack - supports-color - eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint@8.57.0): + eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.15.0(eslint@9.7.0)(typescript@5.5.3))(eslint@9.7.0): dependencies: array-includes: 3.1.7 array.prototype.findlastindex: 1.2.3 @@ -18462,9 +19707,9 @@ snapshots: array.prototype.flatmap: 1.3.2 debug: 3.2.7(supports-color@8.1.1) doctrine: 2.1.0 - eslint: 8.57.0 + eslint: 9.7.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint@8.57.0) + eslint-module-utils: 2.8.0(@typescript-eslint/parser@7.15.0(eslint@9.7.0)(typescript@5.5.3))(eslint-import-resolver-node@0.3.9)(eslint@9.7.0) hasown: 2.0.0 is-core-module: 2.13.1 is-glob: 4.0.3 @@ -18475,49 +19720,22 @@ snapshots: semver: 6.3.1 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 7.1.0(eslint@8.57.0)(typescript@5.3.3) + '@typescript-eslint/parser': 7.15.0(eslint@9.7.0)(typescript@5.5.3) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack - supports-color - eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0): + eslint-plugin-vue@9.26.0(eslint@9.7.0): dependencies: - array-includes: 3.1.7 - array.prototype.findlastindex: 1.2.3 - array.prototype.flat: 1.3.2 - array.prototype.flatmap: 1.3.2 - debug: 3.2.7(supports-color@8.1.1) - doctrine: 2.1.0 - eslint: 8.57.0 - eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@7.7.1(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint@8.57.0) - hasown: 2.0.0 - is-core-module: 2.13.1 - is-glob: 4.0.3 - minimatch: 3.1.2 - object.fromentries: 2.0.7 - object.groupby: 1.0.1 - object.values: 1.1.7 - semver: 6.3.1 - tsconfig-paths: 3.15.0 - optionalDependencies: - '@typescript-eslint/parser': 7.7.1(eslint@8.57.0)(typescript@5.4.5) - transitivePeerDependencies: - - eslint-import-resolver-typescript - - eslint-import-resolver-webpack - - supports-color - - eslint-plugin-vue@9.25.0(eslint@8.57.0): - dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) - eslint: 8.57.0 + '@eslint-community/eslint-utils': 4.4.0(eslint@9.7.0) + eslint: 9.7.0 globals: 13.24.0 natural-compare: 1.4.0 nth-check: 2.1.1 - postcss-selector-parser: 6.0.15 + postcss-selector-parser: 6.0.16 semver: 7.6.0 - vue-eslint-parser: 9.4.2(eslint@8.57.0) + vue-eslint-parser: 9.4.3(eslint@9.7.0) xml-name-validator: 4.0.0 transitivePeerDependencies: - supports-color @@ -18529,40 +19747,48 @@ snapshots: esrecurse: 4.3.0 estraverse: 5.3.0 + eslint-scope@8.0.1: + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + + eslint-scope@8.0.2: + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + eslint-visitor-keys@3.4.3: {} - eslint@8.53.0: + eslint-visitor-keys@4.0.0: {} + + eslint@9.6.0: dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.53.0) - '@eslint-community/regexpp': 4.6.2 - '@eslint/eslintrc': 2.1.4 - '@eslint/js': 8.53.0 - '@humanwhocodes/config-array': 0.11.13 + '@eslint-community/eslint-utils': 4.4.0(eslint@9.6.0) + '@eslint-community/regexpp': 4.10.0 + '@eslint/config-array': 0.17.0 + '@eslint/eslintrc': 3.1.0 + '@eslint/js': 9.6.0 '@humanwhocodes/module-importer': 1.0.1 + '@humanwhocodes/retry': 0.3.0 '@nodelib/fs.walk': 1.2.8 - '@ungap/structured-clone': 1.2.0 ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.3 - debug: 4.3.4(supports-color@8.1.1) - doctrine: 3.0.0 + debug: 4.3.5(supports-color@8.1.1) escape-string-regexp: 4.0.0 - eslint-scope: 7.2.2 - eslint-visitor-keys: 3.4.3 - espree: 9.6.1 - esquery: 1.4.2 + eslint-scope: 8.0.1 + eslint-visitor-keys: 4.0.0 + espree: 10.1.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.19.0 - graphemer: 1.4.0 - ignore: 5.2.4 + ignore: 5.3.1 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 @@ -18574,53 +19800,55 @@ snapshots: transitivePeerDependencies: - supports-color - eslint@8.57.0: + eslint@9.7.0: dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) - '@eslint-community/regexpp': 4.6.2 - '@eslint/eslintrc': 2.1.4 - '@eslint/js': 8.57.0 - '@humanwhocodes/config-array': 0.11.14 + '@eslint-community/eslint-utils': 4.4.0(eslint@9.7.0) + '@eslint-community/regexpp': 4.11.0 + '@eslint/config-array': 0.17.0 + '@eslint/eslintrc': 3.1.0 + '@eslint/js': 9.7.0 '@humanwhocodes/module-importer': 1.0.1 + '@humanwhocodes/retry': 0.3.0 '@nodelib/fs.walk': 1.2.8 - '@ungap/structured-clone': 1.2.0 ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.3 - debug: 4.3.4(supports-color@8.1.1) - doctrine: 3.0.0 + debug: 4.3.5(supports-color@8.1.1) escape-string-regexp: 4.0.0 - eslint-scope: 7.2.2 - eslint-visitor-keys: 3.4.3 - espree: 9.6.1 - esquery: 1.4.2 + eslint-scope: 8.0.2 + eslint-visitor-keys: 4.0.0 + espree: 10.1.0 + esquery: 1.6.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.19.0 - graphemer: 1.4.0 - ignore: 5.2.4 + ignore: 5.3.1 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 + optionator: 0.9.4 strip-ansi: 6.0.1 text-table: 0.2.0 transitivePeerDependencies: - supports-color + espree@10.1.0: + dependencies: + acorn: 8.12.0 + acorn-jsx: 5.3.2(acorn@8.12.0) + eslint-visitor-keys: 4.0.0 + espree@9.6.1: dependencies: - acorn: 8.11.3 - acorn-jsx: 5.3.2(acorn@8.11.3) + acorn: 8.12.0 + acorn-jsx: 5.3.2(acorn@8.12.0) eslint-visitor-keys: 3.4.3 esprima@4.0.1: {} @@ -18629,6 +19857,14 @@ snapshots: dependencies: estraverse: 5.3.0 + esquery@1.5.0: + dependencies: + estraverse: 5.3.0 + + esquery@1.6.0: + dependencies: + estraverse: 5.3.0 + esrecurse@4.3.0: dependencies: estraverse: 5.3.0 @@ -18723,6 +19959,21 @@ snapshots: signal-exit: 4.1.0 strip-final-newline: 3.0.0 + execa@9.2.0: + dependencies: + '@sindresorhus/merge-streams': 4.0.0 + cross-spawn: 7.0.3 + figures: 6.1.0 + get-stream: 9.0.1 + human-signals: 7.0.0 + is-plain-obj: 4.1.0 + is-stream: 4.0.1 + npm-run-path: 5.3.0 + pretty-ms: 9.0.0 + signal-exit: 4.1.0 + strip-final-newline: 4.0.0 + yoctocolors: 2.0.2 + executable@4.1.1: dependencies: pify: 2.3.0 @@ -18739,42 +19990,6 @@ snapshots: exponential-backoff@3.1.1: {} - express@4.18.2: - dependencies: - accepts: 1.3.8 - array-flatten: 1.1.1 - body-parser: 1.20.1 - content-disposition: 0.5.4 - content-type: 1.0.5 - cookie: 0.5.0 - cookie-signature: 1.0.6 - debug: 2.6.9 - depd: 2.0.0 - encodeurl: 1.0.2 - escape-html: 1.0.3 - etag: 1.8.1 - finalhandler: 1.2.0 - fresh: 0.5.2 - http-errors: 2.0.0 - merge-descriptors: 1.0.1 - methods: 1.1.2 - on-finished: 2.4.1 - parseurl: 1.3.3 - path-to-regexp: 0.1.7 - proxy-addr: 2.0.7 - qs: 6.11.0 - range-parser: 1.2.1 - safe-buffer: 5.2.1 - send: 0.18.0 - serve-static: 1.15.0 - setprototypeof: 1.2.0 - statuses: 2.0.1 - type-is: 1.6.18 - utils-merge: 1.0.1 - vary: 1.1.2 - transitivePeerDependencies: - - supports-color - express@4.19.2: dependencies: accepts: 1.3.8 @@ -18824,7 +20039,7 @@ snapshots: extract-zip@2.0.1(supports-color@8.1.1): dependencies: - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.5(supports-color@8.1.1) get-stream: 5.2.0 yauzl: 2.10.0 optionalDependencies: @@ -18848,15 +20063,15 @@ snapshots: '@nodelib/fs.walk': 1.2.8 glob-parent: 5.1.2 merge2: 1.4.1 - micromatch: 4.0.5 + micromatch: 4.0.7 fast-json-stable-stringify@2.1.0: {} fast-json-stringify@5.8.0: dependencies: '@fastify/deepmerge': 1.3.0 - ajv: 8.13.0 - ajv-formats: 2.1.1(ajv@8.13.0) + ajv: 8.16.0 + ajv-formats: 2.1.1(ajv@8.16.0) fast-deep-equal: 3.1.3 fast-uri: 2.2.0 rfdc: 1.3.0 @@ -18885,7 +20100,7 @@ snapshots: raw-body: 2.5.2 secure-json-parse: 2.7.0 - fastify@4.26.2: + fastify@4.28.1: dependencies: '@fastify/ajv-compiler': 3.5.0 '@fastify/error': 3.4.0 @@ -18896,20 +20111,16 @@ snapshots: fast-json-stringify: 5.8.0 find-my-way: 8.2.0 light-my-request: 5.11.0 - pino: 8.17.0 + pino: 9.2.0 process-warning: 3.0.0 proxy-addr: 2.0.7 rfdc: 1.3.0 secure-json-parse: 2.7.0 semver: 7.6.0 - toad-cache: 3.3.0 + toad-cache: 3.7.0 transitivePeerDependencies: - supports-color - fastq@1.15.0: - dependencies: - reusify: 1.0.4 - fastq@1.17.1: dependencies: reusify: 1.0.4 @@ -18937,9 +20148,13 @@ snapshots: dependencies: escape-string-regexp: 1.0.5 - file-entry-cache@6.0.1: + figures@6.1.0: dependencies: - flat-cache: 3.0.4 + is-unicode-supported: 2.0.0 + + file-entry-cache@8.0.0: + dependencies: + flat-cache: 4.0.1 file-system-cache@2.3.0: dependencies: @@ -18974,6 +20189,10 @@ snapshots: dependencies: to-regex-range: 5.0.1 + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + finalhandler@1.2.0: dependencies: debug: 2.6.9 @@ -19033,23 +20252,23 @@ snapshots: ps-list: 8.1.1 taskkill: 5.0.0 - flat-cache@3.0.4: + flat-cache@4.0.1: dependencies: - flatted: 3.2.7 - rimraf: 3.0.2 + flatted: 3.3.1 + keyv: 4.5.4 - flatted@3.2.7: {} + flatted@3.3.1: {} flow-parser@0.202.0: {} - fluent-ffmpeg@2.1.2: + fluent-ffmpeg@2.1.3: dependencies: - async: 3.2.4 + async: 0.2.10 which: 1.3.1 - follow-redirects@1.15.2(debug@4.3.4): + follow-redirects@1.15.2(debug@4.3.5): optionalDependencies: - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.5(supports-color@8.1.1) for-each@0.3.3: dependencies: @@ -19072,12 +20291,6 @@ snapshots: combined-stream: 1.0.8 mime-types: 2.1.35 - form-data@3.0.1: - dependencies: - asynckit: 0.4.0 - combined-stream: 1.0.8 - mime-types: 2.1.35 - form-data@4.0.0: dependencies: asynckit: 0.4.0 @@ -19121,18 +20334,13 @@ snapshots: jsonfile: 6.1.0 universalify: 2.0.0 - fs-minipass@1.2.7: - dependencies: - minipass: 2.9.0 - optional: true - fs-minipass@2.1.0: dependencies: minipass: 3.3.6 - fs-minipass@3.0.2: + fs-minipass@3.0.3: dependencies: - minipass: 5.0.0 + minipass: 7.1.2 fs.realpath@1.0.0: {} @@ -19176,6 +20384,8 @@ snapshots: has-proto: 1.0.1 has-symbols: 1.0.3 + get-nonce@1.0.1: {} + get-npm-tarball-url@2.0.3: {} get-package-type@0.1.0: {} @@ -19204,6 +20414,11 @@ snapshots: get-stream@8.0.1: {} + get-stream@9.0.1: + dependencies: + '@sec-ant/readable-stream': 0.4.1 + is-stream: 4.0.1 + get-symbol-description@1.0.0: dependencies: call-bind: 1.0.2 @@ -19270,6 +20485,15 @@ snapshots: minipass: 7.0.4 path-scurry: 1.10.2 + glob@10.4.2: + dependencies: + foreground-child: 3.1.1 + jackspeak: 3.4.0 + minimatch: 9.0.4 + minipass: 7.1.2 + package-json-from-dist: 1.0.0 + path-scurry: 1.11.1 + glob@7.2.3: dependencies: fs.realpath: 1.0.0 @@ -19293,14 +20517,14 @@ snapshots: globals@11.12.0: {} - globals@13.19.0: - dependencies: - type-fest: 0.20.2 - globals@13.24.0: dependencies: type-fest: 0.20.2 + globals@14.0.0: {} + + globals@15.7.0: {} + globalthis@1.0.3: dependencies: define-properties: 1.2.0 @@ -19314,6 +20538,15 @@ snapshots: merge2: 1.4.1 slash: 3.0.0 + globby@14.0.1: + dependencies: + '@sindresorhus/merge-streams': 2.3.0 + fast-glob: 3.3.2 + ignore: 5.3.1 + path-type: 5.0.0 + slash: 5.1.0 + unicorn-magic: 0.1.0 + google-protobuf@3.21.2: optional: true @@ -19349,12 +20582,12 @@ snapshots: p-cancelable: 3.0.0 responselike: 3.0.0 - got@14.2.1: + got@14.4.1: dependencies: - '@sindresorhus/is': 6.1.0 + '@sindresorhus/is': 6.3.1 '@szmarczak/http-timer': 5.0.1 cacheable-lookup: 7.0.0 - cacheable-request: 10.2.14 + cacheable-request: 12.0.1 decompress-response: 6.0.0 form-data-encoder: 4.0.2 get-stream: 8.0.1 @@ -19362,6 +20595,7 @@ snapshots: lowercase-keys: 3.0.0 p-cancelable: 4.0.1 responselike: 3.0.0 + type-fest: 4.20.1 graceful-fs@4.2.11: {} @@ -19504,7 +20738,14 @@ snapshots: http-proxy-agent@7.0.0: dependencies: agent-base: 7.1.0 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.5(supports-color@8.1.1) + transitivePeerDependencies: + - supports-color + + http-proxy-agent@7.0.2: + dependencies: + agent-base: 7.1.0 + debug: 4.3.4(supports-color@5.5.0) transitivePeerDependencies: - supports-color @@ -19543,14 +20784,21 @@ snapshots: https-proxy-agent@5.0.1: dependencies: agent-base: 6.0.2 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.5(supports-color@8.1.1) transitivePeerDependencies: - supports-color https-proxy-agent@7.0.2: dependencies: agent-base: 7.1.0 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.4(supports-color@5.5.0) + transitivePeerDependencies: + - supports-color + + https-proxy-agent@7.0.4: + dependencies: + agent-base: 7.1.0 + debug: 4.3.4(supports-color@5.5.0) transitivePeerDependencies: - supports-color @@ -19562,6 +20810,8 @@ snapshots: human-signals@5.0.0: {} + human-signals@7.0.0: {} + iconv-lite@0.4.24: dependencies: safer-buffer: 2.1.2 @@ -19593,16 +20843,16 @@ snapshots: import-in-the-middle@1.4.2: dependencies: - acorn: 8.11.3 - acorn-import-assertions: 1.9.0(acorn@8.11.3) + acorn: 8.12.0 + acorn-import-assertions: 1.9.0(acorn@8.12.0) cjs-module-lexer: 1.2.2 module-details-from-path: 1.0.3 optional: true - import-in-the-middle@1.7.4: + import-in-the-middle@1.8.1: dependencies: - acorn: 8.11.3 - acorn-import-attributes: 1.9.5(acorn@8.11.3) + acorn: 8.12.0 + acorn-import-attributes: 1.9.5(acorn@8.12.0) cjs-module-lexer: 1.2.2 module-details-from-path: 1.0.3 @@ -19642,11 +20892,15 @@ snapshots: intersection-observer@0.12.2: {} + invariant@2.2.4: + dependencies: + loose-envify: 1.4.0 + ioredis@5.4.1: dependencies: '@ioredis/commands': 1.2.0 cluster-key-slot: 1.1.2 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.4(supports-color@5.5.0) denque: 2.1.0 lodash.defaults: 4.2.0 lodash.isarguments: 3.1.0 @@ -19658,15 +20912,14 @@ snapshots: iota-array@1.0.0: {} - ip-address@7.1.0: + ip-address@9.0.5: dependencies: jsbn: 1.1.0 - sprintf-js: 1.1.2 + sprintf-js: 1.1.3 - ip-cidr@3.1.0: + ip-cidr@4.0.1: dependencies: - ip-address: 7.1.0 - jsbn: 1.1.0 + ip-address: 9.0.5 ip-regex@4.3.0: {} @@ -19781,8 +21034,6 @@ snapshots: is-number@7.0.0: {} - is-path-cwd@2.2.0: {} - is-path-inside@3.0.3: {} is-plain-obj@1.1.0: {} @@ -19816,11 +21067,13 @@ snapshots: is-stream@3.0.0: {} + is-stream@4.0.1: {} + is-string@1.0.7: dependencies: has-tostringtag: 1.0.0 - is-svg@5.0.0: + is-svg@5.0.1: dependencies: fast-xml-parser: 4.2.5 @@ -19840,6 +21093,8 @@ snapshots: is-unicode-supported@0.1.0: {} + is-unicode-supported@2.0.0: {} + is-weakmap@2.0.1: {} is-weakref@1.0.2: @@ -19873,8 +21128,8 @@ snapshots: istanbul-lib-instrument@5.2.1: dependencies: - '@babel/core': 7.24.0 - '@babel/parser': 7.24.0 + '@babel/core': 7.24.7 + '@babel/parser': 7.24.7 '@istanbuljs/schema': 0.1.3 istanbul-lib-coverage: 3.2.2 semver: 6.3.1 @@ -19883,8 +21138,8 @@ snapshots: istanbul-lib-instrument@6.0.0: dependencies: - '@babel/core': 7.24.0 - '@babel/parser': 7.24.0 + '@babel/core': 7.24.7 + '@babel/parser': 7.24.7 '@istanbuljs/schema': 0.1.3 istanbul-lib-coverage: 3.2.2 semver: 7.6.0 @@ -19899,12 +21154,20 @@ snapshots: istanbul-lib-source-maps@4.0.1: dependencies: - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.5(supports-color@8.1.1) istanbul-lib-coverage: 3.2.2 source-map: 0.6.1 transitivePeerDependencies: - supports-color + istanbul-lib-source-maps@5.0.4: + dependencies: + '@jridgewell/trace-mapping': 0.3.25 + debug: 4.3.5(supports-color@8.1.1) + istanbul-lib-coverage: 3.2.2 + transitivePeerDependencies: + - supports-color + istanbul-reports@3.1.6: dependencies: html-escaper: 2.0.2 @@ -19918,6 +21181,12 @@ snapshots: optionalDependencies: '@pkgjs/parseargs': 0.11.0 + jackspeak@3.4.0: + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + jake@10.8.5: dependencies: async: 3.2.4 @@ -19937,7 +21206,7 @@ snapshots: '@jest/expect': 29.7.0 '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.12.7 + '@types/node': 20.14.9 chalk: 4.1.2 co: 4.6.0 dedent: 1.3.0 @@ -19957,16 +21226,16 @@ snapshots: - babel-plugin-macros - supports-color - jest-cli@29.7.0(@types/node@20.12.7): + jest-cli@29.7.0(@types/node@20.14.9): dependencies: '@jest/core': 29.7.0 '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 chalk: 4.1.2 - create-jest: 29.7.0(@types/node@20.12.7) + create-jest: 29.7.0(@types/node@20.14.9) exit: 0.1.2 import-local: 3.1.0 - jest-config: 29.7.0(@types/node@20.12.7) + jest-config: 29.7.0(@types/node@20.14.9) jest-util: 29.7.0 jest-validate: 29.7.0 yargs: 17.7.2 @@ -19976,7 +21245,7 @@ snapshots: - supports-color - ts-node - jest-config@29.7.0(@types/node@20.12.7): + jest-config@29.7.0(@types/node@20.14.9): dependencies: '@babel/core': 7.23.5 '@jest/test-sequencer': 29.7.0 @@ -19995,13 +21264,13 @@ snapshots: jest-runner: 29.7.0 jest-util: 29.7.0 jest-validate: 29.7.0 - micromatch: 4.0.5 + micromatch: 4.0.7 parse-json: 5.2.0 pretty-format: 29.7.0 slash: 3.0.0 strip-json-comments: 3.1.1 optionalDependencies: - '@types/node': 20.12.7 + '@types/node': 20.14.9 transitivePeerDependencies: - babel-plugin-macros - supports-color @@ -20030,7 +21299,7 @@ snapshots: '@jest/environment': 29.7.0 '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.12.7 + '@types/node': 20.14.9 jest-mock: 29.7.0 jest-util: 29.7.0 @@ -20047,14 +21316,14 @@ snapshots: dependencies: '@jest/types': 29.6.3 '@types/graceful-fs': 4.1.6 - '@types/node': 20.12.7 + '@types/node': 20.14.9 anymatch: 3.1.3 fb-watchman: 2.0.2 graceful-fs: 4.2.11 jest-regex-util: 29.6.3 jest-util: 29.7.0 jest-worker: 29.7.0 - micromatch: 4.0.5 + micromatch: 4.0.7 walker: 1.0.8 optionalDependencies: fsevents: 2.3.3 @@ -20078,7 +21347,7 @@ snapshots: '@types/stack-utils': 2.0.1 chalk: 4.1.2 graceful-fs: 4.2.11 - micromatch: 4.0.5 + micromatch: 4.0.7 pretty-format: 29.7.0 slash: 3.0.0 stack-utils: 2.0.6 @@ -20086,7 +21355,7 @@ snapshots: jest-mock@29.7.0: dependencies: '@jest/types': 29.6.3 - '@types/node': 20.12.7 + '@types/node': 20.14.9 jest-util: 29.7.0 jest-pnp-resolver@1.2.3(jest-resolve@29.7.0): @@ -20121,7 +21390,7 @@ snapshots: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.12.7 + '@types/node': 20.14.9 chalk: 4.1.2 emittery: 0.13.1 graceful-fs: 4.2.11 @@ -20149,7 +21418,7 @@ snapshots: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.12.7 + '@types/node': 20.14.9 chalk: 4.1.2 cjs-module-lexer: 1.2.2 collect-v8-coverage: 1.0.1 @@ -20195,7 +21464,7 @@ snapshots: jest-util@29.7.0: dependencies: '@jest/types': 29.6.3 - '@types/node': 20.12.7 + '@types/node': 20.14.9 chalk: 4.1.2 ci-info: 3.7.1 graceful-fs: 4.2.11 @@ -20214,7 +21483,7 @@ snapshots: dependencies: '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.12.7 + '@types/node': 20.14.9 ansi-escapes: 4.3.2 chalk: 4.1.2 emittery: 0.13.1 @@ -20228,17 +21497,17 @@ snapshots: jest-worker@29.7.0: dependencies: - '@types/node': 20.12.7 + '@types/node': 20.14.9 jest-util: 29.7.0 merge-stream: 2.0.0 supports-color: 8.1.1 - jest@29.7.0(@types/node@20.12.7): + jest@29.7.0(@types/node@20.14.9): dependencies: '@jest/core': 29.7.0 '@jest/types': 29.6.3 import-local: 3.1.0 - jest-cli: 29.7.0(@types/node@20.12.7) + jest-cli: 29.7.0(@types/node@20.14.9) transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -20268,6 +21537,8 @@ snapshots: js-tokens@4.0.0: {} + js-tokens@9.0.0: {} + js-yaml@3.14.1: dependencies: argparse: 1.0.10 @@ -20283,55 +21554,55 @@ snapshots: jschardet@3.0.0: {} - jscodeshift@0.15.1(@babel/preset-env@7.23.5(@babel/core@7.24.0)): + jscodeshift@0.15.1(@babel/preset-env@7.24.7(@babel/core@7.24.7)): dependencies: - '@babel/core': 7.24.0 - '@babel/parser': 7.24.0 - '@babel/plugin-transform-class-properties': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-transform-modules-commonjs': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-transform-nullish-coalescing-operator': 7.23.4(@babel/core@7.24.0) - '@babel/plugin-transform-optional-chaining': 7.23.4(@babel/core@7.24.0) - '@babel/plugin-transform-private-methods': 7.23.3(@babel/core@7.24.0) - '@babel/preset-flow': 7.23.3(@babel/core@7.24.0) - '@babel/preset-typescript': 7.23.3(@babel/core@7.24.0) - '@babel/register': 7.22.15(@babel/core@7.24.0) - babel-core: 7.0.0-bridge.0(@babel/core@7.24.0) + '@babel/core': 7.24.7 + '@babel/parser': 7.24.7 + '@babel/plugin-transform-class-properties': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-modules-commonjs': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-nullish-coalescing-operator': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-optional-chaining': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-private-methods': 7.24.7(@babel/core@7.24.7) + '@babel/preset-flow': 7.23.3(@babel/core@7.24.7) + '@babel/preset-typescript': 7.23.3(@babel/core@7.24.7) + '@babel/register': 7.22.15(@babel/core@7.24.7) + babel-core: 7.0.0-bridge.0(@babel/core@7.24.7) chalk: 4.1.2 flow-parser: 0.202.0 graceful-fs: 4.2.11 - micromatch: 4.0.5 + micromatch: 4.0.7 neo-async: 2.6.2 node-dir: 0.1.17 - recast: 0.23.4 + recast: 0.23.6 temp: 0.8.4 write-file-atomic: 2.4.3 optionalDependencies: - '@babel/preset-env': 7.23.5(@babel/core@7.24.0) + '@babel/preset-env': 7.24.7(@babel/core@7.24.7) transitivePeerDependencies: - supports-color - jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3): + jsdom@24.1.0(bufferutil@4.0.8)(utf-8-validate@6.0.4): dependencies: cssstyle: 4.0.1 data-urls: 5.0.0 decimal.js: 10.4.3 form-data: 4.0.0 html-encoding-sniffer: 4.0.0 - http-proxy-agent: 7.0.0 - https-proxy-agent: 7.0.2 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.4 is-potential-custom-element-name: 1.0.1 - nwsapi: 2.2.9 + nwsapi: 2.2.10 parse5: 7.1.2 - rrweb-cssom: 0.6.0 + rrweb-cssom: 0.7.1 saxes: 6.0.0 symbol-tree: 3.2.4 - tough-cookie: 4.1.3 + tough-cookie: 4.1.4 w3c-xmlserializer: 5.0.0 webidl-conversions: 7.0.0 whatwg-encoding: 3.1.1 whatwg-mimetype: 4.0.0 whatwg-url: 14.0.0 - ws: 8.17.0(bufferutil@4.0.7)(utf-8-validate@6.0.3) + ws: 8.17.1(bufferutil@4.0.8)(utf-8-validate@6.0.4) xml-name-validator: 5.0.0 transitivePeerDependencies: - bufferutil @@ -20385,9 +21656,9 @@ snapshots: optionalDependencies: graceful-fs: 4.2.11 - jsonld@8.3.2(web-streams-polyfill@3.2.1): + jsonld@8.3.2(web-streams-polyfill@4.0.0): dependencies: - '@digitalbazaar/http-client': 3.4.1(web-streams-polyfill@3.2.1) + '@digitalbazaar/http-client': 3.4.1(web-streams-polyfill@4.0.0) canonicalize: 1.0.8 lru-cache: 6.0.0 rdf-canonize: 3.4.0 @@ -20412,8 +21683,6 @@ snapshots: jsrsasign@11.1.0: {} - jssha@3.3.1: {} - jstransformer@1.0.0: dependencies: is-promise: 2.2.2 @@ -20440,13 +21709,13 @@ snapshots: kleur@3.0.3: {} - ky-universal@0.11.0(ky@0.33.3)(web-streams-polyfill@3.2.1): + ky-universal@0.11.0(ky@0.33.3)(web-streams-polyfill@4.0.0): dependencies: abort-controller: 3.0.0 ky: 0.33.3 node-fetch: 3.3.2 optionalDependencies: - web-streams-polyfill: 3.2.1 + web-streams-polyfill: 4.0.0 ky@0.33.3: {} @@ -20492,7 +21761,10 @@ snapshots: optionalDependencies: enquirer: 2.3.6 - local-pkg@0.4.3: {} + local-pkg@0.5.0: + dependencies: + mlly: 1.5.0 + pkg-types: 1.0.3 locate-path@3.0.0: dependencies: @@ -20515,8 +21787,6 @@ snapshots: lodash.isarguments@3.1.0: {} - lodash.isequal@4.5.0: {} - lodash.memoize@4.1.2: {} lodash.merge@4.6.2: {} @@ -20588,9 +21858,11 @@ snapshots: dependencies: '@jridgewell/sourcemap-codec': 1.4.15 - magic-string@0.30.7: + magicast@0.3.4: dependencies: - '@jridgewell/sourcemap-codec': 1.4.15 + '@babel/parser': 7.24.5 + '@babel/types': 7.24.0 + source-map-js: 1.2.0 mailcheck@1.1.1: {} @@ -20613,7 +21885,7 @@ snapshots: cacache: 18.0.0 http-cache-semantics: 4.1.1 is-lambda: 1.0.1 - minipass: 7.0.4 + minipass: 7.1.2 minipass-fetch: 3.0.3 minipass-flush: 1.0.5 minipass-pipeline: 1.2.4 @@ -20750,7 +22022,7 @@ snapshots: media-typer@0.3.0: {} - meilisearch@0.38.0(encoding@0.1.13): + meilisearch@0.41.0(encoding@0.1.13): dependencies: cross-fetch: 3.1.6(encoding@0.1.13) transitivePeerDependencies: @@ -20963,7 +22235,7 @@ snapshots: micromark@4.0.0: dependencies: '@types/debug': 4.1.12 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.5(supports-color@8.1.1) decode-named-character-reference: 1.0.2 devlop: 1.1.0 micromark-core-commonmark: 2.0.0 @@ -20982,9 +22254,9 @@ snapshots: transitivePeerDependencies: - supports-color - micromatch@4.0.5: + micromatch@4.0.7: dependencies: - braces: 3.0.2 + braces: 3.0.3 picomatch: 2.3.1 mime-db@1.52.0: {} @@ -21067,12 +22339,6 @@ snapshots: dependencies: minipass: 3.3.6 - minipass@2.9.0: - dependencies: - safe-buffer: 5.2.1 - yallist: 3.1.1 - optional: true - minipass@3.3.6: dependencies: yallist: 4.0.0 @@ -21081,10 +22347,7 @@ snapshots: minipass@7.0.4: {} - minizlib@1.3.3: - dependencies: - minipass: 2.9.0 - optional: true + minipass@7.1.2: {} minizlib@2.1.2: dependencies: @@ -21103,7 +22366,7 @@ snapshots: mlly@1.5.0: dependencies: - acorn: 8.11.3 + acorn: 8.12.0 pathe: 1.1.2 pkg-types: 1.0.3 ufo: 1.3.2 @@ -21142,18 +22405,18 @@ snapshots: optionalDependencies: msgpackr-extract: 3.0.2 - msw-storybook-addon@2.0.1(msw@2.2.14(typescript@5.4.5)): + msw-storybook-addon@2.0.2(msw@2.3.1(typescript@5.5.3)): dependencies: is-node-process: 1.2.0 - msw: 2.2.14(typescript@5.4.5) + msw: 2.3.1(typescript@5.5.3) - msw@2.2.14(typescript@5.4.5): + msw@2.3.1(typescript@5.5.3): dependencies: '@bundled-es-modules/cookie': 2.0.0 '@bundled-es-modules/statuses': 1.0.1 '@inquirer/confirm': 3.1.6 '@mswjs/cookies': 1.1.0 - '@mswjs/interceptors': 0.26.15 + '@mswjs/interceptors': 0.29.1 '@open-draft/until': 2.1.0 '@types/cookie': 0.6.0 '@types/statuses': 2.0.4 @@ -21167,7 +22430,7 @@ snapshots: type-fest: 4.9.0 yargs: 17.7.2 optionalDependencies: - typescript: 5.4.5 + typescript: 5.5.3 muggle-string@0.4.1: {} @@ -21193,7 +22456,7 @@ snapshots: object-assign: 4.1.1 thenify-all: 1.6.0 - nan@2.18.0: {} + nan@2.20.0: {} nanoid@3.3.7: {} @@ -21277,6 +22540,12 @@ snapshots: optionalDependencies: encoding: 0.1.13 + node-fetch@2.6.13(encoding@0.1.13): + dependencies: + whatwg-url: 5.0.0 + optionalDependencies: + encoding: 0.1.13 + node-fetch@2.7.0(encoding@0.1.13): dependencies: whatwg-url: 5.0.0 @@ -21295,11 +22564,11 @@ snapshots: node-gyp-build@4.6.0: optional: true - node-gyp@10.0.1: + node-gyp@10.1.0: dependencies: env-paths: 2.2.1 exponential-backoff: 3.1.1 - glob: 10.3.12 + glob: 10.4.2 graceful-fs: 4.2.11 make-fetch-happen: 13.0.0 nopt: 7.2.0 @@ -21314,7 +22583,7 @@ snapshots: node-releases@2.0.14: {} - nodemailer@6.9.13: {} + nodemailer@6.9.14: {} nodemon@3.0.2: dependencies: @@ -21329,14 +22598,14 @@ snapshots: touch: 3.1.0 undefsafe: 2.0.5 - nodemon@3.1.0: + nodemon@3.1.4: dependencies: chokidar: 3.5.3 debug: 4.3.4(supports-color@5.5.0) ignore-by-default: 1.0.1 minimatch: 3.1.2 pstree.remy: 1.1.8 - semver: 7.5.4 + semver: 7.6.0 simple-update-notifier: 2.0.0 supports-color: 5.5.0 touch: 3.1.0 @@ -21381,6 +22650,8 @@ snapshots: normalize-url@8.0.0: {} + normalize-url@8.0.1: {} + npm-run-path@2.0.2: dependencies: path-key: 2.0.1 @@ -21393,6 +22664,10 @@ snapshots: dependencies: path-key: 4.0.0 + npm-run-path@5.3.0: + dependencies: + path-key: 4.0.0 + npmlog@5.0.1: dependencies: are-we-there-yet: 2.0.0 @@ -21401,16 +22676,16 @@ snapshots: set-blocking: 2.0.0 optional: true - nsfwjs@2.4.2(@tensorflow/tfjs@4.4.0(encoding@0.1.13)(seedrandom@3.0.5)): + nsfwjs@2.4.2(@tensorflow/tfjs@4.20.0(encoding@0.1.13)(seedrandom@3.0.5)): dependencies: '@nsfw-filter/gif-frames': 1.0.2 - '@tensorflow/tfjs': 4.4.0(encoding@0.1.13)(seedrandom@3.0.5) + '@tensorflow/tfjs': 4.20.0(encoding@0.1.13)(seedrandom@3.0.5) nth-check@2.1.1: dependencies: boolbase: 1.0.0 - nwsapi@2.2.9: {} + nwsapi@2.2.10: {} oauth-sign@0.9.0: {} @@ -21510,9 +22785,9 @@ snapshots: opentelemetry-instrumentation-fetch-node@1.2.0: dependencies: - '@opentelemetry/api': 1.8.0 - '@opentelemetry/instrumentation': 0.43.0(@opentelemetry/api@1.8.0) - '@opentelemetry/semantic-conventions': 1.24.1 + '@opentelemetry/api': 1.9.0 + '@opentelemetry/instrumentation': 0.43.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.25.1 transitivePeerDependencies: - supports-color optional: true @@ -21526,12 +22801,21 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 + optionator@0.9.4: + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + word-wrap: 1.2.5 + ora@5.4.1: dependencies: bl: 4.1.0 chalk: 4.1.2 cli-cursor: 3.1.0 - cli-spinners: 2.7.0 + cli-spinners: 2.9.2 is-interactive: 1.0.0 is-unicode-supported: 0.1.0 log-symbols: 4.1.0 @@ -21546,9 +22830,9 @@ snapshots: ospath@1.2.2: {} - otpauth@9.2.3: + otpauth@9.3.1: dependencies: - jssha: 3.3.1 + '@noble/hashes': 1.4.0 outvariant@1.4.2: {} @@ -21568,7 +22852,7 @@ snapshots: dependencies: yocto-queue: 0.1.0 - p-limit@4.0.0: + p-limit@5.0.0: dependencies: yocto-queue: 1.0.0 @@ -21599,6 +22883,8 @@ snapshots: p-try@2.2.0: {} + package-json-from-dist@1.0.0: {} + pako@0.2.9: {} parent-module@1.0.1: @@ -21616,6 +22902,8 @@ snapshots: json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 + parse-ms@4.0.0: {} + parse-srcset@1.0.2: {} parse5-htmlparser2-tree-adapter@6.0.1: @@ -21663,6 +22951,11 @@ snapshots: lru-cache: 10.2.2 minipass: 7.0.4 + path-scurry@1.11.1: + dependencies: + lru-cache: 10.2.2 + minipass: 7.1.2 + path-to-regexp@0.1.7: {} path-to-regexp@1.8.0: @@ -21675,6 +22968,8 @@ snapshots: path-type@4.0.0: {} + path-type@5.0.0: {} + pathe@1.1.2: {} pathval@1.1.1: {} @@ -21704,11 +22999,9 @@ snapshots: pg-numeric@1.0.2: {} - pg-pool@3.6.2(pg@8.11.5): + pg-pool@3.6.2(pg@8.12.0): dependencies: - pg: 8.11.5 - - pg-protocol@1.6.0: {} + pg: 8.12.0 pg-protocol@1.6.1: {} @@ -21730,10 +23023,10 @@ snapshots: postgres-interval: 3.0.0 postgres-range: 1.1.3 - pg@8.11.5: + pg@8.12.0: dependencies: pg-connection-string: 2.6.4 - pg-pool: 3.6.2(pg@8.11.5) + pg-pool: 3.6.2(pg@8.12.0) pg-protocol: 1.6.1 pg-types: 2.2.0 pgpass: 1.0.5 @@ -21744,7 +23037,7 @@ snapshots: dependencies: split2: 4.1.0 - photoswipe@5.4.3: {} + photoswipe@5.4.4: {} picocolors@1.0.0: {} @@ -21758,26 +23051,26 @@ snapshots: pify@4.0.1: {} - pino-abstract-transport@1.1.0: + pino-abstract-transport@1.2.0: dependencies: readable-stream: 4.3.0 split2: 4.1.0 - pino-std-serializers@6.1.0: {} + pino-std-serializers@7.0.0: {} - pino@8.17.0: + pino@9.2.0: dependencies: atomic-sleep: 1.0.0 fast-redact: 3.1.2 on-exit-leak-free: 2.1.0 - pino-abstract-transport: 1.1.0 - pino-std-serializers: 6.1.0 - process-warning: 2.2.0 + pino-abstract-transport: 1.2.0 + pino-std-serializers: 7.0.0 + process-warning: 3.0.0 quick-format-unescaped: 4.0.4 real-require: 0.2.0 safe-stable-stringify: 2.4.2 - sonic-boom: 3.7.0 - thread-stream: 2.3.0 + sonic-boom: 4.0.1 + thread-stream: 3.1.0 pirates@4.0.5: {} @@ -22012,7 +23305,7 @@ snapshots: prelude-ls@1.2.1: {} - prettier@3.2.5: {} + prettier@3.3.2: {} pretty-bytes@5.6.0: {} @@ -22030,6 +23323,10 @@ snapshots: pretty-hrtime@1.0.3: {} + pretty-ms@9.0.0: + dependencies: + parse-ms: 4.0.0 + private-ip@2.3.3: dependencies: ip-regex: 4.3.0 @@ -22115,19 +23412,21 @@ snapshots: js-stringify: 1.0.2 pug-runtime: 3.0.1 - pug-code-gen@3.0.2: + pug-code-gen@3.0.3: dependencies: constantinople: 4.0.1 doctypes: 1.1.0 js-stringify: 1.0.2 pug-attrs: 3.0.0 - pug-error: 2.0.0 + pug-error: 2.1.0 pug-runtime: 3.0.1 void-elements: 3.1.0 with: 7.0.2 pug-error@2.0.0: {} + pug-error@2.1.0: {} + pug-filters@4.0.0: dependencies: constantinople: 4.0.1 @@ -22165,9 +23464,9 @@ snapshots: pug-walk@2.0.0: {} - pug@3.0.2: + pug@3.0.3: dependencies: - pug-code-gen: 3.0.2 + pug-code-gen: 3.0.3 pug-filters: 4.0.0 pug-lexer: 5.0.1 pug-linker: 4.0.0 @@ -22247,13 +23546,6 @@ snapshots: ratelimiter@3.4.1: {} - raw-body@2.5.1: - dependencies: - bytes: 3.1.2 - http-errors: 2.0.0 - iconv-lite: 0.4.24 - unpipe: 1.0.0 - raw-body@2.5.2: dependencies: bytes: 3.1.2 @@ -22265,11 +23557,11 @@ snapshots: dependencies: setimmediate: 1.0.5 - re2@1.20.10: + re2@1.21.3: dependencies: install-artifact-from-github: 1.3.5 - nan: 2.18.0 - node-gyp: 10.0.1 + nan: 2.20.0 + node-gyp: 10.1.0 transitivePeerDependencies: - supports-color @@ -22278,15 +23570,15 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - react-docgen-typescript@2.2.2(typescript@5.4.5): + react-docgen-typescript@2.2.2(typescript@5.5.3): dependencies: - typescript: 5.4.5 + typescript: 5.5.3 react-docgen@7.0.1: dependencies: - '@babel/core': 7.24.0 - '@babel/traverse': 7.24.0 - '@babel/types': 7.24.0 + '@babel/core': 7.24.7 + '@babel/traverse': 7.24.7 + '@babel/types': 7.24.7 '@types/babel__core': 7.20.0 '@types/babel__traverse': 7.20.0 '@types/doctrine': 0.0.9 @@ -22319,6 +23611,34 @@ snapshots: react-is@18.2.0: {} + react-remove-scroll-bar@2.3.6(@types/react@18.0.28)(react@18.3.1): + dependencies: + react: 18.3.1 + react-style-singleton: 2.2.1(@types/react@18.0.28)(react@18.3.1) + tslib: 2.6.2 + optionalDependencies: + '@types/react': 18.0.28 + + react-remove-scroll@2.5.7(@types/react@18.0.28)(react@18.3.1): + dependencies: + react: 18.3.1 + react-remove-scroll-bar: 2.3.6(@types/react@18.0.28)(react@18.3.1) + react-style-singleton: 2.2.1(@types/react@18.0.28)(react@18.3.1) + tslib: 2.6.2 + use-callback-ref: 1.3.2(@types/react@18.0.28)(react@18.3.1) + use-sidecar: 1.1.2(@types/react@18.0.28)(react@18.3.1) + optionalDependencies: + '@types/react': 18.0.28 + + react-style-singleton@2.2.1(@types/react@18.0.28)(react@18.3.1): + dependencies: + get-nonce: 1.0.1 + invariant: 2.2.4 + react: 18.3.1 + tslib: 2.6.2 + optionalDependencies: + '@types/react': 18.0.28 + react@18.3.1: dependencies: loose-envify: 1.4.0 @@ -22380,14 +23700,6 @@ snapshots: real-require@0.2.0: {} - recast@0.23.4: - dependencies: - assert: 2.1.0 - ast-types: 0.16.1 - esprima: 4.0.1 - source-map: 0.6.1 - tslib: 2.6.2 - recast@0.23.6: dependencies: ast-types: 0.16.1 @@ -22532,7 +23844,7 @@ snapshots: require-in-the-middle@7.3.0: dependencies: - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.5(supports-color@8.1.1) module-details-from-path: 1.0.3 resolve: 1.22.8 transitivePeerDependencies: @@ -22556,11 +23868,6 @@ snapshots: resolve.exports@2.0.0: {} - resolve@1.19.0: - dependencies: - is-core-module: 2.13.1 - path-parse: 1.0.7 - resolve@1.22.8: dependencies: is-core-module: 2.13.1 @@ -22586,6 +23893,8 @@ snapshots: reusify@1.0.4: {} + rfc4648@1.5.3: {} + rfdc@1.3.0: {} rimraf@2.6.3: @@ -22600,31 +23909,34 @@ snapshots: rimraf@3.0.2: dependencies: glob: 7.2.3 + optional: true - rollup@4.17.2: + rollup@4.18.0: dependencies: '@types/estree': 1.0.5 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.17.2 - '@rollup/rollup-android-arm64': 4.17.2 - '@rollup/rollup-darwin-arm64': 4.17.2 - '@rollup/rollup-darwin-x64': 4.17.2 - '@rollup/rollup-linux-arm-gnueabihf': 4.17.2 - '@rollup/rollup-linux-arm-musleabihf': 4.17.2 - '@rollup/rollup-linux-arm64-gnu': 4.17.2 - '@rollup/rollup-linux-arm64-musl': 4.17.2 - '@rollup/rollup-linux-powerpc64le-gnu': 4.17.2 - '@rollup/rollup-linux-riscv64-gnu': 4.17.2 - '@rollup/rollup-linux-s390x-gnu': 4.17.2 - '@rollup/rollup-linux-x64-gnu': 4.17.2 - '@rollup/rollup-linux-x64-musl': 4.17.2 - '@rollup/rollup-win32-arm64-msvc': 4.17.2 - '@rollup/rollup-win32-ia32-msvc': 4.17.2 - '@rollup/rollup-win32-x64-msvc': 4.17.2 + '@rollup/rollup-android-arm-eabi': 4.18.0 + '@rollup/rollup-android-arm64': 4.18.0 + '@rollup/rollup-darwin-arm64': 4.18.0 + '@rollup/rollup-darwin-x64': 4.18.0 + '@rollup/rollup-linux-arm-gnueabihf': 4.18.0 + '@rollup/rollup-linux-arm-musleabihf': 4.18.0 + '@rollup/rollup-linux-arm64-gnu': 4.18.0 + '@rollup/rollup-linux-arm64-musl': 4.18.0 + '@rollup/rollup-linux-powerpc64le-gnu': 4.18.0 + '@rollup/rollup-linux-riscv64-gnu': 4.18.0 + '@rollup/rollup-linux-s390x-gnu': 4.18.0 + '@rollup/rollup-linux-x64-gnu': 4.18.0 + '@rollup/rollup-linux-x64-musl': 4.18.0 + '@rollup/rollup-win32-arm64-msvc': 4.18.0 + '@rollup/rollup-win32-ia32-msvc': 4.18.0 + '@rollup/rollup-win32-x64-msvc': 4.18.0 fsevents: 2.3.3 rrweb-cssom@0.6.0: {} + rrweb-cssom@0.7.1: {} + rss-parser@3.13.0: dependencies: entities: 2.2.0 @@ -22672,7 +23984,7 @@ snapshots: parse-srcset: 1.0.2 postcss: 8.4.38 - sass@1.76.0: + sass@1.77.6: dependencies: chokidar: 3.5.3 immutable: 4.2.2 @@ -22754,14 +24066,14 @@ snapshots: dependencies: kind-of: 6.0.3 - sharp@0.33.3: + sharp@0.33.4: dependencies: color: 4.2.3 detect-libc: 2.0.3 semver: 7.6.0 optionalDependencies: - '@img/sharp-darwin-arm64': 0.33.3 - '@img/sharp-darwin-x64': 0.33.3 + '@img/sharp-darwin-arm64': 0.33.4 + '@img/sharp-darwin-x64': 0.33.4 '@img/sharp-libvips-darwin-arm64': 1.0.2 '@img/sharp-libvips-darwin-x64': 1.0.2 '@img/sharp-libvips-linux-arm': 1.0.2 @@ -22770,15 +24082,15 @@ snapshots: '@img/sharp-libvips-linux-x64': 1.0.2 '@img/sharp-libvips-linuxmusl-arm64': 1.0.2 '@img/sharp-libvips-linuxmusl-x64': 1.0.2 - '@img/sharp-linux-arm': 0.33.3 - '@img/sharp-linux-arm64': 0.33.3 - '@img/sharp-linux-s390x': 0.33.3 - '@img/sharp-linux-x64': 0.33.3 - '@img/sharp-linuxmusl-arm64': 0.33.3 - '@img/sharp-linuxmusl-x64': 0.33.3 - '@img/sharp-wasm32': 0.33.3 - '@img/sharp-win32-ia32': 0.33.3 - '@img/sharp-win32-x64': 0.33.3 + '@img/sharp-linux-arm': 0.33.4 + '@img/sharp-linux-arm64': 0.33.4 + '@img/sharp-linux-s390x': 0.33.4 + '@img/sharp-linux-x64': 0.33.4 + '@img/sharp-linuxmusl-arm64': 0.33.4 + '@img/sharp-linuxmusl-x64': 0.33.4 + '@img/sharp-wasm32': 0.33.4 + '@img/sharp-win32-ia32': 0.33.4 + '@img/sharp-win32-x64': 0.33.4 shebang-command@1.2.0: dependencies: @@ -22792,9 +24104,9 @@ snapshots: shebang-regex@3.0.0: {} - shiki@1.4.0: + shiki@1.10.0: dependencies: - '@shikijs/core': 1.4.0 + '@shikijs/core': 1.10.0 shimmer@1.2.1: {} @@ -22810,11 +24122,11 @@ snapshots: signal-exit@4.1.0: {} - simple-oauth2@5.0.0: + simple-oauth2@5.0.1: dependencies: - '@hapi/hoek': 10.0.1 + '@hapi/hoek': 11.0.4 '@hapi/wreck': 18.0.1 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.4(supports-color@5.5.0) joi: 17.11.0 transitivePeerDependencies: - supports-color @@ -22895,6 +24207,8 @@ snapshots: slash@3.0.0: {} + slash@5.1.0: {} + slice-ansi@3.0.0: dependencies: ansi-styles: 4.3.0 @@ -22912,7 +24226,7 @@ snapshots: socks-proxy-agent@8.0.2: dependencies: agent-base: 7.1.0 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.5(supports-color@8.1.1) socks: 2.7.1 transitivePeerDependencies: - supports-color @@ -22922,7 +24236,7 @@ snapshots: ip: 2.0.1 smart-buffer: 4.2.0 - sonic-boom@3.7.0: + sonic-boom@4.0.1: dependencies: atomic-sleep: 1.0.0 @@ -22978,7 +24292,7 @@ snapshots: sprintf-js@1.0.3: {} - sprintf-js@1.1.2: {} + sprintf-js@1.1.3: {} sshpk@1.17.0: dependencies: @@ -23004,16 +24318,16 @@ snapshots: standard-as-callback@2.1.0: {} - start-server-and-test@2.0.3: + start-server-and-test@2.0.4: dependencies: arg: 5.0.2 bluebird: 3.7.2 check-more-types: 2.24.0 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.5(supports-color@8.1.1) execa: 5.1.1 lazy-ass: 1.6.0 ps-tree: 1.2.0 - wait-on: 7.2.0(debug@4.3.4) + wait-on: 7.2.0(debug@4.3.5) transitivePeerDependencies: - supports-color @@ -23027,22 +24341,22 @@ snapshots: store2@2.14.2: {} - storybook-addon-misskey-theme@https://codeload.github.com/misskey-dev/storybook-addon-misskey-theme/tar.gz/cf583db098365b2ccc81a82f63ca9c93bc32b640(@storybook/blocks@8.0.9(@types/react@18.0.28)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@storybook/components@8.0.9(@types/react@18.0.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@storybook/core-events@8.0.9)(@storybook/manager-api@8.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@storybook/preview-api@8.0.9)(@storybook/theming@8.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@storybook/types@8.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + storybook-addon-misskey-theme@https://codeload.github.com/misskey-dev/storybook-addon-misskey-theme/tar.gz/cf583db098365b2ccc81a82f63ca9c93bc32b640(@storybook/blocks@8.1.11(@types/react@18.0.28)(encoding@0.1.13)(prettier@3.3.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@storybook/components@8.1.11(@types/react@18.0.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@storybook/core-events@8.1.11)(@storybook/manager-api@8.1.11(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@storybook/preview-api@8.1.11)(@storybook/theming@8.1.11(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@storybook/types@8.1.11)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: - '@storybook/blocks': 8.0.9(@types/react@18.0.28)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@storybook/components': 8.0.9(@types/react@18.0.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@storybook/core-events': 8.0.9 - '@storybook/manager-api': 8.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@storybook/preview-api': 8.0.9 - '@storybook/theming': 8.0.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@storybook/types': 8.0.9 + '@storybook/blocks': 8.1.11(@types/react@18.0.28)(encoding@0.1.13)(prettier@3.3.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@storybook/components': 8.1.11(@types/react@18.0.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@storybook/core-events': 8.1.11 + '@storybook/manager-api': 8.1.11(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@storybook/preview-api': 8.1.11 + '@storybook/theming': 8.1.11(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@storybook/types': 8.1.11 optionalDependencies: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - storybook@8.0.9(@babel/preset-env@7.23.5(@babel/core@7.24.0))(bufferutil@4.0.7)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(utf-8-validate@6.0.3): + storybook@8.1.11(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(utf-8-validate@6.0.4): dependencies: - '@storybook/cli': 8.0.9(@babel/preset-env@7.23.5(@babel/core@7.24.0))(bufferutil@4.0.7)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(utf-8-validate@6.0.3) + '@storybook/cli': 8.1.11(@babel/preset-env@7.24.7(@babel/core@7.24.7))(bufferutil@4.0.8)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(utf-8-validate@6.0.4) transitivePeerDependencies: - '@babel/preset-env' - bufferutil @@ -23151,6 +24465,8 @@ snapshots: strip-final-newline@3.0.0: {} + strip-final-newline@4.0.0: {} + strip-indent@3.0.0: dependencies: min-indent: 1.0.1 @@ -23161,9 +24477,9 @@ snapshots: strip-json-comments@3.1.1: {} - strip-literal@1.3.0: + strip-literal@2.1.0: dependencies: - acorn: 8.11.3 + js-tokens: 9.0.0 strip-outer@2.0.0: {} @@ -23174,6 +24490,8 @@ snapshots: '@tokenizer/token': 0.3.0 peek-readable: 5.0.0 + structured-headers@1.0.1: {} + stylehacks@6.1.1(postcss@8.4.38): dependencies: browserslist: 4.23.0 @@ -23213,7 +24531,7 @@ snapshots: symbol-tree@3.2.4: {} - systeminformation@5.22.7: {} + systeminformation@5.22.11: {} tar-fs@2.1.1: dependencies: @@ -23236,17 +24554,6 @@ snapshots: fast-fifo: 1.3.0 streamx: 2.15.0 - tar@4.4.19: - dependencies: - chownr: 1.1.4 - fs-minipass: 1.2.7 - minipass: 2.9.0 - minizlib: 1.3.3 - mkdirp: 0.5.6 - safe-buffer: 5.2.1 - yallist: 3.1.1 - optional: true - tar@6.2.1: dependencies: chownr: 2.0.0 @@ -23264,27 +24571,34 @@ snapshots: dependencies: memoizerific: 1.11.3 - temp-dir@2.0.0: {} + temp-dir@3.0.0: {} temp@0.8.4: dependencies: rimraf: 2.6.3 - tempy@1.0.1: + tempy@3.1.0: dependencies: - del: 6.1.1 - is-stream: 2.0.1 - temp-dir: 2.0.0 - type-fest: 0.16.0 - unique-string: 2.0.0 + is-stream: 3.0.0 + temp-dir: 3.0.0 + type-fest: 2.19.0 + unique-string: 3.0.0 - terser@5.30.3: + terser@5.31.1: dependencies: '@jridgewell/source-map': 0.3.5 - acorn: 8.11.3 + acorn: 8.12.0 commander: 2.20.3 source-map-support: 0.5.21 + terser@5.31.2: + dependencies: + '@jridgewell/source-map': 0.3.6 + acorn: 8.12.0 + commander: 2.20.3 + source-map-support: 0.5.21 + optional: true + test-exclude@6.0.0: dependencies: '@istanbuljs/schema': 0.1.3 @@ -23303,13 +24617,13 @@ snapshots: dependencies: any-promise: 1.3.0 - thread-stream@2.3.0: + thread-stream@3.1.0: dependencies: real-require: 0.2.0 - three@0.164.1: {} + three@0.165.0: {} - throttle-debounce@5.0.0: {} + throttle-debounce@5.0.2: {} throttleit@1.0.0: {} @@ -23322,8 +24636,6 @@ snapshots: through@2.3.8: {} - tiny-invariant@1.3.1: {} - tiny-invariant@1.3.3: {} tiny-lru@10.0.1: {} @@ -23332,7 +24644,7 @@ snapshots: tinycolor2@1.6.0: {} - tinypool@0.7.0: {} + tinypool@0.8.4: {} tinyspy@2.2.0: {} @@ -23348,8 +24660,6 @@ snapshots: dependencies: is-number: 7.0.0 - toad-cache@3.3.0: {} - toad-cache@3.7.0: {} tocbot@4.21.1: {} @@ -23372,7 +24682,7 @@ snapshots: psl: 1.9.0 punycode: 2.3.1 - tough-cookie@4.1.3: + tough-cookie@4.1.4: dependencies: psl: 1.9.0 punycode: 2.3.1 @@ -23399,9 +24709,9 @@ snapshots: dependencies: typescript: 5.3.3 - ts-api-utils@1.3.0(typescript@5.4.5): + ts-api-utils@1.3.0(typescript@5.5.3): dependencies: - typescript: 5.4.5 + typescript: 5.5.3 ts-case-convert@2.0.2: {} @@ -23409,7 +24719,7 @@ snapshots: ts-map@1.0.3: {} - tsc-alias@1.8.8: + tsc-alias@1.8.10: dependencies: chokidar: 3.5.3 commander: 9.5.0 @@ -23431,9 +24741,9 @@ snapshots: minimist: 1.2.8 strip-bom: 3.0.0 - tsd@0.30.7: + tsd@0.31.1: dependencies: - '@tsd/typescript': 5.3.3 + '@tsd/typescript': 5.4.5 eslint-formatter-pretty: 4.1.0 globby: 11.1.0 jest-diff: 29.7.0 @@ -23445,6 +24755,8 @@ snapshots: tslib@2.6.2: {} + tslib@2.6.3: {} + tsx@4.4.0: dependencies: esbuild: 0.18.20 @@ -23464,8 +24776,6 @@ snapshots: type-detect@4.0.8: {} - type-fest@0.16.0: {} - type-fest@0.18.1: {} type-fest@0.20.2: {} @@ -23476,8 +24786,12 @@ snapshots: type-fest@0.8.1: {} + type-fest@1.4.0: {} + type-fest@2.19.0: {} + type-fest@4.20.1: {} + type-fest@4.9.0: {} type-is@1.6.18: @@ -23514,7 +24828,7 @@ snapshots: typedarray@0.0.6: {} - typeorm@0.3.20(ioredis@5.4.1)(pg@8.11.5): + typeorm@0.3.20(ioredis@5.4.1)(pg@8.12.0): dependencies: '@sqltools/formatter': 1.2.5 app-root-path: 3.1.0 @@ -23522,7 +24836,7 @@ snapshots: chalk: 4.1.2 cli-highlight: 2.1.11 dayjs: 1.11.10 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.4(supports-color@5.5.0) dotenv: 16.0.3 glob: 10.3.10 mkdirp: 2.1.6 @@ -23533,7 +24847,7 @@ snapshots: yargs: 17.7.2 optionalDependencies: ioredis: 5.4.1 - pg: 8.11.5 + pg: 8.12.0 transitivePeerDependencies: - supports-color @@ -23541,7 +24855,7 @@ snapshots: typescript@5.4.2: {} - typescript@5.4.5: {} + typescript@5.5.3: {} ufo@1.3.2: {} @@ -23582,6 +24896,8 @@ snapshots: unicode-property-aliases-ecmascript@2.1.0: {} + unicorn-magic@0.1.0: {} + unified@11.0.4: dependencies: '@types/unist': 3.0.2 @@ -23602,9 +24918,9 @@ snapshots: dependencies: imurmurhash: 0.1.4 - unique-string@2.0.0: + unique-string@3.0.0: dependencies: - crypto-random-string: 2.0.0 + crypto-random-string: 4.0.0 unist-util-is@6.0.0: dependencies: @@ -23637,7 +24953,7 @@ snapshots: unplugin@1.4.0: dependencies: - acorn: 8.11.3 + acorn: 8.12.0 chokidar: 3.5.3 webpack-sources: 3.2.3 webpack-virtual-modules: 0.5.0 @@ -23665,7 +24981,22 @@ snapshots: querystringify: 2.2.0 requires-port: 1.0.0 - utf-8-validate@6.0.3: + use-callback-ref@1.3.2(@types/react@18.0.28)(react@18.3.1): + dependencies: + react: 18.3.1 + tslib: 2.6.2 + optionalDependencies: + '@types/react': 18.0.28 + + use-sidecar@1.1.2(@types/react@18.0.28)(react@18.3.1): + dependencies: + detect-node-es: 1.1.0 + react: 18.3.1 + tslib: 2.6.2 + optionalDependencies: + '@types/react': 18.0.28 + + utf-8-validate@6.0.4: dependencies: node-gyp-build: 4.6.0 optional: true @@ -23682,20 +25013,22 @@ snapshots: utils-merge@1.0.1: {} + uuid@10.0.0: {} + uuid@3.4.0: {} uuid@8.3.2: {} uuid@9.0.1: {} - v-code-diff@1.11.0(vue@3.4.26(typescript@5.4.5)): + v-code-diff@1.12.0(vue@3.4.31(typescript@5.5.3)): dependencies: diff: 5.1.0 diff-match-patch: 1.0.5 highlight.js: 11.9.0 - vue: 3.4.26(typescript@5.4.5) - vue-demi: 0.14.7(vue@3.4.26(typescript@5.4.5)) - vue-i18n: 9.13.1(vue@3.4.26(typescript@5.4.5)) + vue: 3.4.31(typescript@5.5.3) + vue-demi: 0.14.7(vue@3.4.31(typescript@5.5.3)) + vue-i18n: 9.13.1(vue@3.4.31(typescript@5.5.3)) v8-to-istanbul@9.2.0: dependencies: @@ -23708,8 +25041,6 @@ snapshots: spdx-correct: 3.1.1 spdx-expression-parse: 3.0.1 - validator@13.9.0: {} - vary@1.1.2: {} verror@1.10.0: @@ -23729,14 +25060,13 @@ snapshots: unist-util-stringify-position: 4.0.0 vfile-message: 4.0.2 - vite-node@0.34.6(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3): + vite-node@1.6.0(@types/node@20.14.9)(sass@1.77.6)(terser@5.31.2): dependencies: cac: 6.7.14 - debug: 4.3.4(supports-color@8.1.1) - mlly: 1.5.0 + debug: 4.3.5(supports-color@8.1.1) pathe: 1.1.2 picocolors: 1.0.0 - vite: 5.2.11(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3) + vite: 5.3.2(@types/node@20.14.9)(sass@1.77.6)(terser@5.31.2) transitivePeerDependencies: - '@types/node' - less @@ -23749,53 +25079,50 @@ snapshots: vite-plugin-turbosnap@1.0.3: {} - vite@5.2.11(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3): + vite@5.3.2(@types/node@20.14.9)(sass@1.77.6)(terser@5.31.2): dependencies: - esbuild: 0.20.2 + esbuild: 0.21.5 postcss: 8.4.38 - rollup: 4.17.2 + rollup: 4.18.0 optionalDependencies: - '@types/node': 20.12.7 + '@types/node': 20.14.9 fsevents: 2.3.3 - sass: 1.76.0 - terser: 5.30.3 + sass: 1.77.6 + terser: 5.31.2 - vitest-fetch-mock@0.2.2(encoding@0.1.13)(vitest@0.34.6(happy-dom@10.0.3)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3)): + vitest-fetch-mock@0.2.2(encoding@0.1.13)(vitest@1.6.0(@types/node@20.14.9)(happy-dom@10.0.3)(jsdom@24.1.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))(sass@1.77.6)(terser@5.31.2)): dependencies: cross-fetch: 3.1.6(encoding@0.1.13) - vitest: 0.34.6(happy-dom@10.0.3)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3) + vitest: 1.6.0(@types/node@20.14.9)(happy-dom@10.0.3)(jsdom@24.1.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))(sass@1.77.6)(terser@5.31.2) transitivePeerDependencies: - encoding - vitest@0.34.6(happy-dom@10.0.3)(jsdom@24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3))(sass@1.76.0)(terser@5.30.3): + vitest@1.6.0(@types/node@20.14.9)(happy-dom@10.0.3)(jsdom@24.1.0(bufferutil@4.0.8)(utf-8-validate@6.0.4))(sass@1.77.6)(terser@5.31.2): dependencies: - '@types/chai': 4.3.11 - '@types/chai-subset': 1.3.5 - '@types/node': 20.12.7 - '@vitest/expect': 0.34.6 - '@vitest/runner': 0.34.6 - '@vitest/snapshot': 0.34.6 - '@vitest/spy': 0.34.6 - '@vitest/utils': 0.34.6 - acorn: 8.11.3 + '@vitest/expect': 1.6.0 + '@vitest/runner': 1.6.0 + '@vitest/snapshot': 1.6.0 + '@vitest/spy': 1.6.0 + '@vitest/utils': 1.6.0 acorn-walk: 8.3.2 - cac: 6.7.14 chai: 4.3.10 - debug: 4.3.4(supports-color@8.1.1) - local-pkg: 0.4.3 - magic-string: 0.30.7 + debug: 4.3.4(supports-color@5.5.0) + execa: 8.0.1 + local-pkg: 0.5.0 + magic-string: 0.30.10 pathe: 1.1.2 picocolors: 1.0.0 std-env: 3.7.0 - strip-literal: 1.3.0 + strip-literal: 2.1.0 tinybench: 2.6.0 - tinypool: 0.7.0 - vite: 5.2.11(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3) - vite-node: 0.34.6(@types/node@20.12.7)(sass@1.76.0)(terser@5.30.3) + tinypool: 0.8.4 + vite: 5.3.2(@types/node@20.14.9)(sass@1.77.6)(terser@5.31.2) + vite-node: 1.6.0(@types/node@20.14.9)(sass@1.77.6)(terser@5.31.2) why-is-node-running: 2.2.2 optionalDependencies: + '@types/node': 20.14.9 happy-dom: 10.0.3 - jsdom: 24.0.0(bufferutil@4.0.7)(utf-8-validate@6.0.3) + jsdom: 24.1.0(bufferutil@4.0.8)(utf-8-validate@6.0.4) transitivePeerDependencies: - less - lightningcss @@ -23828,98 +25155,102 @@ snapshots: dependencies: vscode-languageserver-protocol: 3.17.5 - vue-component-meta@2.0.16(typescript@5.4.5): + vscode-uri@3.0.8: {} + + vue-component-meta@2.0.16(typescript@5.5.3): dependencies: '@volar/typescript': 2.2.0 - '@vue/language-core': 2.0.16(typescript@5.4.5) + '@vue/language-core': 2.0.16(typescript@5.5.3) path-browserify: 1.0.1 vue-component-type-helpers: 2.0.16 optionalDependencies: - typescript: 5.4.5 + typescript: 5.5.3 vue-component-type-helpers@1.8.4: {} vue-component-type-helpers@2.0.16: {} - vue-component-type-helpers@2.0.19: {} + vue-component-type-helpers@2.0.24: {} - vue-demi@0.14.7(vue@3.4.26(typescript@5.4.5)): - dependencies: - vue: 3.4.26(typescript@5.4.5) + vue-component-type-helpers@2.0.26: {} - vue-docgen-api@4.75.1(vue@3.4.26(typescript@5.4.5)): + vue-demi@0.14.7(vue@3.4.31(typescript@5.5.3)): dependencies: - '@babel/parser': 7.24.0 - '@babel/types': 7.24.0 - '@vue/compiler-dom': 3.4.21 - '@vue/compiler-sfc': 3.4.26 + vue: 3.4.31(typescript@5.5.3) + + vue-docgen-api@4.75.1(vue@3.4.31(typescript@5.5.3)): + dependencies: + '@babel/parser': 7.24.7 + '@babel/types': 7.24.7 + '@vue/compiler-dom': 3.4.29 + '@vue/compiler-sfc': 3.4.31 ast-types: 0.16.1 hash-sum: 2.0.0 lru-cache: 8.0.4 - pug: 3.0.2 - recast: 0.23.4 + pug: 3.0.3 + recast: 0.23.6 ts-map: 1.0.3 - vue: 3.4.26(typescript@5.4.5) - vue-inbrowser-compiler-independent-utils: 4.71.1(vue@3.4.26(typescript@5.4.5)) + vue: 3.4.31(typescript@5.5.3) + vue-inbrowser-compiler-independent-utils: 4.71.1(vue@3.4.31(typescript@5.5.3)) - vue-eslint-parser@9.4.2(eslint@8.57.0): + vue-eslint-parser@9.4.3(eslint@9.7.0): dependencies: - debug: 4.3.4(supports-color@8.1.1) - eslint: 8.57.0 + debug: 4.3.4(supports-color@5.5.0) + eslint: 9.7.0 eslint-scope: 7.2.2 eslint-visitor-keys: 3.4.3 espree: 9.6.1 esquery: 1.4.2 lodash: 4.17.21 - semver: 7.5.4 + semver: 7.6.0 transitivePeerDependencies: - supports-color - vue-i18n@9.13.1(vue@3.4.26(typescript@5.4.5)): + vue-i18n@9.13.1(vue@3.4.31(typescript@5.5.3)): dependencies: '@intlify/core-base': 9.13.1 '@intlify/shared': 9.13.1 '@vue/devtools-api': 6.6.1 - vue: 3.4.26(typescript@5.4.5) + vue: 3.4.31(typescript@5.5.3) - vue-inbrowser-compiler-independent-utils@4.71.1(vue@3.4.26(typescript@5.4.5)): + vue-inbrowser-compiler-independent-utils@4.71.1(vue@3.4.31(typescript@5.5.3)): dependencies: - vue: 3.4.26(typescript@5.4.5) + vue: 3.4.31(typescript@5.5.3) vue-template-compiler@2.7.14: dependencies: de-indent: 1.0.2 he: 1.2.0 - vue-tsc@2.0.16(typescript@5.4.5): + vue-tsc@2.0.24(typescript@5.5.3): dependencies: - '@volar/typescript': 2.2.0 - '@vue/language-core': 2.0.16(typescript@5.4.5) + '@volar/typescript': 2.4.0-alpha.11 + '@vue/language-core': 2.0.24(typescript@5.5.3) semver: 7.6.0 - typescript: 5.4.5 + typescript: 5.5.3 - vue@3.4.26(typescript@5.4.5): + vue@3.4.31(typescript@5.5.3): dependencies: - '@vue/compiler-dom': 3.4.26 - '@vue/compiler-sfc': 3.4.26 - '@vue/runtime-dom': 3.4.26 - '@vue/server-renderer': 3.4.26(vue@3.4.26(typescript@5.4.5)) - '@vue/shared': 3.4.26 + '@vue/compiler-dom': 3.4.31 + '@vue/compiler-sfc': 3.4.31 + '@vue/runtime-dom': 3.4.31 + '@vue/server-renderer': 3.4.31(vue@3.4.31(typescript@5.5.3)) + '@vue/shared': 3.4.31 optionalDependencies: - typescript: 5.4.5 + typescript: 5.5.3 - vuedraggable@4.1.0(vue@3.4.26(typescript@5.4.5)): + vuedraggable@4.1.0(vue@3.4.31(typescript@5.5.3)): dependencies: sortablejs: 1.14.0 - vue: 3.4.26(typescript@5.4.5) + vue: 3.4.31(typescript@5.5.3) w3c-xmlserializer@5.0.0: dependencies: xml-name-validator: 5.0.0 - wait-on@7.2.0(debug@4.3.4): + wait-on@7.2.0(debug@4.3.5): dependencies: - axios: 1.6.2(debug@4.3.4) + axios: 1.6.2(debug@4.3.5) joi: 17.11.0 lodash: 4.17.21 minimist: 1.2.8 @@ -23952,6 +25283,9 @@ snapshots: web-streams-polyfill@3.2.1: {} + web-streams-polyfill@4.0.0: + optional: true + webidl-conversions@3.0.1: {} webidl-conversions@7.0.0: {} @@ -24031,11 +25365,13 @@ snapshots: with@7.0.2: dependencies: - '@babel/parser': 7.23.9 - '@babel/types': 7.23.5 + '@babel/parser': 7.24.5 + '@babel/types': 7.24.0 assert-never: 1.2.1 babel-walk: 3.0.0-canary-5 + word-wrap@1.2.5: {} + wordwrap@1.0.0: {} wrap-ansi@6.2.0: @@ -24069,10 +25405,10 @@ snapshots: imurmurhash: 0.1.4 signal-exit: 3.0.7 - ws@8.17.0(bufferutil@4.0.7)(utf-8-validate@6.0.3): + ws@8.17.1(bufferutil@4.0.8)(utf-8-validate@6.0.4): optionalDependencies: - bufferutil: 4.0.7 - utf-8-validate: 6.0.3 + bufferutil: 4.0.8 + utf-8-validate: 6.0.4 xev@3.0.2: {} @@ -24157,13 +25493,7 @@ snapshots: yocto-queue@1.0.0: {} - z-schema@5.0.5: - dependencies: - lodash.get: 4.4.2 - lodash.isequal: 4.5.0 - validator: 13.9.0 - optionalDependencies: - commander: 9.5.0 + yoctocolors@2.0.2: {} zip-stream@6.0.1: dependencies: diff --git a/scripts/build-assets.mjs b/scripts/build-assets.mjs index b5aa5eb4ab..2b275e12d6 100644 --- a/scripts/build-assets.mjs +++ b/scripts/build-assets.mjs @@ -13,7 +13,7 @@ import * as terser from 'terser'; import { build as buildLocales } from '../locales/index.js'; import generateDTS from '../locales/generateDTS.js'; -import meta from '../package.json' assert { type: "json" }; +import meta from '../package.json' with { type: "json" }; import buildTarball from './tarball.mjs'; const configDir = fileURLToPath(new URL('../.config', import.meta.url)); diff --git a/scripts/changelog-checker/.eslintrc.cjs b/scripts/changelog-checker/.eslintrc.cjs deleted file mode 100644 index 6acf8b3e6e..0000000000 --- a/scripts/changelog-checker/.eslintrc.cjs +++ /dev/null @@ -1,9 +0,0 @@ -module.exports = { - parserOptions: { - tsconfigRootDir: __dirname, - project: ['./tsconfig.json'], - }, - extends: [ - '../../packages/shared/.eslintrc.js', - ], -}; diff --git a/scripts/changelog-checker/eslint.config.js b/scripts/changelog-checker/eslint.config.js new file mode 100644 index 0000000000..813e96981a --- /dev/null +++ b/scripts/changelog-checker/eslint.config.js @@ -0,0 +1,17 @@ +import tsParser from '@typescript-eslint/parser'; +import sharedConfig from '../../packages/shared/eslint.config.js'; + +export default [ + ...sharedConfig, + { + files: ['src/**/*.ts', 'src/**/*.tsx'], + languageOptions: { + parserOptions: { + parser: tsParser, + project: ['./tsconfig.json'], + sourceType: 'module', + tsconfigRootDir: import.meta.dirname, + }, + }, + }, +]; diff --git a/scripts/tarball.mjs b/scripts/tarball.mjs index b1862ad289..e9d8900aca 100644 --- a/scripts/tarball.mjs +++ b/scripts/tarball.mjs @@ -10,7 +10,7 @@ import { fileURLToPath } from 'node:url'; import glob from 'fast-glob'; import walk from 'ignore-walk'; import Pack from 'tar/lib/pack.js'; -import meta from '../package.json' assert { type: "json" }; +import meta from '../package.json' with { type: "json" }; const cwd = fileURLToPath(new URL('..', import.meta.url)); const ignore = [