diff --git a/.github/codeql/codeql-config.yml b/.github/codeql/codeql-config.yml new file mode 100644 index 0000000..8c718db --- /dev/null +++ b/.github/codeql/codeql-config.yml @@ -0,0 +1,8 @@ +# What code scanning looks at: the code that ships. Tests hold fixed passwords, +# keys and tokens on purpose, which only make noise as findings. +name: Forgust +queries: + - uses: security-extended +paths-ignore: + - crates/*/tests + - web/e2e diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..a09c84d --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,111 @@ +version: 2 + +# One pull request per ecosystem each week, majors included. A breaking update +# turns its pull request red: it then gets a branch with the code changes. +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + # pinned to the commit of its `1.99` branch, which picks the Rust version: + # moved by hand with the toolchain + ignore: + - dependency-name: "dtolnay/rust-toolchain" + cooldown: + default-days: 3 + commit-message: + prefix: "chore" + include: "scope" + groups: + github-actions: + patterns: + - "*" + + - package-ecosystem: "cargo" + directory: "/" + schedule: + interval: "weekly" + allow: + - dependency-type: "all" + cooldown: + default-days: 3 + semver-major-days: 7 + commit-message: + prefix: "chore" + include: "scope" + groups: + rust: + patterns: + - "*" + + - package-ecosystem: "npm" + directory: "/web" + schedule: + interval: "weekly" + allow: + - dependency-type: "all" + cooldown: + default-days: 3 + semver-major-days: 7 + commit-message: + prefix: "chore" + include: "scope" + groups: + web: + patterns: + - "*" + + # npm run gen:api's own install: openapi-typescript uses TypeScript's + # JavaScript API, which TypeScript 7 dropped, so it keeps TypeScript 6 + - package-ecosystem: "npm" + directory: "/web/tools/gen-api" + schedule: + interval: "weekly" + ignore: + - dependency-name: "typescript" + update-types: ["version-update:semver-major"] + cooldown: + default-days: 3 + commit-message: + prefix: "chore" + include: "scope" + groups: + gen-api: + patterns: + - "*" + + - package-ecosystem: "docker-compose" + directory: "/" + schedule: + interval: "weekly" + # a new Postgres major cannot open the old data directory: moved by hand, + # with upgrade steps for existing installs + ignore: + - dependency-name: "postgres" + update-types: ["version-update:semver-major"] + cooldown: + default-days: 3 + commit-message: + prefix: "chore" + include: "scope" + groups: + docker-compose: + patterns: + - "*" + + - package-ecosystem: "docker" + directory: "/" + schedule: + interval: "weekly" + # the Rust image moves with the toolchain CI pins (dtolnay/rust-toolchain) + ignore: + - dependency-name: "rust" + cooldown: + default-days: 3 + commit-message: + prefix: "chore" + include: "scope" + groups: + docker: + patterns: + - "*" diff --git a/.github/release-notes.sh b/.github/release-notes.sh new file mode 100755 index 0000000..a275cc5 --- /dev/null +++ b/.github/release-notes.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env bash +# Release notes from the Conventional Commit subjects between two refs, grouped by +# type, newest first. Squash merges make every pull request one such commit. +# .github/release-notes.sh v0.1.0 v0.2.0 # since v0.1.0 +# .github/release-notes.sh "" HEAD # from the start +set -euo pipefail +from=${1:-} +to=${2:-HEAD} +range=${from:+$from..}$to + +order=(feat fix perf docs deps internal other) +declare -A title=([feat]=Features [fix]="Bug Fixes" [perf]=Performance [docs]=Documentation + [deps]=Dependencies [internal]=Internal [other]="Other Changes") +declare -A lines=() + +while IFS=$'\t' read -r sha subject; do + if [[ $subject =~ ^([a-z]+)(\(([^\)]*)\))?(!)?:\ (.+)$ ]]; then + type=${BASH_REMATCH[1]} scope=${BASH_REMATCH[3]} bang=${BASH_REMATCH[4]} text=${BASH_REMATCH[5]} + else + type=other scope="" bang="" text=$subject + fi + # the version bump itself is not news + [[ $type == chore && $text =~ ^release\ ]] && continue + case $type in + feat | fix | perf | docs) group=$type ;; + chore) [[ $scope == deps* ]] && group=deps || group=internal ;; # deps, deps-dev + refactor | test | ci | build | style) group=internal ;; + *) group=other ;; + esac + [[ -n $bang ]] && text="**breaking:** $text" + lines[$group]+="* $text ($sha)"$'\n' +done < <(git log --no-merges --format=$'%h\t%s' "$range") + +for g in "${order[@]}"; do + [[ -n ${lines[$g]:-} ]] || continue + printf '### %s\n%s\n' "${title[$g]}" "${lines[$g]}" +done diff --git a/.github/workflows/bench.yml b/.github/workflows/bench.yml index eca19ec..e32e095 100644 --- a/.github/workflows/bench.yml +++ b/.github/workflows/bench.yml @@ -13,19 +13,22 @@ name: Bench on: workflow_dispatch: +permissions: + contents: read + jobs: bench: runs-on: [self-hosted, bench] env: BASELINE: bench/baselines/bench-host.json steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - run: cargo build --release -p forgust-server -p forgust-bench - name: Run (regression gate vs stored baseline) run: bench/run.sh env: NIGHTLY: ${{ github.event_name == 'schedule' }} - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: name: bench-results path: bench/results/ diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 12458fd..f8cf8a9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,11 +29,11 @@ jobs: lint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@1.99 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - uses: dtolnay/rust-toolchain@d124f86f28ff42855784ff3319f48ac182c248f8 # 1.99 with: components: rustfmt, clippy - - uses: Swatinem/rust-cache@v2 + - uses: Swatinem/rust-cache@d1527c8f67ef9af357290475d4af4b0fab8f12e0 # v2.9.3 - name: Format run: cargo fmt --all --check - name: Clippy @@ -81,7 +81,7 @@ jobs: FORGUST_TEST_PG_RESTORE: /usr/lib/postgresql/17/bin/pg_restore FORGUST_TEST_PG_URL: postgres://forgust:forgust@127.0.0.1:5432 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: System packages (git-lfs, the Postgres 17 client for the backup test) run: | sudo apt-get update @@ -89,8 +89,8 @@ jobs: sudo /usr/share/postgresql-common/pgdg/apt.postgresql.org.sh -y sudo apt-get install -y --no-install-recommends postgresql-client-17 git --version && git lfs version && /usr/lib/postgresql/17/bin/pg_dump --version - - uses: dtolnay/rust-toolchain@1.99 - - uses: Swatinem/rust-cache@v2 + - uses: dtolnay/rust-toolchain@d124f86f28ff42855784ff3319f48ac182c248f8 # 1.99 + - uses: Swatinem/rust-cache@d1527c8f67ef9af357290475d4af4b0fab8f12e0 # v2.9.3 with: shared-key: test save-if: ${{ matrix.shard == 1 }} @@ -128,9 +128,9 @@ jobs: DATABASE_URL: postgres://forgust:forgust@127.0.0.1:5432/forgust FORGUST_TEST_RUNNER: gitlab/gitlab-runner:${{ matrix.runner }} steps: - - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@1.99 - - uses: Swatinem/rust-cache@v2 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - uses: dtolnay/rust-toolchain@d124f86f28ff42855784ff3319f48ac182c248f8 # 1.99 + - uses: Swatinem/rust-cache@d1527c8f67ef9af357290475d4af4b0fab8f12e0 # v2.9.3 - name: Images run: | pull() { for i in 1 2 3 4; do docker pull -q "$1" && return; sleep 15; done; return 1; } @@ -159,9 +159,9 @@ jobs: FORGUST_TEST_SKOPEO: quay.io/skopeo/stable:v1.22.3 GLAB_VERSION: "1.128.0" steps: - - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@1.99 - - uses: Swatinem/rust-cache@v2 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - uses: dtolnay/rust-toolchain@d124f86f28ff42855784ff3319f48ac182c248f8 # 1.99 + - uses: Swatinem/rust-cache@d1527c8f67ef9af357290475d4af4b0fab8f12e0 # v2.9.3 - name: glab, Renovate and skopeo run: | curl -sSfL "https://gitlab.com/gitlab-org/cli/-/releases/v${GLAB_VERSION}/downloads/glab_${GLAB_VERSION}_linux_amd64.tar.gz" \ @@ -189,8 +189,8 @@ jobs: env: CARGO_DENY: "0.20.2" steps: - - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@1.99 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - uses: dtolnay/rust-toolchain@d124f86f28ff42855784ff3319f48ac182c248f8 # 1.99 - name: cargo-deny run: | curl -sSfL "https://github.com/EmbarkStudios/cargo-deny/releases/download/${CARGO_DENY}/cargo-deny-${CARGO_DENY}-x86_64-unknown-linux-musl.tar.gz" \ @@ -204,10 +204,10 @@ jobs: run: working-directory: web steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0 with: - node-version: 22 + node-version: 26 cache: npm cache-dependency-path: web/package-lock.json - run: npm ci @@ -221,7 +221,7 @@ jobs: if: github.event_name == 'push' runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Build the image run: docker build -t "forgust:ci-${GITHUB_RUN_NUMBER}" . - name: The image starts @@ -248,12 +248,12 @@ jobs: FORGUST_SERVER__DATA_DIR: /tmp/forgust-e2e FORGUST_SERVER__STATIC_DIR: web/dist steps: - - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@1.99 - - uses: Swatinem/rust-cache@v2 - - uses: actions/setup-node@v4 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - uses: dtolnay/rust-toolchain@d124f86f28ff42855784ff3319f48ac182c248f8 # 1.99 + - uses: Swatinem/rust-cache@d1527c8f67ef9af357290475d4af4b0fab8f12e0 # v2.9.3 + - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0 with: - node-version: 22 + node-version: 26 cache: npm cache-dependency-path: web/package-lock.json - name: Build @@ -278,7 +278,7 @@ jobs: - name: Server log if: failure() run: tail -200 /tmp/forgust-e2e.log - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 if: failure() continue-on-error: true with: diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000..f1ddf73 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,43 @@ +name: CodeQL + +# Code scanning for the server (Rust), the web UI (TypeScript) and these +# workflows; findings show in the repository's Security tab. +on: + push: + branches: [main] + pull_request: + # nothing to scan in prose or screenshots; main and the weekly run see everything + paths-ignore: ["**/*.md", ".github/images/**"] + schedule: + - cron: "41 4 * * 1" + +permissions: + contents: read + +concurrency: + group: codeql-${{ github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + +jobs: + analyze: + name: analyze (${{ matrix.language }}) + runs-on: ubuntu-latest + permissions: + contents: read + security-events: write + strategy: + fail-fast: false + matrix: + language: [rust, javascript-typescript, actions] + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + + - uses: github/codeql-action/init@33d7b85da1a04171e211befe2c739303b9a4c066 # v4.39.3 + with: + languages: ${{ matrix.language }} + build-mode: none + config-file: ./.github/codeql/codeql-config.yml + + - uses: github/codeql-action/analyze@33d7b85da1a04171e211befe2c739303b9a4c066 # v4.39.3 + with: + category: /language:${{ matrix.language }} diff --git a/.github/workflows/conformance.yml b/.github/workflows/conformance.yml index af49a4c..abbbb0e 100644 --- a/.github/workflows/conformance.yml +++ b/.github/workflows/conformance.yml @@ -22,7 +22,7 @@ jobs: env: GITLAB_CT: forgust-conformance-${{ github.run_id }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Start GitLab CE run: | docker run -d --name "$GITLAB_CT" -p 8929:8929 --shm-size 256m \ diff --git a/.github/workflows/pr-title.yml b/.github/workflows/pr-title.yml new file mode 100644 index 0000000..6acacce --- /dev/null +++ b/.github/workflows/pr-title.yml @@ -0,0 +1,33 @@ +name: Pull request title + +# Squash merges use the pull request's title as the commit message on main, and +# the release notes are grouped by its type: it must be a Conventional Commit. +on: + pull_request: + types: [opened, edited, synchronize, reopened] + +permissions: + pull-requests: read + +jobs: + conventional: + runs-on: ubuntu-latest + steps: + - uses: amannn/action-semantic-pull-request@2252a14e810aa9b85c2d560bd7070c802206ecf6 # v6.1.2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + types: | + feat + fix + perf + refactor + docs + test + ci + chore + revert + subjectPattern: ^(?![A-Z]).+$ + subjectPatternError: | + The summary "{subject}" starts with a capital letter: write it in lower case, + for example "fix: keep reviewed requests apart in your work". diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..2a3c3e6 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,175 @@ +name: Release + +# Pushing a tag vX.Y.Z publishes ghcr.io/forgust-dev/forgust:X.Y.Z (and X.Y, +# latest) for amd64 and arm64, then opens a draft GitHub release with notes +# grouped from the commit subjects since the last tag (.github/release-notes.sh). +# Each architecture builds on its own runner: a Rust release build under +# emulation would take hours. +on: + push: + tags: ["v*"] + +permissions: + contents: read + +env: + IMAGE: ghcr.io/${{ github.repository }} + DESCRIPTION: A fast, self-hosted code forge written in Rust + +jobs: + check: + # the tag names the version in Cargo.toml and web/package.json, on a commit of main + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + fetch-depth: 0 + - name: Tag, versions and branch agree + run: | + tag="${GITHUB_REF_NAME#v}" + cargo=$(sed -n 's/^version = "\(.*\)"/\1/p' Cargo.toml | head -1) + web=$(jq -r .version web/package.json) + echo "tag $tag, Cargo.toml $cargo, web/package.json $web" + [ "$tag" = "$cargo" ] && [ "$tag" = "$web" ] || { echo "::error::the tag does not match the versions"; exit 1; } + git merge-base --is-ancestor "$GITHUB_SHA" origin/main || { echo "::error::the tag is not on main"; exit 1; } + + build: + name: build (${{ matrix.arch }}) + needs: check + strategy: + matrix: + include: + - arch: amd64 + runner: ubuntu-latest + - arch: arm64 + runner: ubuntu-24.04-arm + runs-on: ${{ matrix.runner }} + permissions: + contents: read + packages: write + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + + - uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1 + + - uses: docker/login-action@8aa5831fb8d48d8f76594c7ddde61ae58019f550 # v4.8.0 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0 + id: meta + with: + images: ${{ env.IMAGE }} + labels: | + org.opencontainers.image.title=Forgust + org.opencontainers.image.description=${{ env.DESCRIPTION }} + org.opencontainers.image.documentation=https://github.com/${{ github.repository }}#readme + org.opencontainers.image.vendor=Forgust + + # pushed by digest only: the merge job names the multi-arch image + - uses: docker/build-push-action@c3c9e263c25d99ce0380d002d59b67737d91b0dc # v7.4.0 + id: build + with: + context: . + platforms: linux/${{ matrix.arch }} + labels: ${{ steps.meta.outputs.labels }} + outputs: type=image,name=${{ env.IMAGE }},push-by-digest=true,name-canonical=true,push=true + provenance: mode=max + sbom: true + + - name: Check that it starts, then export its digest + run: | + docker run --rm "$IMAGE@$DIGEST" --version + mkdir -p /tmp/digests + touch "/tmp/digests/${DIGEST#sha256:}" + env: + DIGEST: ${{ steps.build.outputs.digest }} + + - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 + with: + name: digests-${{ matrix.arch }} + path: /tmp/digests/* + if-no-files-found: error + retention-days: 1 + + publish: + # one multi-arch image under the version tags + needs: build + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + steps: + - uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 + with: + path: /tmp/digests + pattern: digests-* + merge-multiple: true + + - uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1 + + - uses: docker/login-action@8aa5831fb8d48d8f76594c7ddde61ae58019f550 # v4.8.0 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0 + id: meta + env: + DOCKER_METADATA_ANNOTATIONS_LEVELS: index + with: + images: ${{ env.IMAGE }} + # X.Y.Z, X.Y and latest; a pre-release (v1.2.0-rc.1) gets its version only + tags: | + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + annotations: | + org.opencontainers.image.description=${{ env.DESCRIPTION }} + + - name: Create the multi-arch image + working-directory: /tmp/digests + run: | + # tags and the index's annotations (source, version, licenses...) from metadata-action + mapfile -t args < <(jq -r '(.tags[] | "-t", .), (.annotations[] | "--annotation", .)' <<< "$DOCKER_METADATA_OUTPUT_JSON") + docker buildx imagetools create "${args[@]}" $(printf "$IMAGE@sha256:%s " *) + + - name: Inspect + run: docker buildx imagetools inspect "$IMAGE:$VERSION" + env: + VERSION: ${{ steps.meta.outputs.version }} + + release: + # a draft: read the notes, then publish it + needs: publish + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + fetch-depth: 0 + + - name: Draft the GitHub release + env: + GH_TOKEN: ${{ github.token }} + run: | + version="${GITHUB_REF_NAME#v}" + # the previous release: a final release (v0.2.0) looks past its release + # candidates (v0.2.0-rc.1), so its notes cover everything since v0.1.0 + exclude=$([[ "$GITHUB_REF_NAME" == *-* ]] || echo "--exclude=*-*") + prev=$(git describe --tags --abbrev=0 --match 'v*' $exclude "$GITHUB_REF_NAME^" 2>/dev/null || true) + { + echo "Image: \`docker pull $IMAGE:$version\`" + echo + .github/release-notes.sh "$prev" "$GITHUB_REF_NAME" + if [ -n "$prev" ]; then + echo "**Full Changelog**: $GITHUB_SERVER_URL/$GITHUB_REPOSITORY/compare/$prev...$GITHUB_REF_NAME" + fi + } > notes.md + cat notes.md + prerelease=$([[ "$GITHUB_REF_NAME" == *-* ]] && echo --prerelease || true) + gh release create "$GITHUB_REF_NAME" --repo "$GITHUB_REPOSITORY" --verify-tag --draft $prerelease \ + --title "$version" --notes-file notes.md diff --git a/.gitignore b/.gitignore index faecf63..6cdf721 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ /target /data /web/node_modules +/web/tools/gen-api/node_modules /web/dist /bench/results .env diff --git a/.gitleaks.toml b/.gitleaks.toml new file mode 100644 index 0000000..fad4533 --- /dev/null +++ b/.gitleaks.toml @@ -0,0 +1,14 @@ +# gitleaks: values that look like secrets here but are not. The default rules +# still apply everywhere, these files included. +[extend] +useDefault = true + +[[allowlists]] +description = "Test fixtures, and the throwaway token the nightly GitLab CE job creates" +regexTarget = "match" +regexes = [ + # .github/workflows/conformance.yml: set on a GitLab container that lives for one job + '''glpat-conformance-0+''', + # tests/m6_everyday.rs: a test user's password + '''alice-owns-this-1''', +] diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1c791ed..4fd1d4a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -17,7 +17,7 @@ Thanks for helping. Bug reports, fixes, docs and tests are all welcome. ## Set up -See [Development](README.md#development) in the README: Rust, git, Node 22, and Docker for +See [Development](README.md#development) in the README: Rust, git, Node 26, and Docker for Postgres, S3 and SMTP. ## Before you open a pull request @@ -38,12 +38,18 @@ And when you changed: - **the API:** `cargo run -p forgust-server -- openapi > web/openapi.json`, then `(cd web && npm run gen:api)`; a unit test fails while they are stale; - **the UI:** the Playwright tests (`cd web && npm run e2e`), at desktop width and - 390 px; + 390 px; if a page in the README changed, its screenshots too + (`node deploy/screenshots.mjs`, see the script for the demo it needs); - **CI behaviour:** a case in [`ci-conformance/cases/`](ci-conformance/README.md), and a note in the pull request for the CI compatibility guide. -Keep each pull request to one change, with tests. Commit messages start with the -area, then say what changed: `CI: one run at a time on the runner`. +Keep each pull request to one change, with tests. Commit messages and pull request +titles follow [Conventional Commits](https://www.conventionalcommits.org/): a type, +then what the change does, in lower case (`fix: keep reviewed requests apart in your +work`). Types: `feat`, `fix`, `perf`, `refactor`, `docs`, `test`, `ci`, `chore`, +`revert`; add `!` for a breaking change (`feat!: …`). Pull requests are squashed, so +their title becomes the commit on `main` and the line in the release notes: CI checks +it. ## Sign your commits (DCO) @@ -58,3 +64,19 @@ git commit -s adds the line from your `user.name` and `user.email`. To sign commits you already made: `git rebase --signoff main`. + +## Releasing (maintainers) + +1. In a pull request, set the new version in `Cargo.toml` (`[workspace.package]`) and + `web/package.json`, then refresh the lock files (`cargo check`, + `cd web && npm install`): `chore: release 0.2.0`. +2. Once it is merged, tag that commit of `main` and push the tag: + `git tag v0.2.0 && git push origin v0.2.0`. +3. The release workflow checks that the tag matches both versions and is on `main`, + builds the image for amd64 and arm64, pushes `ghcr.io/forgust-dev/forgust` as + `0.2.0`, `0.2` and `latest`, and opens a draft GitHub release whose notes group the + commits since the previous release (its release candidates included) by type. + Edit the notes, then publish it. To preview them before tagging: + `.github/release-notes.sh v0.1.0 main`. + +A tag such as `v0.2.0-rc.1` makes a pre-release: no `0.2` or `latest` tag. diff --git a/Cargo.lock b/Cargo.lock index 1d68bbd..c779cf2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -107,9 +107,9 @@ checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "ammonia" -version = "4.2.4" +version = "4.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f45dfa685e1ec33b1bf1a3b93b8047cbdbef41b6040deebbe6bea7720a45574" +checksum = "b34ca49e407c06daac53f0c4debe8ff5df9cc2a4e9369d164a5d86ef8c219319" dependencies = [ "cssparser", "html5ever", @@ -184,9 +184,9 @@ checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470" [[package]] name = "arc-swap" -version = "1.9.3" +version = "1.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "380962b3d93b99642e50b9febf72c071e97e8b32d86eae9cf4ef582bb960ae6e" +checksum = "84a22b5d51209f6de83d37a0b33d320acb8da88823e42a94c075140708f032a5" dependencies = [ "rustversion", ] @@ -313,7 +313,7 @@ checksum = "82f6aeea286b8eb4dd3431a1be1b59d290ace00f5bfd8e2a159bc2a05e2c1667" dependencies = [ "proc-macro2", "quote", - "syn 3.0.9", + "syn 3.0.10", ] [[package]] @@ -425,14 +425,15 @@ dependencies = [ [[package]] name = "axum-extra" -version = "0.10.3" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9963ff19f40c6102c76756ef0a46004c0d58957d87259fc9208ff8441c12ab96" +checksum = "be44683b41ccb9ab2d23a5230015c9c3c55be97a25e4428366de8873103f7970" dependencies = [ "axum", "axum-core", "bytes", "cookie", + "futures-core", "futures-util", "headers", "http", @@ -440,8 +441,6 @@ dependencies = [ "http-body-util", "mime", "pin-project-lite", - "rustversion", - "serde_core", "tower-layer", "tower-service", "tracing", @@ -672,7 +671,7 @@ dependencies = [ "prettyplease", "proc-macro2", "quote", - "syn 3.0.9", + "syn 3.0.10", ] [[package]] @@ -834,7 +833,7 @@ dependencies = [ "num-traits", "serde", "wasm-bindgen", - "windows-link", + "windows-link 0.2.1", ] [[package]] @@ -901,7 +900,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 3.0.9", + "syn 3.0.10", ] [[package]] @@ -986,20 +985,25 @@ checksum = "2ebdda89edc534bf8d5dd2857562633b6495557e5846552ade994b99ed13c36a" [[package]] name = "comrak" -version = "0.39.1" +version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fefab951771fc3beeed0773ce66a4f7b706273fc6c4c95b08dd1615744abcf5" +checksum = "3adf553d37681e21753316065ad5a763d9513f81c910e250576c572114a8eb06" dependencies = [ "bon", "caseless", "clap", + "emojis", "entities", - "memchr", + "finl_unicode", + "fmt2io", + "memchr-n", + "phf 0.14.0", + "phf_codegen", + "rustc-hash", "shell-words", - "slug", + "smallvec", "syntect", "typed-arena", - "unicode_categories", "xdg", ] @@ -1026,9 +1030,9 @@ checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" [[package]] name = "constant_time_eq" -version = "0.3.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" +checksum = "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b" [[package]] name = "convert_case" @@ -1129,9 +1133,9 @@ checksum = "fd121741cf3eb82c08dd3023eb55bf2665e5f60ec20f89760cf836ae4562e6a0" [[package]] name = "crc32fast" -version = "1.5.4" +version = "1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f97d3416d5337d15c4b0d78c8c91df922ca143f57ec20e2d1c188333047ef04" +checksum = "2b929dd2a135771f40afabd1073f85eed59c800b7c61901e5c254270497dad64" dependencies = [ "cfg-if 1.0.5", ] @@ -1204,9 +1208,9 @@ dependencies = [ [[package]] name = "crypto-bigint" -version = "0.7.10" +version = "0.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c035cb64cba03dad2fb921f3e218785e8cf9a41790da5eb3a1400f62fa2be11" +checksum = "914c195c4d7fbc5ed7f88d14cbf85914d5c664967658d43404b263913a477e82" dependencies = [ "cpubits", "ctutils", @@ -1247,7 +1251,7 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3633a51a39c69ebbaa4feaa694bd83d241e4093901c84a0963b19d9bb3f0cf8f" dependencies = [ - "crypto-bigint 0.7.10", + "crypto-bigint 0.7.11", "rand_core 0.10.1", ] @@ -1395,7 +1399,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 3.0.9", + "syn 3.0.10", ] [[package]] @@ -1417,7 +1421,7 @@ checksum = "2ac7135c3ef02b2f7833bbeb1be5ba7f966dcde8a87c6b87f65a778d71a02785" dependencies = [ "darling_core 0.24.1", "quote", - "syn 3.0.9", + "syn 3.0.10", ] [[package]] @@ -1463,7 +1467,7 @@ dependencies = [ "defmt-parser", "proc-macro2", "quote", - "syn 3.0.9", + "syn 3.0.10", ] [[package]] @@ -1602,12 +1606,6 @@ dependencies = [ "cipher 0.5.2", ] -[[package]] -name = "deunicode" -version = "1.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abd57806937c9cc163efc8ea3910e00a62e2aeb0b8119f1793a978088f8f6b04" - [[package]] name = "digest" version = "0.10.7" @@ -1640,7 +1638,7 @@ checksum = "c6232dd377dcc64799954cbd3a9bb882e9cdc1308ccd87b1c098f1fb2eaf82a8" dependencies = [ "proc-macro2", "quote", - "syn 3.0.9", + "syn 3.0.10", ] [[package]] @@ -1826,7 +1824,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "900f37e7e18d74a2347389af6cd69e3a30d5cc9e697f40004865679aa75e9c7c" dependencies = [ "base16ct 1.0.0", - "crypto-bigint 0.7.10", + "crypto-bigint 0.7.11", "crypto-common 0.2.2", "digest 0.11.3", "ff 0.14.0", @@ -1843,9 +1841,9 @@ dependencies = [ [[package]] name = "email-encoding" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "420b9da095f052ea597503e39073b5b3c522f7db933fbac202d91d24492693fd" +checksum = "9f690ae2169f2ceb3f45b28b6fcd8fa16839f2f5c8818546774b9425f5f71004" dependencies = [ "base64 0.23.1", "memchr", @@ -1857,6 +1855,15 @@ version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e079f19b08ca6239f47f8ba8509c11cf3ea30095831f7fed61441475edd8c449" +[[package]] +name = "emojis" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589871e639330783bc20ad89d32ac1b049e02c273d96c907ca27478c8bc674a2" +dependencies = [ + "phf 0.13.1", +] + [[package]] name = "encoding_rs" version = "0.7.2" @@ -1944,6 +1951,17 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "evmap" +version = "11.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b8874945f036109c72242964c1174cf99434e30cfa45bf45fedc983f50046f8" +dependencies = [ + "hashbag", + "left-right", + "smallvec", +] + [[package]] name = "fallible-iterator" version = "0.2.0" @@ -1988,6 +2006,23 @@ dependencies = [ "simd-adler32", ] +[[package]] +name = "fearless_simd" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "629c9d6b6f30b5604089e0980f4d924a013aacb1654a6cdf5d3d852224f68651" + +[[package]] +name = "fearless_simd_macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e91d94c6885390b81782d7ee60fd6583b33907333a8b340de25ccf468353315" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.10", +] + [[package]] name = "ff" version = "0.13.1" @@ -2051,6 +2086,12 @@ version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c66915cc5391097de7a2b0b972e8505aa33c0df401fd3a6811dbdb32881ba48" +[[package]] +name = "finl_unicode" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ded33109e99472f809cb7495544506eea45e366725dacf2a383e184f660456" + [[package]] name = "flagset" version = "0.4.7" @@ -2079,6 +2120,12 @@ dependencies = [ "spin 0.9.9", ] +[[package]] +name = "fmt2io" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b6129284da9f7e5296cc22183a63f24300e945e297705dcc0672f7df01d62c8" + [[package]] name = "fnv" version = "1.0.7" @@ -2139,15 +2186,15 @@ dependencies = [ name = "forgust-server" version = "0.1.0" dependencies = [ - "aes-gcm 0.10.3", + "aes-gcm 0.11.1", "ammonia", "anyhow", - "argon2 0.5.3", + "argon2 0.6.0", "async-compression", "async-trait", "axum", "axum-extra", - "base64 0.22.1", + "base64 0.23.1", "bytes", "chrono", "chrono-tz", @@ -2162,7 +2209,7 @@ dependencies = [ "globset", "graphile_worker", "hex", - "hmac 0.12.1", + "hmac 0.13.0", "http-body-util", "hyper", "hyper-util", @@ -2181,14 +2228,14 @@ dependencies = [ "percent-encoding", "pgp", "quick-xml 0.42.0", - "rand 0.8.8", + "rand 0.10.3", "regex", - "reqwest 0.12.28", + "reqwest 0.13.5", "ring", "russh", "serde", "serde_json", - "sha2 0.10.9", + "sha2 0.11.1", "sqlx", "syntect", "tempfile", @@ -2199,7 +2246,7 @@ dependencies = [ "tokio-util", "totp-rs", "tower", - "tower-http", + "tower-http 0.7.1", "tracing", "tracing-opentelemetry", "tracing-subscriber", @@ -2219,7 +2266,7 @@ dependencies = [ "hex", "lru", "serde", - "sha2 0.10.9", + "sha2 0.11.1", "tempfile", "thiserror 2.0.21", "tokio", @@ -2326,7 +2373,7 @@ checksum = "9fb9654ba8355388abeb8dcb4fc62f511300867002afc858860463bdd9fe0c44" dependencies = [ "proc-macro2", "quote", - "syn 3.0.9", + "syn 3.0.10", ] [[package]] @@ -2358,6 +2405,20 @@ dependencies = [ "slab", ] +[[package]] +name = "generator" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea6c6a73cd1aa4f4f00c02b109fa55d3a9d6ecc2fc4f53177b74ed6ee23b0c53" +dependencies = [ + "cc", + "libc", + "log", + "rustversion", + "windows-core 0.100.0", + "windows-sys 0.61.2", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -3354,7 +3415,7 @@ dependencies = [ "graphile_worker_migrations_core", "proc-macro2", "quote", - "syn 3.0.9", + "syn 3.0.10", ] [[package]] @@ -3525,6 +3586,12 @@ dependencies = [ "byteorder", ] +[[package]] +name = "hashbag" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7040a10f52cba493ddb09926e15d10a9d8a28043708a405931fe4c6f19fac064" + [[package]] name = "hashbrown" version = "0.12.3" @@ -3832,7 +3899,7 @@ dependencies = [ "js-sys", "log", "wasm-bindgen", - "windows-core", + "windows-core 0.62.2", ] [[package]] @@ -4083,17 +4150,16 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.18" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" +checksum = "3bd1574e617a9a6c1f8f8181bd7e841e1f20e4277607ef28945765188d6284d4" [[package]] name = "jiff" -version = "0.2.39" +version = "0.2.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ac703058abac89e5c39b0b879dce2b6b14a4ba36600c7e7e3d0c60a6883ef3c" +checksum = "26699905cc795a23e3949585cc7ba3ee8ade090872a27e4316304a777297894a" dependencies = [ - "defmt 1.2.0", "jiff-core", "jiff-static", "jiff-tzdb-platform", @@ -4101,24 +4167,23 @@ dependencies = [ "portable-atomic", "portable-atomic-util", "serde_core", - "windows-link", + "windows-link 0.2.1", ] [[package]] name = "jiff-core" -version = "0.1.2" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aee43309eb53bafb8c36d35d6e444769c8f8e6206a9fbf7546f5db9d7d4a0e93" +checksum = "ffe6854081f5ac0a3046a9b223729ccd7a20b1e0e8277e44dc0660eedf67dfe2" dependencies = [ - "defmt 1.2.0", "log", ] [[package]] name = "jiff-static" -version = "0.2.39" +version = "0.2.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dc32470c67eb7d0e9ccb74303fa925313dc04cecb1aa048beaa6f391e36a93d" +checksum = "4b4ff49b2887190c760b86207b55cdcaabbdecaf7a0660d68aa2ed6f652abf0a" dependencies = [ "jiff-core", "proc-macro2", @@ -4155,7 +4220,7 @@ dependencies = [ "simd_cesu8", "thiserror 2.0.21", "walkdir", - "windows-link", + "windows-link 0.2.1", ] [[package]] @@ -4273,6 +4338,17 @@ dependencies = [ "spin 0.9.9", ] +[[package]] +name = "left-right" +version = "0.11.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bc015ded5d9b3054dbbdb63332cdd6ee42352ccef19e911e25117490e2f48ee" +dependencies = [ + "crossbeam-utils", + "loom", + "slab", +] + [[package]] name = "lettre" version = "0.11.23" @@ -4323,9 +4399,9 @@ dependencies = [ [[package]] name = "libsqlite3-sys" -version = "0.30.1" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" +checksum = "b1f111c8c41e7c61a49cd34e44c7619462967221a6443b0ec299e0ac30cfb9b1" dependencies = [ "pkg-config", "vcpkg", @@ -4364,11 +4440,24 @@ version = "0.4.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d15f86d12da44cd8d4ec3c73984537eb7f4cadcb9776a575a0a8a05ca11005c" +[[package]] +name = "loom" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1611ddbf89dc6ae42cfbd51fc207836140130257646eab8d6d2fb16577db2d2" +dependencies = [ + "cfg-if 1.0.5", + "generator", + "scoped-tls", + "tracing", + "tracing-subscriber", +] + [[package]] name = "lru" -version = "0.18.5" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef9ac18847474e638e3702b76c65d4eb93428471a74778ef0f1be711717f89b5" +checksum = "4a9f71e3591c7ec44d3e563e87bf14ddc2bada8519dca046e5b0e560cd004e2d" dependencies = [ "hashbrown 0.17.1", ] @@ -4443,6 +4532,16 @@ version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" +[[package]] +name = "memchr-n" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f48c6352cc1185740af256ccc396af598d2366bfd90a34f5afe48744bf06a5b5" +dependencies = [ + "fearless_simd", + "fearless_simd_macros", +] + [[package]] name = "memmap2" version = "0.9.12" @@ -4464,11 +4563,12 @@ dependencies = [ [[package]] name = "metrics-exporter-prometheus" -version = "0.17.2" +version = "0.18.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b166dea96003ee2531cf14833efedced545751d800f03535801d833313f8c15" +checksum = "1db0d8f1fc9e62caebd0319e11eaec5822b0186c171568f0480b46a0137f9108" dependencies = [ "base64 0.22.1", + "evmap", "indexmap 2.14.2", "metrics", "metrics-util", @@ -4928,9 +5028,9 @@ checksum = "7e036b411754132fd6b74e94b74e9a13c5cf606fa93d1885c35860d3060820b1" [[package]] name = "opentelemetry" -version = "0.30.0" +version = "0.33.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aaf416e4cb72756655126f7dd7bb0af49c674f4c1b9903e80c009e0c37e552e6" +checksum = "8c1f1a6ac9c875a4941e4c7c085b61e8f4daa326de03b4701768c3491a6ad9ee" dependencies = [ "futures-core", "futures-sink", @@ -4942,61 +5042,63 @@ dependencies = [ [[package]] name = "opentelemetry-http" -version = "0.30.0" +version = "0.33.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f6639e842a97dbea8886e3439710ae463120091e2e064518ba8e716e6ac36d" +checksum = "302249bd8ee804789faaa7b5b2cbf79bc61cb864714079c644e3828af5b7e811" dependencies = [ "async-trait", "bytes", "http", "opentelemetry", - "reqwest 0.12.28", + "reqwest 0.13.5", ] [[package]] name = "opentelemetry-otlp" -version = "0.30.0" +version = "0.33.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbee664a43e07615731afc539ca60c6d9f1a9425e25ca09c57bc36c87c55852b" +checksum = "0756af24841e367128ef31c831999937b8b5c5197d47914590d8f4e2e88c2e1a" dependencies = [ "http", + "httpdate", "opentelemetry", "opentelemetry-http", "opentelemetry-proto", "opentelemetry_sdk", "prost", - "reqwest 0.12.28", + "reqwest 0.13.5", "thiserror 2.0.21", "tokio", "tonic", - "tracing", + "tonic-types", ] [[package]] name = "opentelemetry-proto" -version = "0.30.0" +version = "0.33.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e046fd7660710fe5a05e8748e70d9058dc15c94ba914e7c4faa7c728f0e8ddc" +checksum = "d576f5dddc3299341bcd85a04be17b2564844c0c9563214f02d85f2524d1afae" dependencies = [ "opentelemetry", "opentelemetry_sdk", "prost", "tonic", + "tonic-prost", ] [[package]] name = "opentelemetry_sdk" -version = "0.30.0" +version = "0.33.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11f644aa9e5e31d11896e024305d7e3c98a88884d9f8919dbf37a9991bc47a4b" +checksum = "372a912db2974d1990207006fd0e3aa0ef3fd4ad3be43c65cfaadf2206866061" dependencies = [ "futures-channel", "futures-executor", "futures-util", "opentelemetry", "percent-encoding", + "portable-atomic", "rand 0.9.5", - "serde_json", "thiserror 2.0.21", "tokio", "tokio-stream", @@ -5116,7 +5218,7 @@ dependencies = [ "thiserror 2.0.21", "tokio", "windows", - "windows-strings", + "windows-strings 0.5.1", ] [[package]] @@ -5145,7 +5247,7 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-link", + "windows-link 0.2.1", ] [[package]] @@ -5165,6 +5267,7 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aab41826031698d6ffcd9cff78ef56ef998e39dc7e5067cdfebe373842d4723b" dependencies = [ + "getrandom 0.4.3", "phc", ] @@ -5302,6 +5405,7 @@ checksum = "44dc769b75f93afdddd8c7fa12d685292ddeff1e66f7f0f3a234cf1818afe892" dependencies = [ "base64ct", "ctutils", + "getrandom 0.4.3", ] [[package]] @@ -5632,7 +5736,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2bfe0f4c752e450fc2faf62654f1c134747922825d5b04ca717b8874f41a40c0" dependencies = [ "proc-macro2", - "syn 3.0.9", + "syn 3.0.10", ] [[package]] @@ -5641,7 +5745,7 @@ version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c555a6e4eb7d4e158fcb028c835c3b8642206ddc279b5c6b202ef9a8bdb592f4" dependencies = [ - "crypto-bigint 0.7.10", + "crypto-bigint 0.7.11", "crypto-common 0.2.2", "ff 0.14.0", "rand_core 0.10.1", @@ -5704,9 +5808,9 @@ dependencies = [ [[package]] name = "prost" -version = "0.13.5" +version = "0.14.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2796faa41db3ec313a31f7624d9286acf277b52de526150b7e69f3debf891ee5" +checksum = "3ef0b569d1d907ab3a28596aee62cf1f61dacb0529a4bedcd8e7460e2d5228b4" dependencies = [ "bytes", "prost-derive", @@ -5714,17 +5818,26 @@ dependencies = [ [[package]] name = "prost-derive" -version = "0.13.5" +version = "0.14.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" +checksum = "1ad9c5423459fa2f729b8d9235fab810aa29628b171467744fc86d21460ad70d" dependencies = [ "anyhow", - "itertools 0.14.0", + "itertools 0.15.0", "proc-macro2", "quote", "syn 2.0.119", ] +[[package]] +name = "prost-types" +version = "0.14.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f29a7c4c7a84cef41a53d338a2d10d4f1b043ea5c3dde26db22ee2c9c1b1c75b" +dependencies = [ + "prost", +] + [[package]] name = "pxfm" version = "0.1.30" @@ -5999,7 +6112,7 @@ checksum = "92ecd8964f8453721699a1ed72037b0db49ce2f5a5138486ee89bed6f67cdf3a" dependencies = [ "proc-macro2", "quote", - "syn 3.0.9", + "syn 3.0.10", ] [[package]] @@ -6045,9 +6158,7 @@ checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" dependencies = [ "base64 0.22.1", "bytes", - "futures-channel", "futures-core", - "futures-util", "http", "http-body", "http-body-util", @@ -6056,7 +6167,6 @@ dependencies = [ "hyper-util", "js-sys", "log", - "mime_guess", "percent-encoding", "pin-project-lite", "quinn", @@ -6068,14 +6178,12 @@ dependencies = [ "sync_wrapper", "tokio", "tokio-rustls", - "tokio-util", "tower", - "tower-http", + "tower-http 0.6.11", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", - "wasm-streams 0.4.2", "web-sys", "webpki-roots", ] @@ -6088,6 +6196,7 @@ checksum = "16a1cfa75cc186dd73d5818e510e042e40927bccc9c236b061cea97e1eb08029" dependencies = [ "base64 0.23.1", "bytes", + "futures-channel", "futures-core", "futures-util", "h2", @@ -6099,23 +6208,27 @@ dependencies = [ "hyper-util", "js-sys", "log", + "mime_guess", "percent-encoding", "pin-project-lite", "quinn", "rustls", "rustls-pki-types", "rustls-platform-verifier", + "serde", + "serde_json", + "serde_urlencoded", "sync_wrapper", "tokio", "tokio-rustls", "tokio-util", "tower", - "tower-http", + "tower-http 0.6.11", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", - "wasm-streams 0.5.0", + "wasm-streams", "web-sys", ] @@ -6135,7 +6248,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4a459cddafb3fe76b31fd8f1108007566c40301feb64dc7b54656eb7388172b" dependencies = [ - "crypto-bigint 0.7.10", + "crypto-bigint 0.7.11", "hmac 0.13.0", ] @@ -6189,7 +6302,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "30b2aa4ba0d89f73d1e332df05be0eeab8840351c36ca5654341dfdb57bb3caf" dependencies = [ "const-oid 0.10.2", - "crypto-bigint 0.7.10", + "crypto-bigint 0.7.11", "crypto-primes", "digest 0.11.3", "pkcs1 0.8.0-rc.4", @@ -6215,7 +6328,7 @@ dependencies = [ "bytes", "cbc", "cipher 0.5.2", - "crypto-bigint 0.7.10", + "crypto-bigint 0.7.11", "ctr 0.10.1", "curve25519-dalek 5.0.0", "data-encoding", @@ -6497,6 +6610,12 @@ dependencies = [ "serde_json", ] +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + [[package]] name = "scopeguard" version = "1.2.0" @@ -6610,7 +6729,7 @@ checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" dependencies = [ "proc-macro2", "quote", - "syn 3.0.9", + "syn 3.0.10", ] [[package]] @@ -6709,7 +6828,7 @@ dependencies = [ "darling 0.24.1", "proc-macro2", "quote", - "syn 3.0.9", + "syn 3.0.10", ] [[package]] @@ -6926,16 +7045,6 @@ version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" -[[package]] -name = "slug" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "882a80f72ee45de3cc9a5afeb2da0331d58df69e4e7d8eeb5d3c7784ae67e724" -dependencies = [ - "deunicode", - "wasm-bindgen", -] - [[package]] name = "smallvec" version = "1.16.5" @@ -7224,7 +7333,7 @@ checksum = "7b54d0ed0498daf3f78d82e00e28c8eec9d75a067c4cfbcc7a0f7d0f4077749e" dependencies = [ "base64ct", "bytes", - "crypto-bigint 0.7.10", + "crypto-bigint 0.7.11", "ctutils", "digest 0.11.3", "pem-rfc7468 1.0.0", @@ -7344,9 +7453,9 @@ dependencies = [ [[package]] name = "syn" -version = "3.0.9" +version = "3.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d78c8dee4c7bf0e14673097256fed6142ce9d3b85a408189d07482442145823b" +checksum = "4ae9ccbea3a7b0b09443036490c8f34a8b1b760fd345e5c0dae0aac718faea79" dependencies = [ "proc-macro2", "quote", @@ -7370,7 +7479,7 @@ checksum = "901704edd0dfe137f1987838ee4f259e4e063c31371bdb423f7ae38ec6f77f02" dependencies = [ "proc-macro2", "quote", - "syn 3.0.9", + "syn 3.0.10", ] [[package]] @@ -7476,7 +7585,7 @@ checksum = "fe5197923287db20a58125f0bc85c062f7f2c892de97b18c356f9efb14b28524" dependencies = [ "proc-macro2", "quote", - "syn 3.0.9", + "syn 3.0.10", ] [[package]] @@ -7580,7 +7689,7 @@ checksum = "78773a2a397f451582ce068015985c33193cf6dea8b74d2a639fe457b2f07b0e" dependencies = [ "proc-macro2", "quote", - "syn 3.0.9", + "syn 3.0.10", ] [[package]] @@ -7703,13 +7812,14 @@ checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" [[package]] name = "tonic" -version = "0.13.1" +version = "0.14.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e581ba15a835f4d9ea06c55ab1bd4dce26fc53752c69a04aac00703bfb49ba9" +checksum = "e2cdfc673aabd30fe8fee92e65837b644c37c5d47f0f97ae6d5e0f1237d15e1b" dependencies = [ "async-trait", "base64 0.22.1", "bytes", + "h2", "http", "http-body", "http-body-util", @@ -7718,29 +7828,54 @@ dependencies = [ "hyper-util", "percent-encoding", "pin-project", - "prost", + "sync_wrapper", "tokio", "tokio-stream", + "tokio-util", "tower", "tower-layer", "tower-service", "tracing", ] +[[package]] +name = "tonic-prost" +version = "0.14.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eba464054e2226f182a34489b8b079bf4c6e3e7ab5fd7fc30e024f24aa92a484" +dependencies = [ + "bytes", + "prost", + "tonic", +] + +[[package]] +name = "tonic-types" +version = "0.14.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccbb6c31deb8e99dcdf87df19c5289b7838a600da74a8224baa671e52fe7c5ad" +dependencies = [ + "prost", + "prost-types", + "tonic", +] + [[package]] name = "totp-rs" -version = "5.7.2" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50e69a15e21b2ff22c415446983978bded3244195f17d59cb113551c1e806f91" +checksum = "49d0f9b7aa5def86d3a8d8ba926fe8c1990924dd715d2b5fc54a4aa3788c11c1" dependencies = [ "base32", "constant_time_eq", - "hmac 0.12.1", - "rand 0.9.5", - "sha1 0.10.7", - "sha2 0.10.9", + "hmac 0.13.0", + "percent-encoding", + "rand 0.10.3", + "serde", + "sha1 0.11.0", + "sha2 0.11.1", "url", - "urlencoding", + "zeroize", ] [[package]] @@ -7767,6 +7902,24 @@ name = "tower-http" version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840" +dependencies = [ + "bitflags 2.13.2", + "bytes", + "futures-util", + "http", + "http-body", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", + "url", +] + +[[package]] +name = "tower-http" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08a05a66a4fdd61cbbe0a1d755ffe0ca6aba159dd4820936a0ff8a8278245b9c" dependencies = [ "async-compression", "bitflags 2.13.2", @@ -7784,11 +7937,9 @@ dependencies = [ "pin-project-lite", "tokio", "tokio-util", - "tower", "tower-layer", "tower-service", "tracing", - "url", "uuid", ] @@ -7850,14 +8001,12 @@ dependencies = [ [[package]] name = "tracing-opentelemetry" -version = "0.31.0" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddcf5959f39507d0d04d6413119c04f33b623f4f951ebcbdddddfad2d0623a9c" +checksum = "0a904802a1b902f43638b677ff2a650847e3b4404101b6c586d648e8c1e3e8fe" dependencies = [ "js-sys", - "once_cell", "opentelemetry", - "opentelemetry_sdk", "smallvec", "tracing", "tracing-core", @@ -7999,12 +8148,6 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" -[[package]] -name = "unicode_categories" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" - [[package]] name = "universal-hash" version = "0.5.1" @@ -8044,12 +8187,6 @@ dependencies = [ "serde_derive", ] -[[package]] -name = "urlencoding" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" - [[package]] name = "utf8_iter" version = "1.1.0" @@ -8073,9 +8210,9 @@ checksum = "3a3b425286980a367278453f3b6d28cdcb134b574e5a35824a6ff5eebad50bb6" [[package]] name = "utoipa" -version = "5.5.0" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bde15df68e80b16c7d16b9616e80770ad158988daa56a27dccd1e55558b0160" +checksum = "8765fe27aeff71012a3f90fa474cf1df863a7d0dd81ed25de4e63fff2544994f" dependencies = [ "indexmap 2.14.2", "serde", @@ -8085,20 +8222,20 @@ dependencies = [ [[package]] name = "utoipa-gen" -version = "5.5.0" +version = "6.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ba0b99ee52df3028635d93840c797102da61f8a7bb3cf751032455895b52ef8" +checksum = "d935f1c83fdf8b88f09bbe050d0cea78ea4afee6d7b0317403228c1200b2c8ab" dependencies = [ "proc-macro2", "quote", - "syn 2.0.119", + "syn 3.0.10", ] [[package]] name = "uuid" -version = "1.29.1" +version = "1.29.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a06f08a856b009bc7bbaf7d3e79808595d032dd19074c0c2ef26e49e03e6bdc" +checksum = "bed99139f7dac9b5cfe5f17be4d66dc7079a34dee1d74bcc77217119240e267c" dependencies = [ "getrandom 0.4.3", "js-sys", @@ -8218,7 +8355,7 @@ dependencies = [ "bumpalo", "proc-macro2", "quote", - "syn 3.0.9", + "syn 3.0.10", "wasm-bindgen-shared", ] @@ -8231,19 +8368,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "wasm-streams" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65" -dependencies = [ - "futures-util", - "js-sys", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - [[package]] name = "wasm-streams" version = "0.5.0" @@ -8364,7 +8488,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "527fadee13e0c05939a6a05d5bd6eec6cd2e3dbd648b9f8e447c6518133d8580" dependencies = [ "windows-collections", - "windows-core", + "windows-core 0.62.2", "windows-future", "windows-numerics", ] @@ -8375,7 +8499,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23b2d95af1a8a14a3c7367e1ed4fc9c20e0a26e79551b1454d72583c97cc6610" dependencies = [ - "windows-core", + "windows-core 0.62.2", ] [[package]] @@ -8384,11 +8508,24 @@ version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" dependencies = [ - "windows-implement", - "windows-interface", - "windows-link", - "windows-result", - "windows-strings", + "windows-implement 0.60.2", + "windows-interface 0.59.3", + "windows-link 0.2.1", + "windows-result 0.4.1", + "windows-strings 0.5.1", +] + +[[package]] +name = "windows-core" +version = "0.100.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "803590c6856f51d15fa2e9fabe4f4703122c8737f72ef2741b4ac09d4c2192f5" +dependencies = [ + "windows-implement 0.100.0", + "windows-interface 0.100.0", + "windows-link 0.100.0", + "windows-result 0.100.0", + "windows-strings 0.100.0", ] [[package]] @@ -8397,8 +8534,8 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1d6f90251fe18a279739e78025bd6ddc52a7e22f921070ccdc67dde84c605cb" dependencies = [ - "windows-core", - "windows-link", + "windows-core 0.62.2", + "windows-link 0.2.1", "windows-threading", ] @@ -8413,6 +8550,17 @@ dependencies = [ "syn 2.0.119", ] +[[package]] +name = "windows-implement" +version = "0.100.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc1bc82e5a1b1a4d7255861b07881a0407b552f50a4d8543c0c7276fa96f6e8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + [[package]] name = "windows-interface" version = "0.59.3" @@ -8424,20 +8572,37 @@ dependencies = [ "syn 2.0.119", ] +[[package]] +name = "windows-interface" +version = "0.100.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3f7005c3b757b9b82c2f40c0e71094ff1080adddaf3e8b6ce99b545d3c48796" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + [[package]] name = "windows-link" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" +[[package]] +name = "windows-link" +version = "0.100.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b39de7c7fe78858b0144c50c3fc000bab3be17d5e9b85b1053871693c7f7415" + [[package]] name = "windows-numerics" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e2e40844ac143cdb44aead537bbf727de9b044e107a0f1220392177d15b0f26" dependencies = [ - "windows-core", - "windows-link", + "windows-core 0.62.2", + "windows-link 0.2.1", ] [[package]] @@ -8446,7 +8611,16 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" dependencies = [ - "windows-link", + "windows-link 0.2.1", +] + +[[package]] +name = "windows-result" +version = "0.100.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44873a1ef61c85d5e2991db91fe656cfcf0731097e00dff1ac860f1cb3b752a0" +dependencies = [ + "windows-link 0.100.0", ] [[package]] @@ -8455,7 +8629,16 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" dependencies = [ - "windows-link", + "windows-link 0.2.1", +] + +[[package]] +name = "windows-strings" +version = "0.100.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a70b590c684f1d2854f74999896f7c0558f1bdde62f599088599e20ea1d2f60" +dependencies = [ + "windows-link 0.100.0", ] [[package]] @@ -8473,7 +8656,7 @@ version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" dependencies = [ - "windows-link", + "windows-link 0.2.1", ] [[package]] @@ -8498,7 +8681,7 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3949bd5b99cafdf1c7ca86b43ca564028dfe27d66958f2470940f73d86d75b37" dependencies = [ - "windows-link", + "windows-link 0.2.1", ] [[package]] @@ -8617,9 +8800,9 @@ dependencies = [ [[package]] name = "xdg" -version = "2.5.2" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "213b7324336b53d2414b2db8537e56544d981803139155afa84f76eeebb7a546" +checksum = "2fb433233f2df9344722454bc7e96465c9d03bff9d77c248f9e7523fe79585b5" [[package]] name = "yaml-rust" @@ -8655,7 +8838,7 @@ checksum = "ec8ebde2db3681e8c9980cc27822030e68752690ddfa9473e739aeb4dbde6d71" dependencies = [ "proc-macro2", "quote", - "syn 3.0.9", + "syn 3.0.10", "synstructure", ] @@ -8696,7 +8879,7 @@ checksum = "f75b4683f6c7f45248d4d64056a24298c6281e0993356d7d1b4a1a962ef10d4a" dependencies = [ "proc-macro2", "quote", - "syn 3.0.9", + "syn 3.0.10", "synstructure", ] @@ -8750,7 +8933,7 @@ checksum = "c3743ddbf47738d929cd1ae2e199d40d0162979dfe31aef8ae646d2bf00bf97a" dependencies = [ "proc-macro2", "quote", - "syn 3.0.9", + "syn 3.0.10", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 8ce2d2d..a49b450 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,9 +30,9 @@ chrono = { version = "0.4", features = ["serde"] } uuid = { version = "1", features = ["v4", "serde"] } tracing = "0.1" sqlx = { version = "0.9", default-features = false, features = ["runtime-tokio", "tls-rustls-ring-webpki", "postgres", "macros", "migrate", "chrono", "json", "uuid"] } -rand = "0.8" -sha2 = "0.10" +rand = "0.10" +sha2 = "0.11" hex = "0.4" -base64 = "0.22" +base64 = "0.23" moka = { version = "0.12", features = ["future"] } ipnet = { version = "2", features = ["serde"] } diff --git a/Dockerfile b/Dockerfile index 6f74361..a7c9c1f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,7 @@ # syntax=docker/dockerfile:1.7 # Forgust: one binary + the web UI. Runtime needs git >= 2.45 (trixie ships 2.47). -FROM node:22.11-bookworm-slim AS web +FROM node:26.12-bookworm-slim AS web WORKDIR /src/web COPY web/package.json web/package-lock.json ./ RUN npm ci --no-audit --no-fund diff --git a/README.md b/README.md index a048506..578779c 100644 --- a/README.md +++ b/README.md @@ -62,12 +62,13 @@ The app is available at **http://$FORGUST_HOST:8080**, and the emails it sends a ### Production -Build the image with `docker build -t forgust .`, then run it next to Postgres: +Run the published image (amd64 and arm64) next to Postgres, or build your own with +`docker build -t forgust .`: ```yaml services: forgust: - image: forgust + image: ghcr.io/forgust-dev/forgust:0.1 restart: unless-stopped ports: ["8080:8080", "2222:2222"] environment: diff --git a/compose.dev.yml b/compose.dev.yml index 97d94e8..8d918a2 100644 --- a/compose.dev.yml +++ b/compose.dev.yml @@ -38,7 +38,7 @@ services: - s3-data:/data mail: - image: axllent/mailpit:v1.33.0@sha256:9b3a463be15354c0f0eba91697d80e3e0d8a5623ef0e627cacc836bc17fd5231 + image: axllent/mailpit:v1.33.1@sha256:aef2aacc11f075ec0fb6874275ee4a421e688e11a96ebb296134d1735c7761ce restart: unless-stopped ports: - "1026:1025" diff --git a/compose.yml b/compose.yml index a18084b..e8b244d 100644 --- a/compose.yml +++ b/compose.yml @@ -71,7 +71,7 @@ services: - s3-data:/data mail: - image: axllent/mailpit:v1.33.0@sha256:9b3a463be15354c0f0eba91697d80e3e0d8a5623ef0e627cacc836bc17fd5231 + image: axllent/mailpit:v1.33.1@sha256:aef2aacc11f075ec0fb6874275ee4a421e688e11a96ebb296134d1735c7761ce restart: unless-stopped ports: - "8027:8025" @@ -90,7 +90,7 @@ services: # answers every webhook with 200 and logs it hooks: - image: python:3.13-alpine + image: python:3.15-alpine restart: unless-stopped command: - python3 diff --git a/crates/forgust-db/Cargo.toml b/crates/forgust-db/Cargo.toml index 0e6bbf1..aa17109 100644 --- a/crates/forgust-db/Cargo.toml +++ b/crates/forgust-db/Cargo.toml @@ -13,6 +13,6 @@ serde_json.workspace = true chrono.workspace = true thiserror.workspace = true tracing.workspace = true -utoipa = { version = "5", features = ["chrono"] } +utoipa = { version = "6", features = ["chrono"] } globset = "0.4" uuid.workspace = true diff --git a/crates/forgust-server/Cargo.toml b/crates/forgust-server/Cargo.toml index cd43c1a..927484d 100644 --- a/crates/forgust-server/Cargo.toml +++ b/crates/forgust-server/Cargo.toml @@ -38,29 +38,29 @@ hex.workspace = true base64.workspace = true moka.workspace = true axum = { version = "0.8", features = ["macros", "multipart"] } -axum-extra = { version = "0.10", features = ["cookie", "typed-header"] } +axum-extra = { version = "0.12", features = ["cookie", "typed-header"] } tower = "0.5" -tower-http = { version = "0.6", features = ["trace", "fs", "compression-gzip", "cors", "request-id", "set-header", "timeout"] } +tower-http = { version = "0.7", features = ["trace", "fs", "compression-gzip", "cors", "request-id", "set-header", "timeout"] } hyper = { version = "1", features = ["client", "http1"] } hyper-util = { version = "0.1", features = ["tokio"] } http-body-util = "0.1" clap = { version = "4", features = ["derive", "env"] } figment = { version = "0.10", features = ["toml", "env"] } tracing-subscriber = { version = "0.3", features = ["env-filter", "json"] } -opentelemetry = "0.30" -opentelemetry_sdk = { version = "0.30", features = ["rt-tokio"] } -opentelemetry-otlp = { version = "0.30", features = ["grpc-tonic", "trace"] } -tracing-opentelemetry = "0.31" +opentelemetry = "0.33" +opentelemetry_sdk = { version = "0.33", features = ["rt-tokio"] } +opentelemetry-otlp = { version = "0.33", features = ["grpc-tonic", "trace"] } +tracing-opentelemetry = "0.34" metrics = "0.24" -metrics-exporter-prometheus = { version = "0.17", default-features = false } -utoipa = { version = "5", features = ["chrono"] } +metrics-exporter-prometheus = { version = "0.18", default-features = false } +utoipa = { version = "6", features = ["chrono"] } time = "0.3" graphile_worker = "0.14" object_store = { version = "0.14", features = ["aws"] } -argon2 = "0.5" -totp-rs = { version = "5", features = ["otpauth", "gen_secret"] } +argon2 = "0.6" +totp-rs = { version = "6", features = ["otpauth", "gen_secret"] } openidconnect = { version = "4", default-features = false, features = ["reqwest", "rustls-tls"] } -aes-gcm = "0.10" +aes-gcm = "0.11" russh = "0.65" # OpenPGP signatures on commits; no bzip2: signatures are not compressed pgp = { version = "0.21", default-features = false } @@ -68,7 +68,7 @@ pgp = { version = "0.21", default-features = false } ring = "0.17" async-compression = { version = "0.4", features = ["tokio", "gzip", "deflate"] } syntect = { version = "5", default-features = false, features = ["parsing", "default-syntaxes", "default-themes", "html", "dump-load", "regex-fancy"] } -comrak = "0.39" +comrak = "0.59" ammonia = "4" mime_guess = "2" quick-xml = "0.42" @@ -79,10 +79,10 @@ regex = "1" image = { version = "0.25", default-features = false, features = ["png", "jpeg", "gif", "webp"] } percent-encoding = "2" url = "2" -reqwest = { version = "0.12", default-features = false, features = ["rustls-tls", "json", "stream"] } -hmac = "0.12" +reqwest = { version = "0.13", default-features = false, features = ["rustls", "json", "stream"] } +hmac = "0.13" lettre = { version = "0.11", default-features = false, features = ["builder", "smtp-transport", "tokio1", "tokio1-rustls", "ring", "webpki-roots"] } [dev-dependencies] tempfile = "3" -reqwest = { version = "0.12", default-features = false, features = ["rustls-tls", "json", "stream", "multipart"] } +reqwest = { version = "0.13", default-features = false, features = ["rustls", "json", "stream", "multipart", "query", "form"] } diff --git a/crates/forgust-server/src/api/registry.rs b/crates/forgust-server/src/api/registry.rs index 3d6417c..0e42259 100644 --- a/crates/forgust-server/src/api/registry.rs +++ b/crates/forgust-server/src/api/registry.rs @@ -109,8 +109,8 @@ pub async fn set_cleanup_policy( ) -> ApiResult> { let p = project_for(&state, &principal, &id, ProjectAction::Admin).await?; for (what, re) in [("tags to remove", &policy.name_regex), ("tags to keep", &policy.name_regex_keep)] { - if !re.is_empty() && regex::Regex::new(re).is_err() { - return Err(ApiError::bad(format!("the pattern of {what} is not a valid regular expression"))); + if !re.is_empty() { + crate::registry::tag_pattern(re).map_err(|e| ApiError::bad(format!("the pattern of {what} is not valid: {e}")))?; } } if policy.keep_n.is_some_and(|n| n < 0) || policy.older_than_days.is_some_and(|d| d < 0) { diff --git a/crates/forgust-server/src/api/user.rs b/crates/forgust-server/src/api/user.rs index 00d3c7f..b3f4b48 100644 --- a/crates/forgust-server/src/api/user.rs +++ b/crates/forgust-server/src/api/user.rs @@ -274,7 +274,7 @@ pub async fn totp_setup(State(state): State, SignedIn(u, p): SignedIn) let secret = session::new_totp_secret(); let sealed = state.secrets.encrypt(secret.as_bytes())?; forgust_db::users::set_totp(&state.db, u.id, Some(&sealed), false).await?; - let url = session::totp_for(&secret, &u.username)?.get_url(); + let url = session::totp_for(&secret, &u.username)?.to_url().map_err(|e| ApiError::Internal(anyhow::anyhow!("{e}")))?; Ok(Json(TotpSetup { secret, otpauth_url: url })) } diff --git a/crates/forgust-server/src/auth/session.rs b/crates/forgust-server/src/auth/session.rs index f54ce63..35cb0c5 100644 --- a/crates/forgust-server/src/auth/session.rs +++ b/crates/forgust-server/src/auth/session.rs @@ -3,7 +3,7 @@ use axum_extra::extract::cookie::{Cookie, SameSite}; use chrono::{Duration, Utc}; use forgust_db::users::User; -use totp_rs::{Algorithm, Secret, TOTP}; +use totp_rs::{Algorithm, Builder, Secret, Totp}; use super::session_cookie_name; use crate::crypto; @@ -84,14 +84,23 @@ pub async fn destroy(state: &AppState, token: &str) -> ApiResult<()> { Ok(()) } -pub fn totp_for(secret_b32: &str, account: &str) -> ApiResult { - let bytes = Secret::Encoded(secret_b32.to_string()).to_bytes().map_err(|_| ApiError::bad("bad TOTP secret"))?; - TOTP::new(Algorithm::SHA1, 6, 1, 30, bytes, Some("Forgust".into()), account.to_string()) +/// SHA-1, 6 digits, 30 s steps, one step of clock skew either way. +pub fn totp_for(secret_b32: &str, account: &str) -> ApiResult { + let secret = Secret::try_from_base32(secret_b32).map_err(|_| ApiError::bad("bad TOTP secret"))?; + Builder::new() + .with_algorithm(Algorithm::SHA1) + .with_digits(6) + .with_skew(1) + .with_step_duration(30) + .with_secret(secret) + .with_issuer(Some("Forgust")) + .with_account_name(account) + .build() .map_err(|e| ApiError::Internal(anyhow::anyhow!("{e}"))) } pub fn new_totp_secret() -> String { - Secret::generate_secret().to_encoded().to_string() + Secret::generate().to_base32() } /// Check a code against the user's stored (encrypted) TOTP seed. @@ -101,13 +110,34 @@ pub async fn verify_totp(state: &AppState, user: &User, code: &str) -> ApiResult let totp = totp_for(&secret, &user.username)?; let code = code.trim(); let now = std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).map_err(|e| ApiError::Internal(e.into()))?.as_secs(); - // the step before, this one and the next (clock skew), each once - let Some(step) = [now.saturating_sub(totp.step), now, now + totp.step] - .into_iter() - .find(|t| crate::crypto::eq_ct(&totp.generate(*t), code)) - .map(|t| (t / totp.step) as i64) - else { - return Ok(false); - }; - Ok(forgust_db::users::use_totp_step(&state.db, user.id, step).await?) + // the step before, this one and the next (clock skew), each accepted once + let Some(step) = totp.check(code, now) else { return Ok(false) }; + Ok(forgust_db::users::use_totp_step(&state.db, user.id, step as i64).await?) +} + +#[cfg(test)] +mod totp_tests { + use super::*; + + // RFC 6238 test vector: secret "12345678901234567890", SHA-1, T = 59 s + const RFC_SECRET: &str = "GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ"; + + #[test] + fn codes_match_the_rfc_and_the_window_is_one_step() { + let t = totp_for(RFC_SECRET, "x").unwrap(); + assert_eq!(t.generate(59).to_string(), "287082"); + // accepted from the step before to the step after, reporting the code's step + assert_eq!(t.check("287082", 59), Some(1)); + assert_eq!(t.check("287082", 89), Some(1)); + assert_eq!(t.check("287082", 29), Some(1)); + assert_eq!(t.check("287082", 120), None); + assert_eq!(t.check("nope", 59), None); + } + + #[test] + fn new_secrets_are_160_bits_of_base32() { + let s = new_totp_secret(); + assert_eq!(s.len(), 32); + assert!(totp_for(&s, "x").is_ok()); + } } diff --git a/crates/forgust-server/src/crypto.rs b/crates/forgust-server/src/crypto.rs index 168a59a..328c4dc 100644 --- a/crates/forgust-server/src/crypto.rs +++ b/crates/forgust-server/src/crypto.rs @@ -1,12 +1,13 @@ //! Tokens, password hashing and encryption at rest. -use aes_gcm::aead::{Aead, KeyInit}; -use aes_gcm::{Aes256Gcm, Nonce}; +use aes_gcm::Aes256Gcm; +use aes_gcm::aead::{Aead, Generate, KeyInit, Nonce}; use argon2::Argon2; -use argon2::password_hash::{PasswordHash, PasswordHasher, PasswordVerifier, SaltString}; +use argon2::password_hash::phc::PasswordHash; +use argon2::password_hash::{PasswordHasher, PasswordVerifier}; use base64::Engine; use base64::engine::general_purpose::{STANDARD, URL_SAFE_NO_PAD}; -use rand::{Rng, RngCore}; +use rand::{Rng, RngExt}; use sha2::{Digest, Sha256}; /// Token prefixes by type (ADR-0015), so leaked tokens are easy to scan for. @@ -21,14 +22,14 @@ pub mod prefix { const ALPHABET: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; pub fn random_token(prefix: &str) -> String { - let mut rng = rand::thread_rng(); - let body: String = (0..32).map(|_| ALPHABET[rng.gen_range(0..ALPHABET.len())] as char).collect(); + let mut rng = rand::rng(); + let body: String = (0..32).map(|_| ALPHABET[rng.random_range(0..ALPHABET.len())] as char).collect(); format!("{prefix}{body}") } pub fn random_urlsafe(bytes: usize) -> String { let mut buf = vec![0u8; bytes]; - rand::thread_rng().fill_bytes(&mut buf); + rand::rng().fill_bytes(&mut buf); URL_SAFE_NO_PAD.encode(buf) } @@ -52,8 +53,8 @@ pub async fn hash_password_gated(password: &str) -> anyhow::Result { } pub fn hash_password(password: &str) -> anyhow::Result { - let salt = SaltString::generate(&mut argon2::password_hash::rand_core::OsRng); - Ok(Argon2::default().hash_password(password.as_bytes(), &salt).map_err(|e| anyhow::anyhow!("{e}"))?.to_string()) + // a fresh random salt from the OS for every hash + Ok(Argon2::default().hash_password(password.as_bytes()).map_err(|e| anyhow::anyhow!("{e}"))?.to_string()) } pub fn verify_password(password: &str, hash: &str) -> bool { @@ -108,8 +109,8 @@ impl SecretBox { /// A signature of `msg` for a link (HMAC-SHA256, URL-safe). pub fn sign(&self, msg: &str) -> String { - use hmac::{Hmac, Mac}; - let mut m = as Mac>::new_from_slice(&self.mac_key).expect("any key length"); + use hmac::{Hmac, KeyInit, Mac}; + let mut m = as KeyInit>::new_from_slice(&self.mac_key).expect("any key length"); m.update(msg.as_bytes()); URL_SAFE_NO_PAD.encode(m.finalize().into_bytes()) } @@ -120,15 +121,15 @@ impl SecretBox { pub fn generate_key() -> String { let mut k = [0u8; 32]; - rand::thread_rng().fill_bytes(&mut k); + rand::rng().fill_bytes(&mut k); STANDARD.encode(k) } /// AES-256-GCM; output is base64(nonce || ciphertext). pub fn encrypt(&self, plaintext: &[u8]) -> anyhow::Result { - let mut nonce = [0u8; 12]; - rand::thread_rng().fill_bytes(&mut nonce); - let ct = self.cipher.encrypt(Nonce::from_slice(&nonce), plaintext).map_err(|e| anyhow::anyhow!("{e}"))?; + // a fresh random nonce for every message, from the OS + let nonce = Nonce::::generate(); + let ct = self.cipher.encrypt(&nonce, plaintext).map_err(|e| anyhow::anyhow!("{e}"))?; let mut out = nonce.to_vec(); out.extend(ct); Ok(STANDARD.encode(out)) @@ -138,7 +139,8 @@ impl SecretBox { let raw = STANDARD.decode(sealed)?; anyhow::ensure!(raw.len() > 12, "sealed value too short"); let (nonce, ct) = raw.split_at(12); - self.cipher.decrypt(Nonce::from_slice(nonce), ct).map_err(|e| anyhow::anyhow!("{e}")) + let nonce = Nonce::::try_from(nonce).map_err(|e| anyhow::anyhow!("{e}"))?; + self.cipher.decrypt(&nonce, ct).map_err(|e| anyhow::anyhow!("{e}")) } pub fn decrypt_str(&self, sealed: &str) -> anyhow::Result { @@ -188,6 +190,28 @@ mod tests { let b = SecretBox::from_base64(&SecretBox::generate_key()).unwrap(); let sealed = b.encrypt(b"JBSWY3DPEHPK3PXP").unwrap(); assert_eq!(b.decrypt(&sealed).unwrap(), b"JBSWY3DPEHPK3PXP"); + // a new nonce each time: the same secret never seals the same way twice + assert_ne!(b.encrypt(b"JBSWY3DPEHPK3PXP").unwrap(), sealed); assert!(SecretBox::from_base64(&SecretBox::generate_key()).unwrap().decrypt(&sealed).is_err()); } + + // Values produced by the previous versions of argon2, aes-gcm and hmac: + // what is already stored, or already sent out, must still work. + const OLD_KEY: &str = "BwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwc="; + + #[test] + fn verifies_existing_password_hashes() { + let h = "$argon2id$v=19$m=19456,t=2,p=1$qfkAMuMQOdo1ELfRKTteQg$FOMCy1G7PZEfRiKce1KkLnAk7NtL/6m0Gvkizr6FAHA"; + assert!(verify_password("correct horse", h)); + assert!(!verify_password("wrong", h)); + // new hashes keep the same algorithm and cost + assert!(hash_password("x").unwrap().starts_with("$argon2id$v=19$m=19456,t=2,p=1$")); + } + + #[test] + fn opens_existing_secrets_and_signs_links_the_same_way() { + let b = SecretBox::from_base64(OLD_KEY).unwrap(); + assert_eq!(b.decrypt_str("L0dibbhn63DwoVD+J0pZ/txPw6UrqAqGn9C6Q25/bcoMsxGdGRtgKVg=").unwrap(), "stored secret"); + assert_eq!(b.sign("unsubscribe:42"), "zQ99AL3EG0XzmB8kDKyOdhu-_sfjOzKp-ygLHkELI2I"); + } } diff --git a/crates/forgust-server/src/registry.rs b/crates/forgust-server/src/registry.rs index 55fb32b..2f775a1 100644 --- a/crates/forgust-server/src/registry.rs +++ b/crates/forgust-server/src/registry.rs @@ -945,16 +945,27 @@ pub async fn sweep(state: &AppState) -> anyhow::Result<()> { Ok(()) } +/// A cleanup policy's tag pattern, matched against whole tag names. Maintainers +/// write these: GitLab's 255-character cap, and the same compiled-size limit +/// as push rules (the `regex` crate matches in linear time). +pub const MAX_TAG_PATTERN: usize = 255; +pub fn tag_pattern(r: &str) -> Result { + if r.chars().count() > MAX_TAG_PATTERN { + return Err(format!("longer than {MAX_TAG_PATTERN} characters")); + } + regex::RegexBuilder::new(&format!("^(?:{r})$")).size_limit(1 << 20).build().map_err(|e| e.to_string()) +} + /// Apply a project's cleanup policy, GitLab's way: per repository, take the /// tags `name_regex` matches, minus `latest` and those `name_regex_keep` /// matches; keep the newest `keep_n` of them; remove the rest that are older /// than `older_than_days`. pub async fn cleanup(state: &AppState, project_id: i64) -> anyhow::Result { let policy = rdb::cleanup_policy(&state.db, project_id).await?; - let anchored = |r: &str| regex::Regex::new(&format!("^(?:{r})$")).ok(); - let (Some(remove), keep) = - (anchored(&policy.name_regex), (!policy.name_regex_keep.is_empty()).then(|| anchored(&policy.name_regex_keep)).flatten()) - else { + let (Ok(remove), keep) = ( + tag_pattern(&policy.name_regex), + (!policy.name_regex_keep.is_empty()).then(|| tag_pattern(&policy.name_regex_keep).ok()).flatten(), + ) else { return Ok(0); }; let cutoff = policy.older_than_days.map(|d| chrono::Utc::now() - chrono::Duration::days(d as i64)); diff --git a/crates/forgust-server/src/render.rs b/crates/forgust-server/src/render.rs index c11b238..4d875b5 100644 --- a/crates/forgust-server/src/render.rs +++ b/crates/forgust-server/src/render.rs @@ -262,13 +262,13 @@ pub fn markdown_with(source: &str, project_url: &str, git_ref: &str, dir: &str, opts.extension.autolink = true; opts.extension.tasklist = true; opts.extension.footnotes = true; - opts.extension.header_ids = Some("user-content-".into()); + opts.extension.header_id_prefix = Some("user-content-".into()); // `> [!NOTE]` and friends (GitHub's and GitLab's alerts) opts.extension.alerts = true; // `$x^2$`, `$$...$$`, `` $`x`$ `` and ```math: marked here, typeset in the browser opts.extension.math_dollars = true; opts.extension.math_code = true; - opts.render.unsafe_ = false; + opts.render.r#unsafe = false; let html = comrak::markdown_to_html(source, &opts); let rewrite = LinkRewriter { diff --git a/crates/forgust-server/src/services/webhooks.rs b/crates/forgust-server/src/services/webhooks.rs index 5f36a49..fa44202 100644 --- a/crates/forgust-server/src/services/webhooks.rs +++ b/crates/forgust-server/src/services/webhooks.rs @@ -204,7 +204,7 @@ pub async fn fetch_image(state: &AppState, raw: &str, max_bytes: usize) -> Resul } pub fn sign(secret: &str, body: &[u8]) -> String { - let mut mac = Hmac::::new_from_slice(secret.as_bytes()).expect("any key length works"); + let mut mac = as hmac::KeyInit>::new_from_slice(secret.as_bytes()).expect("any key length works"); mac.update(body); format!("sha256={}", hex::encode(mac.finalize().into_bytes())) } @@ -288,6 +288,12 @@ pub async fn deliver(state: &AppState, delivery_id: i64) -> anyhow::Result<()> { mod tests { use super::*; + #[test] + fn signature_unchanged() { + // receivers check this header: the value from the previous hmac version + assert_eq!(sign("whsec", b"{\"a\":1}"), "sha256=19373ef0e8c66f206e49d251e4402291615bbce6ef00922e94a47a213fb76ee1"); + } + #[test] fn internal_addresses_are_refused() { for ip in [ diff --git a/crates/forgust-server/src/ssh.rs b/crates/forgust-server/src/ssh.rs index 3ab2ed1..a769bb6 100644 --- a/crates/forgust-server/src/ssh.rs +++ b/crates/forgust-server/src/ssh.rs @@ -29,7 +29,7 @@ pub fn load_or_create_host_key(path: &Path) -> anyhow::Result { return Ok(PrivateKey::read_openssh_file(path)?); } let mut seed = [0u8; 32]; - rand::RngCore::fill_bytes(&mut rand::rngs::OsRng, &mut seed); + rand::TryRng::try_fill_bytes(&mut rand::rngs::SysRng, &mut seed)?; let key = PrivateKey::from(russh::keys::ssh_key::private::Ed25519Keypair::from_seed(&seed)); if let Some(dir) = path.parent() { std::fs::create_dir_all(dir)?; diff --git a/crates/forgust-server/tests/m16_security.rs b/crates/forgust-server/tests/m16_security.rs index e9bdc60..a598f5f 100644 --- a/crates/forgust-server/tests/m16_security.rs +++ b/crates/forgust-server/tests/m16_security.rs @@ -418,7 +418,10 @@ async fn real_scanners_find_a_sql_injection_a_secret_and_a_vulnerable_dependency "import sqlite3\n\n\ndef find(name):\n db = sqlite3.connect('app.db')\n cur = db.cursor()\n cur.execute(\"SELECT * FROM users WHERE name = '%s'\" % name)\n return cur.fetchall()\n", ) .unwrap(); - std::fs::write(work.join("settings.py"), "GITLAB_TOKEN = \"glpat-x7Qk2mVb9LpR4tYw8NzA\"\n").unwrap(); + // a fake token for the secrets scanner to find, in two pieces here so that + // scanners reading this repository do not report it + let fake_token = ["glpat-", "x7Qk2mVb9LpR4tYw8NzA"].concat(); + std::fs::write(work.join("settings.py"), format!("GITLAB_TOKEN = \"{fake_token}\"\n")).unwrap(); std::fs::write(work.join("package.json"), r#"{ "name": "app", "version": "1.0.0", "dependencies": { "lodash": "4.17.15" } }"#).unwrap(); std::fs::write( work.join("package-lock.json"), @@ -519,7 +522,7 @@ async fn real_scanners_find_a_sql_injection_a_secret_and_a_vulnerable_dependency ); assert!(has("secret_detection", &|x| x["file"] == "settings.py"), "the token: {found}"); assert!(has("dependency_scanning", &|x| x["package_name"] == "lodash" && x["fixed_version"].is_string()), "lodash: {found}"); - assert!(!found.to_string().contains("glpat-x7Qk2mVb9LpR4tYw8NzA"), "the secret itself is not stored"); + assert!(!found.to_string().contains(&fake_token), "the secret itself is not stored"); } struct Container(String); diff --git a/crates/forgust-server/tests/m1_repos.rs b/crates/forgust-server/tests/m1_repos.rs index 94be20e..bb8884b 100644 --- a/crates/forgust-server/tests/m1_repos.rs +++ b/crates/forgust-server/tests/m1_repos.rs @@ -241,9 +241,9 @@ fn totp_code(secret: &str) -> String { /// The code `ahead` seconds from now (the server accepts the next step too). fn totp_code_at(secret: &str, ahead: u64) -> String { - let bytes = totp_rs::Secret::Encoded(secret.to_string()).to_bytes().unwrap(); + let secret = totp_rs::Secret::try_from_base32(secret).unwrap(); let now = std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_secs(); - totp_rs::TOTP::new(totp_rs::Algorithm::SHA1, 6, 1, 30, bytes, Some("Forgust".into()), "x".into()).unwrap().generate(now + ahead) + totp_rs::Builder::new().with_secret(secret).build().unwrap().generate(now + ahead).to_string() } #[sqlx::test(migrator = "forgust_db::MIGRATOR")] @@ -374,7 +374,7 @@ async fn setup_and_admin(pool: sqlx::PgPool) { fn test_key() -> russh::keys::PrivateKey { let mut seed = [0u8; 32]; - rand::RngCore::fill_bytes(&mut rand::rngs::OsRng, &mut seed); + rand::TryRng::try_fill_bytes(&mut rand::rngs::SysRng, &mut seed).unwrap(); russh::keys::PrivateKey::from(russh::keys::ssh_key::private::Ed25519Keypair::from_seed(&seed)) } diff --git a/crates/forgust-server/tests/m9_registry.rs b/crates/forgust-server/tests/m9_registry.rs index 7a696cb..38facbf 100644 --- a/crates/forgust-server/tests/m9_registry.rs +++ b/crates/forgust-server/tests/m9_registry.rs @@ -361,6 +361,11 @@ async fn cleanup_policies_and_garbage_collection(pool: sqlx::PgPool) { .0, 400 ); + // patterns are capped at 255 characters, as on GitLab + let (s, body) = owner + .put(&policy, json!({ "enabled": true, "keep_n": 1, "older_than_days": 30, "name_regex": "a".repeat(256), "name_regex_keep": "" })) + .await; + assert_eq!(s, 400, "{body}"); let (s, body) = owner .put(&policy, json!({ "enabled": true, "keep_n": 1, "older_than_days": 30, "name_regex": "v.*", "name_regex_keep": "stable" })) .await; diff --git a/crates/forgust-storage/Cargo.toml b/crates/forgust-storage/Cargo.toml index ecc018d..c7e6610 100644 --- a/crates/forgust-storage/Cargo.toml +++ b/crates/forgust-storage/Cargo.toml @@ -15,9 +15,9 @@ tokio.workspace = true tokio-util.workspace = true serde.workspace = true tracing.workspace = true -utoipa = { version = "5", features = ["chrono"] } +utoipa = { version = "6", features = ["chrono"] } gix = { version = "0.90", default-features = false, features = ["max-performance", "sha1", "revision"] } -lru = "0.18" +lru = "0.19" sha2.workspace = true hex.workspace = true diff --git a/deny.toml b/deny.toml index 7874871..95370b5 100644 --- a/deny.toml +++ b/deny.toml @@ -42,6 +42,11 @@ allow = [ "MPL-2.0", ] +# MIT plus "modified versions must not claim to be the original": via comrak +[[licenses.exceptions]] +crate = "fmt2io" +allow = ["MITNFA"] + [[licenses.clarify]] crate = "ring" expression = "MIT AND ISC AND OpenSSL" diff --git a/deploy/screenshots.mjs b/deploy/screenshots.mjs new file mode 100644 index 0000000..1ad7132 --- /dev/null +++ b/deploy/screenshots.mjs @@ -0,0 +1,98 @@ +// The README's screenshots, light and dark, from the seeded demo instance: +// FORGUST_HOST=192.0.2.10 docker compose up -d --build +// FORGUST_HOST=192.0.2.10 python3 deploy/seed.py +// FORGUST_HOST=192.0.2.10 node deploy/screenshots.mjs [name] +// Writes .github/images/-light.png and -dark.png (all of them, or +// only the one named). Uses the web UI's Playwright: run `npm ci` in web/ first. +import { createRequire } from "node:module"; +import { dirname, join } from "node:path"; +import { fileURLToPath } from "node:url"; + +const root = join(dirname(fileURLToPath(import.meta.url)), ".."); +const { chromium } = createRequire(join(root, "web/package.json"))("@playwright/test"); + +const host = process.env.FORGUST_HOST; +if (!host) throw new Error("set FORGUST_HOST to the address compose.yml was started with"); +const base = `http://${host}:8080`; +const password = process.env.SEED_PASSWORD ?? "forgust-demo-pass"; +const out = join(root, ".github/images"); +const only = process.argv[2]; +const P = "acme/shop"; + +const browser = await chromium.launch(); +const contexts = {}; +/** One signed-in context per user; each page picks its colour scheme. */ +async function as(user) { + if (!contexts[user]) { + const ctx = await browser.newContext({ viewport: { width: 1440, height: 900 }, deviceScaleFactor: 1.5 }); + const r = await ctx.request.post(`${base}/api/v1/auth/login`, { data: { login: user, password } }); + if (!r.ok()) throw new Error(`sign-in as ${user}: ${r.status()} (is the instance seeded?)`); + contexts[user] = ctx; + } + return contexts[user]; +} +async function api(path) { + const r = await (await as("alice")).request.get(`${base}/api/v1${path}`); + if (!r.ok()) throw new Error(`GET ${path}: ${r.status()}`); + return r.json(); +} +function need(value, what) { + if (!value) throw new Error(`no ${what} in the demo: run deploy/seed.py first`); + return value; +} + +// the subjects, from what the seed made: looked up only for the shots that need them +const wanted = (...names) => !only || names.includes(only); +const project = await api(`/resolve?path=${encodeURIComponent(P)}`); +let mr, pipeline, job; +if (wanted("merge-request", "diff")) { + const mrs = await api(`/projects/${project.id}/merge_requests?state=opened`); + mr = need(mrs.find((m) => /discount/i.test(m.title)) ?? mrs[0], "open merge request"); +} +if (wanted("pipeline", "job")) { + // the main pipeline with the most jobs, once it has finished + const mains = (await api(`/projects/${project.id}/pipelines`)).filter((p) => p.ref === "main"); + const details = await Promise.all(mains.map((p) => api(`/projects/${project.id}/pipelines/${p.iid}`))); + pipeline = need(details.sort((a, b) => b.jobs.length - a.jobs.length)[0], "pipeline on main"); + for (let i = 0; ["running", "pending", "created"].includes(pipeline.status); i++) { + if (i === 60) throw new Error(`pipeline #${pipeline.iid} still ${pipeline.status} after 10 minutes`); + if (i === 0) console.log(`waiting for pipeline #${pipeline.iid} (${pipeline.status})…`); + await new Promise((r) => setTimeout(r, 10_000)); + pipeline = await api(`/projects/${project.id}/pipelines/${pipeline.iid}`); + } + job = need(pipeline.jobs.find((j) => /^unit/.test(j.name)) ?? pipeline.jobs[0], "job"); +} + +const SHOTS = [ + // name, user, path (a function when it needs a subject above) + ["code", "alice", P], + ["file", "alice", `${P}/-/blob/main/shop/cart.py`], + ["merge-request", "alice", () => `${P}/-/merge_requests/${mr.iid}`], + ["diff", "alice", () => `${P}/-/merge_requests/${mr.iid}/diffs`], + ["pipeline", "alice", () => `${P}/-/pipelines/${pipeline.iid}`], + ["job", "alice", () => `${P}/-/jobs/${job.id}`], + ["issues", "alice", `${P}/-/issues`], + ["security", "alice", `${P}/-/security`], + ["admin", "root", "admin"], + ["admin-storage", "root", "admin/storage"], + ["admin-health", "root", "admin/health"], +]; + +for (const [name, user, at] of SHOTS) { + if (only && only !== name) continue; + const path = typeof at === "function" ? at() : at; + const ctx = await as(user); + await Promise.all( + ["light", "dark"].map(async (scheme) => { + const page = await ctx.newPage(); + await page.emulateMedia({ colorScheme: scheme }); + await page.goto(`${base}/${path}`); + await page.waitForLoadState("networkidle"); + await page.evaluate(() => document.fonts.ready); + await page.screenshot({ path: join(out, `${name}-${scheme}.png`), animations: "disabled" }); + await page.close(); + console.log(`wrote .github/images/${name}-${scheme}.png from /${path}`); + }), + ); +} +await browser.close(); diff --git a/deploy/seed.py b/deploy/seed.py index feacfa9..49304d1 100644 --- a/deploy/seed.py +++ b/deploy/seed.py @@ -222,7 +222,7 @@ def png(w, h, seed): stages: [build, test, package, deploy] default: - image: python:3.13-alpine + image: python:3.15-alpine interruptible: true variables: @@ -291,7 +291,7 @@ def png(w, h, seed): script: - crane auth login "$CI_REGISTRY" -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" - mkdir -p layer/app && tar xzf dist/*.tar.gz -C layer/app && tar cf layer.tar -C layer app - - crane append --insecure --platform linux/amd64 -b python:3.13-alpine -f layer.tar -t "$CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA" + - crane append --insecure --platform linux/amd64 -b python:3.15-alpine -f layer.tar -t "$CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA" - crane tag --insecure "$CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA" "${CI_COMMIT_TAG:-latest}" rules: - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_TAG diff --git a/web/e2e/everyday.spec.ts b/web/e2e/everyday.spec.ts index 332ffa4..3759d12 100644 --- a/web/e2e/everyday.spec.ts +++ b/web/e2e/everyday.spec.ts @@ -1,4 +1,4 @@ -import { test, expect, P, csrfHeaders, isMobile } from "./fixtures"; +import { test, expect, P, ADMIN, apiCall, csrfHeaders, freshProject, isMobile } from "./fixtures"; const MR = `${P}/-/merge_requests`; @@ -84,6 +84,35 @@ test("your work lists your merge requests; projects moved to their own page", as await expect(page.getByRole("heading", { name: "Your projects" })).toBeVisible(); }); +test("your work keeps review requests you already reviewed apart from those waiting", async ({ page }) => { + const call = await apiCall(page); + const project = await call("get", `/resolve?path=${P.slice(1)}`); + const me = await call("get", `/users/${ADMIN}`); + const mr2 = `/projects/${project.id}/merge_requests/2`; + const section = (name: string) => page.locator("section", { has: page.getByRole("heading", { name }) }); + const reviewRequests = async () => { + await page.goto("/"); + await page.getByRole("navigation", { name: "Your work" }).getByRole("button", { name: /Review requests/ }).click(); + }; + // !2 is shared: whatever happens, leave no reviewer and no open thread behind + let note: { id: number } | null = null; + try { + // asked afresh: the request waits for the admin + await call("put", mr2, { reviewer_ids: [] }); + await call("put", mr2, { reviewer_ids: [me.id] }); + await reviewRequests(); + await expect(section("Waiting for your review").getByRole("link", { name: "Checkout page" })).toBeVisible(); + // a comment marks it reviewed: it moves to its own section, out of the count + note = await call("post", `${mr2}/notes`, { body: "Looked at it." }); + await reviewRequests(); + await expect(section("Reviewed by you").getByRole("link", { name: "Checkout page" })).toBeVisible(); + await expect(section("Waiting for your review").getByRole("link", { name: "Checkout page" })).toHaveCount(0); + } finally { + if (note) await call("delete", `${mr2}/notes/${note.id}`); + await call("put", mr2, { reviewer_ids: [] }); + } +}); + test("references in a comment preview link to what they name", async ({ page }) => { await page.goto(`${MR}/2`); const box = page.getByRole("textbox", { name: /comment/i }).last(); @@ -95,15 +124,22 @@ test("references in a comment preview link to what they name", async ({ page }) }); test("a user's page shows the contribution calendar and recent activity", async ({ page }) => { - await page.goto("/root"); - const cal = page.getByRole("grid", { name: "Contributions per day" }); - await expect(cal).toBeVisible(); - await expect(page.locator(".contrib-caption")).toContainText(/[1-9]\d* contributions? in the last year/); - await expect(cal.locator(".contrib-cell.l0, .contrib-cell.l1, .contrib-cell.l2, .contrib-cell.l3, .contrib-cell.l4").first()).toBeVisible(); - await expect(page.locator(".contrib-cell:not(.l0):not(.future)").first()).toBeAttached(); - const activity = page.locator(".activity-list"); - await expect(activity).toContainText("opened"); - await expect(activity.getByRole("link", { name: /Checkout with discounts/ }).first()).toBeVisible(); + // an event of its own, newest in the list whatever ran before + const { project, api, remove } = await freshProject(page, "activity", { "README.md": "# Activity\n" }); + const title = `Activity check ${Date.now() % 1_000_000}`; + await api("post", `/projects/${project.id}/issues`, { title }); + try { + await page.goto(`/${ADMIN}`); + const cal = page.getByRole("grid", { name: "Contributions per day" }); + await expect(cal).toBeVisible(); + await expect(page.locator(".contrib-caption")).toContainText(/[1-9]\d* contributions? in the last year/); + await expect(cal.locator(".contrib-cell.l0, .contrib-cell.l1, .contrib-cell.l2, .contrib-cell.l3, .contrib-cell.l4").first()).toBeVisible(); + await expect(page.locator(".contrib-cell:not(.l0):not(.future)").first()).toBeAttached(); + const row = page.locator(".activity-list li", { has: page.getByRole("link", { name: title }) }); + await expect(row).toContainText("opened"); + } finally { + await remove(); + } }); test("set auto-merge while the pipeline runs, then cancel it", async ({ page }) => { diff --git a/web/e2e/fixtures.ts b/web/e2e/fixtures.ts index 0fe3989..163add0 100644 --- a/web/e2e/fixtures.ts +++ b/web/e2e/fixtures.ts @@ -5,7 +5,7 @@ import { tmpdir } from "node:os"; import { join } from "node:path"; import { ADMIN, SEED } from "./global-setup"; -export { expect, SEED }; +export { expect, SEED, ADMIN }; /** Every test fails on an uncaught page error or a console error. */ export const test = base.extend<{ errors: string[] }>({ @@ -43,15 +43,22 @@ export async function csrfHeaders(page: Page): Promise> { return { "x-csrf-token": session.csrf_token }; } -/** A project of its own (settings other specs must not see), with a first - * commit on `main` pushed over git; `files` are its content. Delete it after. */ -export async function freshProject(page: Page, prefix: string, files: Record) { +/** Calls `/api/v1` as the signed-in user and fails the test on an error answer: + * `const call = await apiCall(page); await call("post", "/projects", {...})`. */ +export async function apiCall(page: Page) { const csrf = await csrfHeaders(page); - const call = async (method: "get" | "post" | "put" | "delete", url: string, data?: unknown) => { + return async (method: "get" | "post" | "put" | "delete", url: string, data?: unknown) => { const r = await page.request[method](`/api/v1${url}`, { headers: csrf, data }); expect(r.ok(), `${method} ${url}: ${await r.text()}`).toBeTruthy(); return r.status() === 204 ? null : r.json(); }; +} + +/** A project of its own (settings other specs must not see), with a first + * commit on `main` pushed over git; `files` are its content. Delete it after. */ +export async function freshProject(page: Page, prefix: string, files: Record) { + const csrf = await csrfHeaders(page); + const call = await apiCall(page); const group = await call("get", `/resolve?path=${SEED.group}`); const n = Date.now() % 1_000_000; const path = `${prefix}-${n}`; diff --git a/web/openapi.json b/web/openapi.json index 82ca5b0..e990c43 100644 --- a/web/openapi.json +++ b/web/openapi.json @@ -19,7 +19,6 @@ "operationId": "admin_get", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -47,7 +46,6 @@ }, "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -68,7 +66,6 @@ "operationId": "admin_host_rules", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -99,7 +96,6 @@ }, "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -121,9 +117,7 @@ ], "operationId": "admin_delete_host_rule", "responses": { - "204": { - "description": "" - } + "204": {} } } }, @@ -135,7 +129,6 @@ "operationId": "instance_runners", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -166,7 +159,6 @@ }, "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -186,7 +178,6 @@ "operationId": "admin_scanning", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -214,7 +205,6 @@ }, "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -244,9 +234,7 @@ "required": true }, "responses": { - "200": { - "description": "" - } + "200": {} } } }, @@ -268,7 +256,6 @@ }, "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -298,7 +285,6 @@ }, "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -328,9 +314,7 @@ "required": true }, "responses": { - "200": { - "description": "" - } + "200": {} } } }, @@ -352,9 +336,7 @@ "required": true }, "responses": { - "200": { - "description": "" - } + "200": {} } } }, @@ -366,7 +348,6 @@ "operationId": "list_top", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -397,7 +378,6 @@ }, "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -417,7 +397,6 @@ "operationId": "show", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -437,7 +416,6 @@ "operationId": "members", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -460,7 +438,6 @@ "operationId": "projects", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -483,7 +460,6 @@ "operationId": "group_get", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -512,7 +488,6 @@ }, "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -532,7 +507,6 @@ "operationId": "group_runners", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -563,7 +537,6 @@ }, "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -583,7 +556,6 @@ "operationId": "group_scanning", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -611,7 +583,6 @@ }, "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -632,7 +603,6 @@ "operationId": "storage", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -652,7 +622,6 @@ "operationId": "subgroups", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -675,7 +644,6 @@ "operationId": "group_variables", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -706,7 +674,6 @@ }, "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -728,9 +695,7 @@ ], "operationId": "delete_group_variable", "responses": { - "200": { - "description": "" - } + "200": {} } } }, @@ -742,7 +707,6 @@ "operationId": "list", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -774,7 +738,6 @@ }, "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -805,7 +768,6 @@ }, "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -836,7 +798,6 @@ }, "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -856,7 +817,6 @@ "operationId": "show", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -877,7 +837,6 @@ "operationId": "cancel", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -908,7 +867,6 @@ }, "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -939,7 +897,6 @@ }, "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -1010,7 +967,6 @@ ], "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -1039,7 +995,6 @@ }, "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -1059,7 +1014,6 @@ "operationId": "explore", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -1090,7 +1044,6 @@ }, "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -1110,7 +1063,6 @@ "operationId": "show", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -1130,7 +1082,6 @@ "operationId": "ci_settings", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -1158,7 +1109,6 @@ }, "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -1179,7 +1129,6 @@ "operationId": "commit_statuses", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -1202,7 +1151,6 @@ "operationId": "list", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -1225,7 +1173,6 @@ "operationId": "show", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -1245,7 +1192,6 @@ "operationId": "list", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -1273,7 +1219,6 @@ }, "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -1293,7 +1238,6 @@ "operationId": "show", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -1321,7 +1265,6 @@ }, "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -1341,7 +1284,6 @@ "operationId": "notes", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -1371,9 +1313,7 @@ "required": true }, "responses": { - "200": { - "description": "" - } + "200": {} } } }, @@ -1394,9 +1334,7 @@ "required": true }, "responses": { - "200": { - "description": "" - } + "200": {} } }, "delete": { @@ -1405,9 +1343,7 @@ ], "operationId": "delete_note", "responses": { - "200": { - "description": "" - } + "200": {} } } }, @@ -1419,7 +1355,6 @@ "operationId": "issue_reactions", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -1447,7 +1382,6 @@ }, "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -1467,7 +1401,6 @@ "operationId": "job_token_allowlist", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -1498,7 +1431,6 @@ }, "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -1520,9 +1452,7 @@ ], "operationId": "disallow_job_token", "responses": { - "200": { - "description": "" - } + "200": {} } } }, @@ -1534,7 +1464,6 @@ "operationId": "show_job", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -1555,7 +1484,6 @@ "operationId": "job_artifacts", "responses": { "200": { - "description": "", "content": { "application/zip": {} } @@ -1571,9 +1499,7 @@ "summary": "One file of a job's artifacts archive (text and a few media types shown,\nanything else downloaded).", "operationId": "artifact_file", "responses": { - "200": { - "description": "" - } + "200": {} } } }, @@ -1586,7 +1512,6 @@ "operationId": "artifact_tree", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -1606,7 +1531,6 @@ "operationId": "cancel_job", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -1626,7 +1550,6 @@ "operationId": "play_job", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -1646,7 +1569,6 @@ "operationId": "job_raw", "responses": { "200": { - "description": "", "content": { "text/plain": {} } @@ -1662,7 +1584,6 @@ "operationId": "retry_job", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -1683,7 +1604,6 @@ "operationId": "job_trace", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -1703,7 +1623,6 @@ "operationId": "labels", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -1734,7 +1653,6 @@ }, "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -1764,7 +1682,6 @@ }, "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -1781,9 +1698,7 @@ ], "operationId": "delete_label", "responses": { - "200": { - "description": "" - } + "200": {} } } }, @@ -1795,7 +1710,6 @@ "operationId": "lfs_locks", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -1818,7 +1732,6 @@ "operationId": "members", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -1841,7 +1754,6 @@ "operationId": "list", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -1872,7 +1784,6 @@ }, "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -1892,7 +1803,6 @@ "operationId": "show", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -1923,7 +1833,6 @@ }, "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -1943,7 +1852,6 @@ "operationId": "code_owners", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -1963,7 +1871,6 @@ "operationId": "diff", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -1993,7 +1900,6 @@ }, "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -2026,7 +1932,6 @@ }, "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -2046,7 +1951,6 @@ "operationId": "merge_status", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -2067,7 +1971,6 @@ "operationId": "add_to_train", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -2087,7 +1990,6 @@ "operationId": "notes", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -2110,7 +2012,6 @@ "operationId": "mr_pipelines", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -2133,7 +2034,6 @@ "operationId": "mr_reactions", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -2162,7 +2062,6 @@ }, "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -2182,7 +2081,6 @@ "operationId": "merge_request", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -2213,7 +2111,6 @@ }, "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -2233,7 +2130,6 @@ "operationId": "mr_tests", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -2254,7 +2150,6 @@ "operationId": "count", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -2275,7 +2170,6 @@ "operationId": "merge_trains", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -2298,7 +2192,6 @@ "operationId": "list", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -2329,7 +2222,6 @@ }, "responses": { "201": { - "description": "", "content": { "application/json": { "schema": { @@ -2349,7 +2241,6 @@ "operationId": "show", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -2377,7 +2268,6 @@ }, "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -2394,9 +2284,7 @@ ], "operationId": "delete", "responses": { - "204": { - "description": "" - } + "204": {} } } }, @@ -2408,7 +2296,6 @@ "operationId": "project", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -2436,7 +2323,6 @@ }, "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -2456,7 +2342,6 @@ "operationId": "pages", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -2476,7 +2361,6 @@ "operationId": "list_schedules", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -2507,7 +2391,6 @@ }, "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -2537,7 +2420,6 @@ }, "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -2554,9 +2436,7 @@ ], "operationId": "delete_schedule", "responses": { - "200": { - "description": "" - } + "200": {} } } }, @@ -2568,9 +2448,7 @@ "summary": "Run a schedule's pipeline now (as its owner).", "operationId": "play_schedule", "responses": { - "200": { - "description": "" - } + "200": {} } } }, @@ -2582,7 +2460,6 @@ "operationId": "list_pipelines", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -2614,7 +2491,6 @@ }, "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -2634,7 +2510,6 @@ "operationId": "show_pipeline", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -2654,7 +2529,6 @@ "operationId": "cancel_pipeline", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -2675,7 +2549,6 @@ "operationId": "retry_pipeline", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -2696,7 +2569,6 @@ "operationId": "pipeline_test_cases", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -2719,7 +2591,6 @@ "operationId": "pipeline_tests", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -2739,7 +2610,6 @@ "operationId": "protected_branches", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -2762,7 +2632,6 @@ "operationId": "protected", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -2793,7 +2662,6 @@ }, "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -2816,7 +2684,6 @@ "operationId": "protected_tags", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -2848,7 +2715,6 @@ }, "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -2870,9 +2736,7 @@ ], "operationId": "unprotect_tag", "responses": { - "200": { - "description": "" - } + "200": {} } } }, @@ -2884,7 +2748,6 @@ "operationId": "push_rule", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -2912,7 +2775,6 @@ }, "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -2932,7 +2794,6 @@ "operationId": "info", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -2952,7 +2813,6 @@ "operationId": "cleanup_policy", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -2980,7 +2840,6 @@ }, "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -3000,7 +2859,6 @@ "operationId": "tags", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -3024,7 +2882,6 @@ "operationId": "list", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -3056,7 +2913,6 @@ }, "responses": { "201": { - "description": "", "content": { "application/json": { "schema": { @@ -3076,7 +2932,6 @@ "operationId": "show", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -3104,7 +2959,6 @@ }, "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -3122,9 +2976,7 @@ "summary": "Delete a release; its tag stays.", "operationId": "delete", "responses": { - "204": { - "description": "" - } + "204": {} } } }, @@ -3146,7 +2998,6 @@ }, "responses": { "201": { - "description": "", "content": { "application/json": { "schema": { @@ -3165,9 +3016,7 @@ ], "operationId": "delete_link", "responses": { - "204": { - "description": "" - } + "204": {} } } }, @@ -3180,7 +3029,6 @@ "operationId": "get", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -3209,7 +3057,6 @@ }, "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -3230,7 +3077,6 @@ "operationId": "host_rules", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -3261,7 +3107,6 @@ }, "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -3283,9 +3128,7 @@ ], "operationId": "delete_host_rule", "responses": { - "204": { - "description": "" - } + "204": {} } } }, @@ -3298,7 +3141,6 @@ "operationId": "run_now", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -3318,7 +3160,6 @@ "operationId": "blame", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -3338,7 +3179,6 @@ "operationId": "blob", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -3358,7 +3198,6 @@ "operationId": "branches", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -3389,9 +3228,7 @@ "required": true }, "responses": { - "200": { - "description": "" - } + "200": {} } } }, @@ -3403,7 +3240,6 @@ "operationId": "commits", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -3435,7 +3271,6 @@ }, "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -3455,7 +3290,6 @@ "operationId": "commit", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -3475,7 +3309,6 @@ "operationId": "commit_diff", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -3496,7 +3329,6 @@ "operationId": "commit_signature", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -3517,7 +3349,6 @@ "operationId": "last_commits", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -3548,7 +3379,6 @@ }, "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -3574,7 +3404,6 @@ "operationId": "stats", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -3605,7 +3434,6 @@ }, "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -3625,9 +3453,7 @@ "summary": "Delete a tag; a release on it is deleted too.", "operationId": "delete_tag", "responses": { - "204": { - "description": "" - } + "204": {} } } }, @@ -3639,7 +3465,6 @@ "operationId": "tree", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -3660,7 +3485,6 @@ "operationId": "project_runners", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -3691,7 +3515,6 @@ }, "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -3711,7 +3534,6 @@ "operationId": "findings", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -3731,7 +3553,6 @@ "operationId": "finding", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -3761,7 +3582,6 @@ }, "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -3781,7 +3601,6 @@ "operationId": "reopen", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -3801,7 +3620,6 @@ "operationId": "scanning", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -3829,7 +3647,6 @@ }, "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -3849,7 +3666,6 @@ "operationId": "run_scan", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -3870,7 +3686,6 @@ "operationId": "storage", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -3891,7 +3706,6 @@ "operationId": "templates", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -3915,7 +3729,6 @@ "operationId": "upload", "responses": { "201": { - "description": "", "content": { "application/json": { "schema": { @@ -3936,7 +3749,6 @@ "operationId": "users", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -3959,7 +3771,6 @@ "operationId": "project_variables", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -3990,7 +3801,6 @@ }, "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -4012,9 +3822,7 @@ ], "operationId": "delete_project_variable", "responses": { - "200": { - "description": "" - } + "200": {} } } }, @@ -4026,7 +3834,6 @@ "operationId": "show_runner", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -4054,7 +3861,6 @@ }, "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -4071,9 +3877,7 @@ ], "operationId": "delete_runner", "responses": { - "200": { - "description": "" - } + "200": {} } } }, @@ -4085,7 +3889,6 @@ "operationId": "reset_runner_token", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -4105,7 +3908,6 @@ "operationId": "search", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -4126,7 +3928,6 @@ "operationId": "session", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -4147,7 +3948,6 @@ "operationId": "unsubscribe_info", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -4166,7 +3966,6 @@ "operationId": "unsubscribe", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -4186,7 +3985,6 @@ "operationId": "me", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -4206,7 +4004,6 @@ "operationId": "list_gpg_keys", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -4237,7 +4034,6 @@ }, "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -4257,7 +4053,6 @@ "operationId": "list_keys", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -4280,7 +4075,6 @@ "operationId": "mine", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -4308,7 +4102,6 @@ }, "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -4328,7 +4121,6 @@ "operationId": "my_projects", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -4351,7 +4143,6 @@ "operationId": "todos", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -4374,7 +4165,6 @@ "operationId": "list_tokens", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -4398,7 +4188,6 @@ "operationId": "work", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -4419,7 +4208,6 @@ "operationId": "profile", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -4440,7 +4228,6 @@ "operationId": "contributions", "responses": { "200": { - "description": "", "content": { "application/json": { "schema": { @@ -5311,10 +5098,10 @@ "method": { "oneOf": [ { - "type": "null" + "$ref": "#/components/schemas/MergeMethod" }, { - "$ref": "#/components/schemas/MergeMethod" + "type": "null" } ] }, @@ -5526,10 +5313,10 @@ "lfs": { "oneOf": [ { - "type": "null" + "$ref": "#/components/schemas/LfsInfo" }, { - "$ref": "#/components/schemas/LfsInfo" + "type": "null" } ] }, @@ -5620,10 +5407,10 @@ "commit": { "oneOf": [ { - "type": "null" + "$ref": "#/components/schemas/CommitSummary" }, { - "$ref": "#/components/schemas/CommitSummary" + "type": "null" } ] }, @@ -6402,10 +6189,10 @@ "options": { "oneOf": [ { - "type": "null" + "$ref": "#/components/schemas/Options" }, { - "$ref": "#/components/schemas/Options" + "type": "null" } ] }, @@ -6566,10 +6353,10 @@ "position": { "oneOf": [ { - "type": "null" + "$ref": "#/components/schemas/NewPosition" }, { - "$ref": "#/components/schemas/NewPosition" + "type": "null" } ] } @@ -7357,10 +7144,10 @@ "last_deployment": { "oneOf": [ { - "type": "null" + "$ref": "#/components/schemas/Deployment" }, { - "$ref": "#/components/schemas/Deployment" + "type": "null" } ] } @@ -7856,12 +7643,12 @@ }, "policy": { "oneOf": [ - { - "type": "null" - }, { "$ref": "#/components/schemas/OrgPolicyDto", "description": "Present on orgs (top-level groups)." + }, + { + "type": "null" } ] } @@ -8913,12 +8700,12 @@ }, "downstream": { "oneOf": [ - { - "type": "null" - }, { "$ref": "#/components/schemas/PipelineLink", "description": "The pipeline a bridge started (when the viewer may see it)." + }, + { + "type": "null" } ] }, @@ -8933,10 +8720,10 @@ "environment": { "oneOf": [ { - "type": "null" + "$ref": "#/components/schemas/JobEnvironment" }, { - "$ref": "#/components/schemas/JobEnvironment" + "type": "null" } ] }, @@ -9463,10 +9250,10 @@ "session": { "oneOf": [ { - "type": "null" + "$ref": "#/components/schemas/SessionInfo" }, { - "$ref": "#/components/schemas/SessionInfo" + "type": "null" } ] }, @@ -9772,10 +9559,10 @@ "method": { "oneOf": [ { - "type": "null" + "$ref": "#/components/schemas/MergeMethod" }, { - "$ref": "#/components/schemas/MergeMethod" + "type": "null" } ] }, @@ -10060,12 +9847,12 @@ }, "auto_merge_user": { "oneOf": [ - { - "type": "null" - }, { "$ref": "#/components/schemas/UserBrief", "description": "Who set auto-merge, when it is on." + }, + { + "type": "null" } ] }, @@ -10093,12 +9880,12 @@ }, "stack": { "oneOf": [ - { - "type": "null" - }, { "$ref": "#/components/schemas/StackView", "description": "The stack this MR belongs to, bottom first (ADR-0019)." + }, + { + "type": "null" } ] }, @@ -10201,10 +9988,10 @@ "stack": { "oneOf": [ { - "type": "null" + "$ref": "#/components/schemas/StackBadge" }, { - "$ref": "#/components/schemas/StackBadge" + "type": "null" } ] } @@ -10271,10 +10058,10 @@ "base": { "oneOf": [ { - "type": "null" + "$ref": "#/components/schemas/Totals" }, { - "$ref": "#/components/schemas/Totals" + "type": "null" } ] }, @@ -10296,10 +10083,10 @@ "head": { "oneOf": [ { - "type": "null" + "$ref": "#/components/schemas/Totals" }, { - "$ref": "#/components/schemas/Totals" + "type": "null" } ] }, @@ -10739,12 +10526,12 @@ }, "position": { "oneOf": [ - { - "type": "null" - }, { "$ref": "#/components/schemas/MappedPosition", "description": "Where the thread sits on the requested version; null when outdated." + }, + { + "type": "null" } ] }, @@ -10953,10 +10740,10 @@ "deployment": { "oneOf": [ { - "type": "null" + "$ref": "#/components/schemas/PagesDeployment" }, { - "$ref": "#/components/schemas/PagesDeployment" + "type": "null" } ] }, @@ -10985,12 +10772,12 @@ "properties": { "commit": { "oneOf": [ - { - "type": "null" - }, { "$ref": "#/components/schemas/CommitInfo", "description": "Last commit that touched this entry (none when it could not be found in time)." + }, + { + "type": "null" } ] }, @@ -11216,12 +11003,12 @@ }, "upstream": { "oneOf": [ - { - "type": "null" - }, { "$ref": "#/components/schemas/PipelineLink", "description": "The pipeline whose `trigger` job started this one (when the viewer may see it)." + }, + { + "type": "null" } ] } @@ -11525,12 +11312,12 @@ }, "storage_warning": { "oneOf": [ - { - "type": "null" - }, { "$ref": "#/components/schemas/Warning", "description": "Its storage quota, or its namespace's, is 80 % or 100 % full (for those\nwho can push)." + }, + { + "type": "null" } ] } @@ -11728,23 +11515,23 @@ "properties": { "namespace": { "oneOf": [ - { - "type": "null" - }, { "$ref": "#/components/schemas/QuotaUse", "description": "Its top-level namespace's (shared by all its projects)." + }, + { + "type": "null" } ] }, "quota": { "oneOf": [ - { - "type": "null" - }, { "$ref": "#/components/schemas/QuotaUse", "description": "The project's own quota." + }, + { + "type": "null" } ] }, @@ -12256,12 +12043,12 @@ "properties": { "commit": { "oneOf": [ - { - "type": "null" - }, { "$ref": "#/components/schemas/CommitBrief", "description": "The tagged commit (none when the tag is gone)." + }, + { + "type": "null" } ] }, @@ -12424,10 +12211,10 @@ "last_run": { "oneOf": [ { - "type": "null" + "$ref": "#/components/schemas/RenovateRun" }, { - "$ref": "#/components/schemas/RenovateRun" + "type": "null" } ] }, @@ -13442,12 +13229,12 @@ }, "impersonator": { "oneOf": [ - { - "type": "null" - }, { "$ref": "#/components/schemas/UserDto", "description": "The administrator signed in as `user` (impersonation), if any." + }, + { + "type": "null" } ] }, @@ -13944,12 +13731,12 @@ }, "scan": { "oneOf": [ - { - "type": "null" - }, { "$ref": "#/components/schemas/BlobScan", "description": "The last listing of the blob store, if any." + }, + { + "type": "null" } ] }, @@ -14041,10 +13828,10 @@ "commit": { "oneOf": [ { - "type": "null" + "$ref": "#/components/schemas/CommitSummary" }, { - "$ref": "#/components/schemas/CommitSummary" + "type": "null" } ] }, @@ -14471,12 +14258,12 @@ }, "last_commit": { "oneOf": [ - { - "type": "null" - }, { "$ref": "#/components/schemas/CommitInfo", "description": "Last commit that touched this directory." + }, + { + "type": "null" } ] }, diff --git a/web/package-lock.json b/web/package-lock.json index 3564d6e..4495950 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -10,24 +10,23 @@ "dependencies": { "@fontsource-variable/inter": "5.3.0", "@fontsource/jetbrains-mono": "5.3.0", - "@tanstack/react-query": "5.62.7", - "@tanstack/react-virtual": "3.11.1", + "@tanstack/react-query": "5.107.1", + "@tanstack/react-virtual": "3.14.26", "katex": "^0.19.1", - "lucide-react": "0.468.0", - "mermaid": "12.2.0", + "lucide-react": "1.71.0", + "mermaid": "12.3.0", "radix-ui": "1.8.1", - "react": "18.3.1", - "react-dom": "18.3.1", + "react": "19.3.1", + "react-dom": "19.3.1", "react-router-dom": "7.18.5" }, "devDependencies": { - "@playwright/test": "1.64.1", - "@types/react": "18.3.12", - "@types/react-dom": "18.3.1", - "@vitejs/plugin-react": "4.3.4", - "openapi-typescript": "7.4.4", - "typescript": "5.6.3", - "vite": "6.4.5" + "@playwright/test": "1.65.0", + "@types/react": "19.3.0", + "@types/react-dom": "19.3.0", + "@vitejs/plugin-react": "^6.3.0", + "typescript": "7.0.2", + "vite": "^8.3.7" } }, "node_modules/@antfu/install-pkg": { @@ -43,288 +42,6 @@ "url": "https://github.com/sponsors/antfu" } }, - "node_modules/@babel/code-frame": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", - "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-validator-identifier": "^7.29.7", - "js-tokens": "^4.0.0", - "picocolors": "^1.1.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", - "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.29.13", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.13.tgz", - "integrity": "sha512-j1nvOQCZYSgp7HLmisnCXFTpVvFODiijQ9QHkORfGKWH6YDtskTEeCJS7eV545GZ9UBzrq0e2xsOd5QQ5PjIqw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.29.7", - "@babel/generator": "^7.29.13", - "@babel/helper-compilation-targets": "^7.29.13", - "@babel/helper-module-transforms": "^7.29.13", - "@babel/helpers": "^7.29.13", - "@babel/parser": "^7.29.13", - "@babel/template": "^7.29.7", - "@babel/traverse": "^7.29.13", - "@babel/types": "^7.29.11", - "@jridgewell/remapping": "^2.3.5", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/generator": { - "version": "7.29.13", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.13.tgz", - "integrity": "sha512-T5FRo+RzVHvGjWOuF1Ljc44b+NXAOazodHkGUHp4I3zCkQ4/sNVJm56h1S278LMR0bY5xBhztGziSbli8zObIw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.29.13", - "@babel/types": "^7.29.11", - "@jridgewell/gen-mapping": "^0.3.12", - "@jridgewell/trace-mapping": "^0.3.28", - "jsesc": "^3.0.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.29.13", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.13.tgz", - "integrity": "sha512-8WxJ4/Vmes3ghacj8VOJy3NW8eyHiFY/4thU/LSBuBE470+igjR/j1ZTNn8fV5VdNrLx6iXUwig526UdOvfP0w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.29.7", - "@babel/helper-validator-option": "^7.29.7", - "browserslist": "^4.24.0", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-globals": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", - "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", - "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.29.7", - "@babel/types": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.29.13", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.13.tgz", - "integrity": "sha512-/U96wOz+SCoZ7Da/8kjDGltcNY280JPQcRNPK0Hk3PTbdpaiBDQImtC6JsbVwb1HGMr3usZQU2WsWVjhYNmRzw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-imports": "^7.29.7", - "@babel/helper-validator-identifier": "^7.29.7", - "@babel/traverse": "^7.29.13" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz", - "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.29.13", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.13.tgz", - "integrity": "sha512-fWegr+WsEsiMVW4KUNdIIzzMTZSzNiqhy0//6+2MRi2d5NFNsL/AYwBQW8eBnRbTBVRnDVzjaJEUqKaCWjMMdQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", - "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", - "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.29.13", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.13.tgz", - "integrity": "sha512-laoRpD/kO/iA4CDlgJbixHekg7oPvWALK0PQyK3Ob2I2njZRvVAD77RfWCIImtqWCq6KijoBoZK7bp/HlTWASQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/template": "^7.29.7", - "@babel/types": "^7.29.11" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.29.13", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.13.tgz", - "integrity": "sha512-fJM50YYjlTiBhgdkGmC1tBpv+FMAyo4annf2X6Aks+0yRlaiVkYW/3f07xAfVVkYIoZ9fFZp+mEThUFnuybhkQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.29.11" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-self": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.29.7.tgz", - "integrity": "sha512-TL0hMc9xzy86VD31nUiwzd5otRAcyEPcsegCxolO0PvcXuH1v0kECe/UIznYFihpkvU5wg/jk4v0TTEFfm53fw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-source": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.29.7.tgz", - "integrity": "sha512-06IyK09H3wi4cGbhDBwp5gUGo0IKtnYa8tyTiephirPCK6fbobVGiXMMI5zLQ4aKEYP3wZ3ArU44o+8KMrSG/Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/template": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", - "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.29.7", - "@babel/parser": "^7.29.7", - "@babel/types": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.29.13", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.13.tgz", - "integrity": "sha512-0ve0xMlFA73dgY1oyJRY6RoW+/bncdcOQqg6jjYcVfXBK90OdLXjm9R6lmRetdZVrPjXkKIoMVBqYFPjcAlZ4Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.29.7", - "@babel/generator": "^7.29.13", - "@babel/helper-globals": "^7.29.7", - "@babel/parser": "^7.29.13", - "@babel/template": "^7.29.7", - "@babel/types": "^7.29.11", - "debug": "^4.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/types": { - "version": "7.29.11", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.11.tgz", - "integrity": "sha512-WCsemW40Cpc6gouC1SrY6PBaZ+oLRlEVY9XBvZBI7il/HyUrb2nJ505wE1MHEFyDZNnrWDEuy4jL50WVHfTTSQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-string-parser": "^7.29.11", - "@babel/helper-validator-identifier": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@braintree/sanitize-url": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-7.1.2.tgz", @@ -368,446 +85,38 @@ "integrity": "sha512-SzKYY68rseOrb9KILVzPsl6SjkQtdWw01SRGB5aCVI5kFcHltQsOYV3JB0Ffst72DgkvHCyDQ0NLwxtmCCf97Q==", "license": "Apache-2.0" }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", - "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", - "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", - "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", - "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", - "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", - "cpu": [ - "arm64" - ], + "node_modules/@emnapi/core": { + "version": "2.0.0-beta.2", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-2.0.0-beta.2.tgz", + "integrity": "sha512-MzCVoWtcg4Pm2B3je5mMvYMvj3MmBKw+fU7vbsJc9/iT8ip6/eYIHo/Dsm/mr+wsHB6SEyJDuxB09Yy6r/8+4A==", "dev": true, "license": "MIT", "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", - "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", - "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", - "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", - "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", - "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", - "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", - "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", - "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", - "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", - "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", - "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", - "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", - "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", - "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", - "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", - "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openharmony-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", - "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", - "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", - "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" + "dependencies": { + "@emnapi/wasi-threads": "2.2.0", + "tslib": "^2.4.0" } }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", - "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", - "cpu": [ - "ia32" - ], + "node_modules/@emnapi/runtime": { + "version": "2.0.0-beta.2", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-2.0.0-beta.2.tgz", + "integrity": "sha512-JcrSPzPvZuNZvJqPTF9Fw25LbOJ8avzFVlaf2grmH4Cku0oGP47tRgqPZadcfj3YoZMHkFVnCYFbQM8I+i5QEw==", "dev": true, "license": "MIT", "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" + "dependencies": { + "tslib": "^2.4.0" } }, - "node_modules/@esbuild/win32-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", - "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", - "cpu": [ - "x64" - ], + "node_modules/@emnapi/wasi-threads": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-2.2.0.tgz", + "integrity": "sha512-JP7OYH38Q7+pyTAe14raZHLQIK7BDKbdwji+Xi3pcd/6QkJYQH3SX4wu6EplGrGJWRepoNzedfm0G3B9Z4e9Rw==", "dev": true, "license": "MIT", "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" + "dependencies": { + "tslib": "^2.4.0" } }, "node_modules/@floating-ui/core": { @@ -883,76 +192,58 @@ "import-meta-resolve": "^4.2.0" } }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.13", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", - "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", - "dev": true, + "node_modules/@mermaid-js/parser": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@mermaid-js/parser/-/parser-2.0.1.tgz", + "integrity": "sha512-j37dj/h6p6pots1L7pLPPNuABEEu9WP4OYg9pW1g+nYG331j0+3canE9OagtYdytYvdSAMG+2fKU5cxep6LgjA==", "license": "MIT", "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" + "@chevrotain/types": "~13.2.0" + }, + "engines": { + "node": ">=22.12.0" } }, - "node_modules/@jridgewell/remapping": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", - "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.2.6.tgz", + "integrity": "sha512-mRyDmEw9/fCDXCGfL1sbgIw/GUK0PVxRW4YwgPN61F3LQ+fSyoBFarJVzgGyhF6kRzEQZ0FejDqm4WLXSeqQmw==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, - "license": "MIT", + "@tybys/wasm-util": "^0.10.3" + }, "engines": { - "node": ">=6.0.0" + "node": "^20.19.0 || ^22.13.0 || >=23.5.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1 || 2.0.0-beta.2", + "@emnapi/runtime": "^1.7.1 || 2.0.0-beta.2" } }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.6.0.tgz", - "integrity": "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.31", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", - "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "node_modules/@oxc-project/types": { + "version": "0.156.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.156.0.tgz", + "integrity": "sha512-1Duyg48TdJNdyhEB8Xn1L36bT9Pv6GUtlKjHxOys8xkaF/rQq3XJE+bAurSK/AgIz5mGFsb77cn9Pb20+WCScw==", "dev": true, "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@mermaid-js/parser": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@mermaid-js/parser/-/parser-2.0.1.tgz", - "integrity": "sha512-j37dj/h6p6pots1L7pLPPNuABEEu9WP4OYg9pW1g+nYG331j0+3canE9OagtYdytYvdSAMG+2fKU5cxep6LgjA==", - "license": "MIT", - "dependencies": { - "@chevrotain/types": "~13.2.0" - }, - "engines": { - "node": ">=22.12.0" + "funding": { + "url": "https://github.com/sponsors/oxc-project" } }, "node_modules/@playwright/test": { - "version": "1.64.1", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.64.1.tgz", - "integrity": "sha512-IaYGml/nSOiZWROfPtuIL7neuu9qDOZ3TNvNljUIrhDMxiGTgPjzj/g9p9RxpS2tSepPDRY+UwAaEeiKtUvIAg==", + "version": "1.65.0", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.65.0.tgz", + "integrity": "sha512-iGURLGuKDLakSEl7Pgfv8h7f+XLT+V861Wfhz0zlEl5nyFuKUopdkFBPKqTllTUp06aOwPuH8iuUEb3yp3MpbQ==", "dev": true, "license": "Apache-2.0", "dependencies": { - "playwright": "1.64.1" + "playwright": "1.65.0" }, "bin": { "playwright": "cli.js" @@ -2464,56 +1755,10 @@ "integrity": "sha512-JtyZR+mqgBibTo8xea3B6ZRmzZiM/YeVBtUkas6zMuXjAlfIFIW2FgqeM9eLyvEaYX66vr6DJMK+4U6LV0KhNw==", "license": "MIT" }, - "node_modules/@redocly/ajv": { - "version": "8.11.2", - "resolved": "https://registry.npmjs.org/@redocly/ajv/-/ajv-8.11.2.tgz", - "integrity": "sha512-io1JpnwtIcvojV7QKDUSIuMN/ikdOUd1ReEnUnMKGfDVridQZ31J0MmIuqwuRjWDZfmvr+Q0MqCcfHM2gTivOg==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js-replace": "^1.0.1" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/@redocly/config": { - "version": "0.22.0", - "resolved": "https://registry.npmjs.org/@redocly/config/-/config-0.22.0.tgz", - "integrity": "sha512-gAy93Ddo01Z3bHuVdPWfCwzgfaYgMdaZPcfL7JZ7hWJoK9V0lXDbigTWkhiPFAaLWzbOJ+kbUQG1+XwIm0KRGQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@redocly/openapi-core": { - "version": "1.34.24", - "resolved": "https://registry.npmjs.org/@redocly/openapi-core/-/openapi-core-1.34.24.tgz", - "integrity": "sha512-jDFMu4zirFVOF9nEWCT31s7OzzVhkxZkb4lO3yZhkdPXAOspLo10ED9thVgm6gtI0dJBTLa+mNP0IYeZpVSYGA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@redocly/ajv": "8.11.2", - "@redocly/config": "0.22.0", - "colorette": "1.4.0", - "https-proxy-agent": "7.0.6", - "js-levenshtein": "1.1.6", - "js-yaml": "4.3.2", - "minimatch": "5.1.9", - "pluralize": "8.0.0", - "yaml-ast-parser": "0.0.43" - }, - "engines": { - "node": ">=18.17.0", - "npm": ">=9.5.0" - } - }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.68.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.68.0.tgz", - "integrity": "sha512-Ta2n0ntLfzP0LqwwcXOIh2z0mnHjlxMS+h4Y9lo+w33Quyf9KFKEi9QZ2IKqeEBKr0qxNpXc/DQjz5KVIs8AEA==", + "node_modules/@rolldown/binding-android-arm-eabi": { + "version": "1.2.19", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm-eabi/-/binding-android-arm-eabi-1.2.19.tgz", + "integrity": "sha512-e+Ebe0WT+9tbXmNKPIiC8YrWAHYwug3m6i4p3rZGGulfZri1jtI4HslT+OZnFf/OIHowWF71DTlHwXBP2SiA7A==", "cpu": [ "arm" ], @@ -2522,12 +1767,15 @@ "optional": true, "os": [ "android" - ] + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.68.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.68.0.tgz", - "integrity": "sha512-iFDtS0oMaBvKbtrRKXmRcBSsI0UaWL2bWpd62iHzb0A8RSPrVz47mUGE0CfrrD0c/7/7dUhNtoN3cc6aEUn1Ow==", + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.2.19", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.19.tgz", + "integrity": "sha512-hOombrTJ+szt2ciEzS7oCA78lMPBgF5UMQWCJIyNfnrI7GLl8HYoFqCnpL2gcPOaXMqryGCU5ExdQKyDDcC+yA==", "cpu": [ "arm64" ], @@ -2536,26 +1784,15 @@ "optional": true, "os": [ "android" - ] - }, - "node_modules/@rollup/rollup-android-x64": { - "version": "4.68.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-x64/-/rollup-android-x64-4.68.0.tgz", - "integrity": "sha512-OnYETr+cZYSbesBD1tCvUjrBUTkjSaOcewRUoIHqD0XI3yn5i9WpdFaE3LZwrMlq0yeJNU0N5sxfHK/fNVMqlQ==", - "cpu": [ - "x64" ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.68.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.68.0.tgz", - "integrity": "sha512-2qavWZtFeon/6oMkjsBF3OH7ENKgRTW4xRTwmz9VJeNUYhmPitpR9Jd4sAAc2OZJryHs2neoovMTCYnNvhvANQ==", + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.2.19", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.19.tgz", + "integrity": "sha512-XoMA2pwCKGTQzUjPgtRwkedH4WmXhdIPKT6l6oOxd1PUbNodGI6DcBekgN7EC//+x3pfBYX/qL1gNmZAqivw5g==", "cpu": [ "arm64" ], @@ -2564,12 +1801,15 @@ "optional": true, "os": [ "darwin" - ] + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.68.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.68.0.tgz", - "integrity": "sha512-QpgJO+GwNQDPt6uYcFSjZTFVyHNIeumN2am7RISDR9Nf3e/h8sur9cIfplPGihZPUn+sTw9j3JErZIUkHg8+Pw==", + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.2.19", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.19.tgz", + "integrity": "sha512-zo8EsSSwMZCY/e+fRnGaX02YGgvJD0yvhNi/9hpGPA2MJ9ZF8dPCw75UGfpI6OpQ/myR/dIYmogRvqiZD0TrXg==", "cpu": [ "x64" ], @@ -2578,26 +1818,15 @@ "optional": true, "os": [ "darwin" - ] - }, - "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.68.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.68.0.tgz", - "integrity": "sha512-TERqEn6P9bp4lsTyoFjT3nLKV6G++76HhGb4k6dRGcs+jvhVcTGaS2zkeRdLLRjwKxpBtdCZe11kUQ2hNGgFSA==", - "cpu": [ - "arm64" ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.68.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.68.0.tgz", - "integrity": "sha512-RBjDrqb7h5l6Xgdgz5eKYvbpnUkii/z5ejWuZmHJsXORi0X0tTtFzEEgJj2DX995kW18c6T9LGFn/deEAMXDcQ==", + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.2.19", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.19.tgz", + "integrity": "sha512-O8ISAOfI1nj7AuBPd30FSF47z7f7lzlk5poQVGgiikvQuGEBFYvW8ki+UEnT+YJPnNGjQzn304klt4O9FUE7mA==", "cpu": [ "x64" ], @@ -2606,26 +1835,15 @@ "optional": true, "os": [ "freebsd" - ] - }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.68.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.68.0.tgz", - "integrity": "sha512-HtLgXBqjF1Ampt9eJjzSmoGDvNb4LP8Y2aPXQZeQ5qhyExXLmoXJB9Jfm/nPi/8fJ3UFn4sZ7pQKyr8V+oTN8g==", - "cpu": [ - "arm" ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.68.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.68.0.tgz", - "integrity": "sha512-q51xJyqjaqCNtDjYD7xNVwsPa2TcVfAIBeP6E20wicKZ6XYp8Taz9SUPYhIENojAQIAoV7cO3mUdMUgWYEAuhQ==", + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.2.19", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.19.tgz", + "integrity": "sha512-/lYCba5NO0yq4S0jGMH8QTBtkvQxoXjoQWzF5BcWp9MjB9jxVRD1GQDNofkVjcOj30DWyhLIN/4Oe60JKzaONw==", "cpu": [ "arm" ], @@ -2634,26 +1852,15 @@ "optional": true, "os": [ "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.68.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.68.0.tgz", - "integrity": "sha512-wejnVabl92oFC/o4sr/EEJuJZMHtMq4C+LBIPphN4EUiVHe9qvZNw+biqhVHpX2ggs1+Z3ugXGwJxT+qhyaaYQ==", - "cpu": [ - "arm64" ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.68.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.68.0.tgz", - "integrity": "sha512-tyu+hrsCWHHqV6+2tligV/recJH+HVvNV2Sp4nS1C+MKQPkNXRovKIzyHy0V0xXjm6igCLgsT2vTky5CvWP37g==", + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.2.19", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.19.tgz", + "integrity": "sha512-pm/apFMBnSbFb3O6nG5pHO1iqHhZrjGDFEjSm+ot9J17XXPvH9L90y5h+jgfHCE+Qdlsvy8qKEcU4VKxgjD+vA==", "cpu": [ "arm64" ], @@ -2662,54 +1869,32 @@ "optional": true, "os": [ "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.68.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.68.0.tgz", - "integrity": "sha512-5gjJNglKDfgs3OmnGi/RVZQPhEfRoCIHxwSAP9ngmdnxreu0Vl9lI4gxmFBXOhKdftpS82xRdc/7Dp5/A1F0qg==", - "cpu": [ - "loong64" ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-linux-loong64-musl": { - "version": "4.68.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.68.0.tgz", - "integrity": "sha512-2IBxTUds33rFYwOIEyf77wfW8WQThwiQQ1ofXSraZQG7PiIq7BnQBf/ge0qEI/Ny/2cSc7SKkGO/wUDqmYXqTg==", + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.2.19", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.19.tgz", + "integrity": "sha512-K1SmQp3FFichn8oqrNIwvFoZ5wcvjC7goBzpaMNvLf9FZc+QB/QvLmnpJZgAAGHiD980tP8FZZnXk2K94rvlxg==", "cpu": [ - "loong64" + "arm64" ], "dev": true, "license": "MIT", "optional": true, "os": [ "linux" - ] - }, - "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.68.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.68.0.tgz", - "integrity": "sha512-mE/Pj2PPTZIVHkNNuHq+eYoU3td8LCm73zjrXoBWkNlnuULJS2l/fxwgGPpN4WUCNZgKZ1IXwrnnETPyOcWPmg==", - "cpu": [ - "ppc64" ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-linux-ppc64-musl": { - "version": "4.68.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.68.0.tgz", - "integrity": "sha512-dYuykUkAiTv+RQdP3Ib47XcFiImkBWiRpTGSQWAMfZPQyoQYGe8Je4IUeZYNUQWIojmRCUnt5xsH4BbUb2uqSw==", + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.2.19", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.19.tgz", + "integrity": "sha512-I0xwD57jP/3A7+5UPZin2w8Y7XHEmEM5zqpYZOcQ45MlNW6tUJUziymV3yRr7rL4vwyfEcRsRksC4a7Kc08p5Q==", "cpu": [ "ppc64" ], @@ -2718,40 +1903,15 @@ "optional": true, "os": [ "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.68.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.68.0.tgz", - "integrity": "sha512-OnPDDFXLqJewY56T6ow8sA4wuzbqlliD7QJgkrx2KX+pWOpjI3usYXgB0pwK3nsgTF2odCw9IuJs0Uis/jy2qA==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.68.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.68.0.tgz", - "integrity": "sha512-CqoQf06cK0brrRfDqH7Mt8G4MdteFGbjBdC61zEMaSVna6xo6QMUixa9bAkAD4a92g3ElPbQAkLMUzdf+Lk8dg==", - "cpu": [ - "riscv64" ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.68.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.68.0.tgz", - "integrity": "sha512-LPHNmE8GwiyELGLUTkqj4zsP1YEHzGdtwnKxAcdP/swsNxXsfxPtpe5nrD/KGxr136xPB+eWv2r/SGj9md0pnQ==", + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.2.19", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.19.tgz", + "integrity": "sha512-BrtEHT24SNXj9HiXqy+s/kXiSiQGt6EKCPUlRirAoIioVxKGnbXBUEkbZASAei7iZJB0/Ynm+0JP00Ipx7AnSw==", "cpu": [ "s390x" ], @@ -2760,12 +1920,15 @@ "optional": true, "os": [ "linux" - ] + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.68.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.68.0.tgz", - "integrity": "sha512-GDOmvgephpRCNyNGRQOZh0KD2gTyRVM1Bb1iOo759xeCUpCAoRCmJioOOSu2MwyWfNOocGd0V5I9vYLfteC6/A==", + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.2.19", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.19.tgz", + "integrity": "sha512-rm75/9DkHKeU2WnA8w4X94WGYgLlDCFCfkQC+4bguVJmC/jvDRv2B+2wLOYhyE0fVuv7//Ckk39OoOufyCu76Q==", "cpu": [ "x64" ], @@ -2774,12 +1937,15 @@ "optional": true, "os": [ "linux" - ] + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.68.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.68.0.tgz", - "integrity": "sha512-HADRxkvl5eg3hbemCmv81UwTfdQy/CiSJDOabLE+p5tpm3OTjuRtzpLXy5zPfGY9FQD4Qv7qHptXmG/YjmNmyw==", + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.2.19", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.19.tgz", + "integrity": "sha512-irh/4+iYFM4GAzpluDErgjz89bj6NDtqqMAG/6O1LG38Ed3NpyebzCpcVNkFW8uhy+/3/BocUvnXDR33CXWe9A==", "cpu": [ "x64" ], @@ -2788,26 +1954,15 @@ "optional": true, "os": [ "linux" - ] - }, - "node_modules/@rollup/rollup-openbsd-x64": { - "version": "4.68.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.68.0.tgz", - "integrity": "sha512-iERrpqu1VEfyX736HLKiXRbwGDkCV/iybARY/mn14KcI6oKhJGBx1e+bU+g+umTKghtiGSPaHkwwpII4/N3RjA==", - "cpu": [ - "x64" ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ] + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.68.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.68.0.tgz", - "integrity": "sha512-hBn57IqAbpXpyktckonwePTaFOQS6THph8ZnpRO3eZHY4LncuZGjSsseigBnKuSMKKpLnJJ7PemDvXEzniXC+A==", + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.2.19", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.19.tgz", + "integrity": "sha512-+KWTWNoPt+CfSq94CiceWu3yPE+QzkaG+phPyz9G60tmZLwfQkcA4AeksafzvJAw4pvg1mcd5a1TkUqVv0s4JA==", "cpu": [ "arm64" ], @@ -2816,40 +1971,51 @@ "optional": true, "os": [ "openharmony" - ] + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.68.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.68.0.tgz", - "integrity": "sha512-pJWb7mIw9Z25Hl3Q6nHFjl7AnczfOpm2gbOFYguSRv6TiH7DzsoAk/thymb/URSQu9OUEK7uaDMC5Xfm+7TAww==", + "node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.2.19", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.2.19.tgz", + "integrity": "sha512-7EH+skOsl5qpWnK0vzamgJFhOv1cwxQpsxm8tI883K9fur5c27p8q87fzEO6BbBPabA2/+s/zR63/pLc137iOg==", "cpu": [ - "arm64" + "wasm32" ], "dev": true, "license": "MIT", "optional": true, - "os": [ - "win32" - ] + "dependencies": { + "@emnapi/core": "2.0.0-beta.2", + "@emnapi/runtime": "2.0.0-beta.2", + "@napi-rs/wasm-runtime": "1.2.6" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=23.5.0" + } }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.68.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.68.0.tgz", - "integrity": "sha512-pnrhmoyF2otH2Mezol14/ELUFGuRddOCz6+I+J0pq2Itnp4UxkjABQcXawCNMaKNsCRiuL90BtNzbEd0fHjpIg==", + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.2.19", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.19.tgz", + "integrity": "sha512-3Q1Yg1Q7tEvBWoZf5rFvG/GKZQPgwfru+p4wBajDfJFBs0SHCpL++dfTjW9gyAKd1T7ZpIYvdaUax7Pa/IhFVQ==", "cpu": [ - "ia32" + "arm64" ], "dev": true, "license": "MIT", "optional": true, "os": [ "win32" - ] + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.68.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.68.0.tgz", - "integrity": "sha512-1dJ3U+ktdtaIdPaOZKwIX57+bKQk4iAjs5M1wQWLKRB6Wglp98qf8LUeuN4u6bGlIYouZKaySZJ5Qd4OalUMnA==", + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.2.19", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.19.tgz", + "integrity": "sha512-y/sqRRc6d7hECzOFc5n3LSeqctmIp9mMjY1Kq4s14uLPd/LZ4z7i1zrW6fMtp2mPeuQIC4e6ULMcwQzMomqQag==", "cpu": [ "x64" ], @@ -2858,26 +2024,22 @@ "optional": true, "os": [ "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.68.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.68.0.tgz", - "integrity": "sha512-e/NRJFl48wL5DFNSzQrvm4kaB5dzNNmqWjIJ6And2Sjuw4klO3w3TXMvCAEF1tHTrQQgpOD4QVkBE/92/yBGrQ==", - "cpu": [ - "x64" ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.1.1.tgz", + "integrity": "sha512-glFIJDvLNDtJhT9qrMFWLPbvS+skxgt4L0K8Ei2YtnhPysAJnsI7nyxSJxKj4ADeKX0OLjC4ntRkwpLOoS3rwA==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] + "license": "MIT" }, "node_modules/@tanstack/query-core": { - "version": "5.62.7", - "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.62.7.tgz", - "integrity": "sha512-fgpfmwatsrUal6V+8EC2cxZIQVl9xvL7qYa03gsdsCy985UTUlS4N+/3hCzwR0PclYDqisca2AqR1BVgJGpUDA==", + "version": "5.107.1", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.107.1.tgz", + "integrity": "sha512-PSyAik11oQBEVOiVy5hjZWHmoUqOXqK1WYy4v55mcxozEfKaQgpUMsgnXhWjuESzSht8JfzqMS1m6M/9CpNgvg==", "license": "MIT", "funding": { "type": "github", @@ -2885,91 +2047,63 @@ } }, "node_modules/@tanstack/react-query": { - "version": "5.62.7", - "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.62.7.tgz", - "integrity": "sha512-+xCtP4UAFDTlRTYyEjLx0sRtWyr5GIk7TZjZwBu4YaNahi3Rt2oMyRqfpfVrtwsqY2sayP4iXVCwmC+ZqqFmuw==", + "version": "5.107.1", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.107.1.tgz", + "integrity": "sha512-udCOOLp3ZAheUrIHLCe+ZZge6nr2ZUrGMSWcCuXsjY1Bf2JeeE09oxst97PILiCY6N8xo/7bIo3Hvz13zh06FA==", "license": "MIT", "dependencies": { - "@tanstack/query-core": "5.62.7" + "@tanstack/query-core": "5.107.1" }, "funding": { "type": "github", "url": "https://github.com/sponsors/tannerlinsley" }, "peerDependencies": { + "@types/react": "^18 || ^19", "react": "^18 || ^19" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, "node_modules/@tanstack/react-virtual": { - "version": "3.11.1", - "resolved": "https://registry.npmjs.org/@tanstack/react-virtual/-/react-virtual-3.11.1.tgz", - "integrity": "sha512-orn2QNe5tF6SqjucHJ6cKTKcRDe3GG7bcYqPNn72Yejj7noECdzgAyRfGt2pGDPemhYim3d1HIR/dgruCnLfUA==", + "version": "3.14.26", + "resolved": "https://registry.npmjs.org/@tanstack/react-virtual/-/react-virtual-3.14.26.tgz", + "integrity": "sha512-HUDlfsrYH6ko5xH56L62Mcl/uzT+AGVNMHFuDNqDJMdZWc1AQa2oeVKNUvZ/RWBZQ4TYtyQerFrNvLnp39h65A==", "license": "MIT", "dependencies": { - "@tanstack/virtual-core": "3.10.9" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" + "@tanstack/virtual-core": "3.19.11" }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", - "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" - } - }, - "node_modules/@tanstack/virtual-core": { - "version": "3.10.9", - "resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.10.9.tgz", - "integrity": "sha512-kBknKOKzmeR7lN+vSadaKWXaLS0SZZG+oqpQ/k80Q6g9REn6zRHS/ZYdrIzHnpHgy/eWs00SujveUN/GJT2qTw==", - "license": "MIT", "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - } - }, - "node_modules/@types/babel__core": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", - "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "node_modules/@types/babel__generator": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", - "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.0.0" + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, - "node_modules/@types/babel__template": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", - "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", - "dev": true, + "node_modules/@tanstack/virtual-core": { + "version": "3.19.11", + "resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.19.11.tgz", + "integrity": "sha512-/5iHb0RHBvj8Di59FDs4ESNm45jls33aZAi4zccVXZjc/6ZvwQP6nzEYeT6weXjTf9E6/vrp2JhYWRyO+ZP13A==", "license": "MIT", - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" } }, - "node_modules/@types/babel__traverse": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", - "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "node_modules/@tybys/wasm-util": { + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.4.tgz", + "integrity": "sha512-W3c4gRigFS0T/Ma4qIYF3GDAc5AQdHb1yL5znJT1Zv1YaD9Kitx656wBjvr19qbiosmZT8lWDM5BEMynUqX65A==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { - "@babel/types": "^7.28.2" + "tslib": "^2.4.0" } }, "node_modules/@types/d3": { @@ -3225,45 +2359,30 @@ "@types/d3-selection": "*" } }, - "node_modules/@types/estree": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.10.tgz", - "integrity": "sha512-lTyOMnOcmRBzdCv6/4zUZCrEhV0xrqQiUZBZtVcbmLHBXKLnN8q89v/wKRF/Q0HbwVsqbIG3o5HDoFl9sduM+g==", - "dev": true, - "license": "MIT" - }, "node_modules/@types/geojson": { "version": "7946.0.16", "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz", "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", "license": "MIT" }, - "node_modules/@types/prop-types": { - "version": "15.7.15", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", - "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", - "devOptional": true, - "license": "MIT" - }, "node_modules/@types/react": { - "version": "18.3.12", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.12.tgz", - "integrity": "sha512-D2wOSq/d6Agt28q7rSI3jhU7G6aiuzljDGZ2hTZHIkrTLUI+AF3WMeKkEZ9nN2fkBAlcktT6vcZjDFiIhMYEQw==", + "version": "19.3.0", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.3.0.tgz", + "integrity": "sha512-N0rFCuH9YoxG9/m61l9MfpJKfmLOVU0em7ipIz6TRgSSkvReLB9vL85GB+yr8Bs5leqpvg96JSwF4ZS1s4viQg==", "devOptional": true, "license": "MIT", "dependencies": { - "@types/prop-types": "*", - "csstype": "^3.0.2" + "csstype": "^3.2.2" } }, "node_modules/@types/react-dom": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.1.tgz", - "integrity": "sha512-qW1Mfv8taImTthu4KoXgDfLuk4bydU6Q/TkADnDWWHwi4NX4BR+LWfTp2sVmTqRrsHvyDDTelgelxJ+SsejKKQ==", + "version": "19.3.0", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.3.0.tgz", + "integrity": "sha512-ZI7bU42mZXXKHn/qNLEw2IrbiINU7X5+vfgdixBHkCNpYWXjKgfQ/P+uyGb5CjOLB9UcnTeg3rylQtV2hym44Q==", "devOptional": true, "license": "MIT", - "dependencies": { - "@types/react": "*" + "peerDependencies": { + "@types/react": "^19.3.0" } }, "node_modules/@types/trusted-types": { @@ -3273,6 +2392,346 @@ "license": "MIT", "optional": true }, + "node_modules/@typescript/typescript-aix-ppc64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-aix-ppc64/-/typescript-aix-ppc64-7.0.2.tgz", + "integrity": "sha512-MTKKkWB7p/0E9xi1d1tHtZ5PiLkGEMIq88pK2CubZjOsLtYTLqhgIgi6zepFa+9GHZ6h05NMCkQxGKiPXMxXtQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-darwin-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-darwin-arm64/-/typescript-darwin-arm64-7.0.2.tgz", + "integrity": "sha512-gowzar9MwS/aRWp6f3a4KUqzRjAZjOsmGNCM6LcTgXum+dBfgsBVMN+AgvOCCbguXyick6LJhpBszxMebJ8syA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-darwin-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-darwin-x64/-/typescript-darwin-x64-7.0.2.tgz", + "integrity": "sha512-SZ9xZInqApNlNGc9s0W1VSsktYSOe9cFqNOIqmN1Gs8SmkjKZYFt017G4VwPxASInODuAdbTW7sXiFUf893RgA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-freebsd-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-freebsd-arm64/-/typescript-freebsd-arm64-7.0.2.tgz", + "integrity": "sha512-W5NH4y/J0plIIS5b2xvTEkU7JFxyqdMAOgf+Ilhl0vHQXKO5dZoxd+C/jEtq56c4F3wk71RB4BMRQ2XdI+bwYQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-freebsd-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-freebsd-x64/-/typescript-freebsd-x64-7.0.2.tgz", + "integrity": "sha512-UMGDx5sTpzNw3WiPebH7l90IWfJggEd+egHt/q6p7/Cm3zqoV7VxkGXt+3DxPIw8CcmvAB0j3sVVfbhX+M4Tpw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-arm": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-arm/-/typescript-linux-arm-7.0.2.tgz", + "integrity": "sha512-gffT3xPz9sR7j/YJExkyPntrI0P2EP9XbOyWzth2/Gs0RstK+90RBcO0ncXoXy/beYll1SXw846Nf2zdnEz0QQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-arm64/-/typescript-linux-arm64-7.0.2.tgz", + "integrity": "sha512-Qh4eU4/y3yDjnfjjyPYihMj5/ODIlmt+Bzu17OI+fiSRDW57QmU5SiN63exPRNJPKUzcc1INa1NXdrJ+MqHjUQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-loong64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-loong64/-/typescript-linux-loong64-7.0.2.tgz", + "integrity": "sha512-uEHck9i8hoAzXPiYRib1O7miOnz23SxIeVl6F4LXox+qov1K35jHcEW6VHKvZI+pyvl7fZEP4MCU5LYvIq1GuQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-mips64el": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-mips64el/-/typescript-linux-mips64el-7.0.2.tgz", + "integrity": "sha512-R4KvAMnE43W5Qeqb0Ly56O3mWMWIAgsMyz36DCaycd5nbg/9kzm0liw3JocfRqyJY0KPmzFjbswozXyW0DnIYA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-ppc64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-ppc64/-/typescript-linux-ppc64-7.0.2.tgz", + "integrity": "sha512-DORx5b3sd/4S7eayxm4FQv+A7CrkUIGRaHiwI8oiHTAI1fAPWhF4J0vAlkC8biAlHSVVwxMQ3tjZ2/DVbnQiiA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-riscv64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-riscv64/-/typescript-linux-riscv64-7.0.2.tgz", + "integrity": "sha512-wf0jqEDOjrPRnKwYRyyJDRo11KMbvMFrU+q4zqKyChODBzvlkbhNQfKvLxQCcwTpdDaXSHZTVuh0JoCrKCUMHQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-s390x": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-s390x/-/typescript-linux-s390x-7.0.2.tgz", + "integrity": "sha512-IkwJc3L7yhytWd/ewjyxNDfOmswCm9GWMJT/ue/dU4aZNbwZeYAetq42VyLmsmSjvoX7z74X6ZaYCtzAr0EuGw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-x64/-/typescript-linux-x64-7.0.2.tgz", + "integrity": "sha512-EYdf2cNg7rgCWJnxCdJ+F3V39O8ihb37eHAu1LK8oAFizgTQbPOK7zHHXbPt8rX24COqODXeI3sIf0fCXG7H/A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-netbsd-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-netbsd-arm64/-/typescript-netbsd-arm64-7.0.2.tgz", + "integrity": "sha512-+polYF4MF04aPpO5FTkHran9yUQDSXqy5GiSDKpsll5jy3l3+g9QLhpf39T+ePtefhXLOGrLl0QIjkQP6VnelA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-netbsd-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-netbsd-x64/-/typescript-netbsd-x64-7.0.2.tgz", + "integrity": "sha512-8YIT0EHM/3dq10ZOVF/A7pc/YSMtbcecct4rWtexrnSCHOPcpC2KTLXfTCR6vDpnSiY12heNb1GiN/wu+T/FyA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-openbsd-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-openbsd-arm64/-/typescript-openbsd-arm64-7.0.2.tgz", + "integrity": "sha512-APT8+ClYnuYm1u9+kgGXoMj2VzWzcymwh2gNSQVySHfkRDGOTVkoWLjCmOQSaO+PoqQ57B0flRp9SA+7GnnkzQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-openbsd-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-openbsd-x64/-/typescript-openbsd-x64-7.0.2.tgz", + "integrity": "sha512-yX7s+Q0Dln0Dt9tEzZsAjXXR/+ytBM7AlglaqyeMPxQszJ1JhlJdZ6jLA+IzldHtflX81em7lDao1xXu+aRRkg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-sunos-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-sunos-x64/-/typescript-sunos-x64-7.0.2.tgz", + "integrity": "sha512-dLJDGaLZ1D4HPQn62u1n8mBDkJREwMsAkCdkwd4Ieqw+x3TUyTsqY0YiBCtE6H6OzzgGk3iuZ3vFWRS+E8/d1g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-win32-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-win32-arm64/-/typescript-win32-arm64-7.0.2.tgz", + "integrity": "sha512-Gyl1Vy6OsWesLzmq+EP0Fb7b4Nid5232AvcA2SFcdYreldpNtYFFofPjnt62y9hQy7VTaZp65ICJjuAQRaVcIQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-win32-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-win32-x64/-/typescript-win32-x64-7.0.2.tgz", + "integrity": "sha512-0BQ3HkAHHlKLSp1qRvf3SUhGpGsDuhB/jgFw75guyqbxJqEaS0Cw/VFO8i2nHglJUzQCRtMMR/IBAKE3ETMC4g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=16.20.0" + } + }, "node_modules/@upsetjs/venn.js": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@upsetjs/venn.js/-/venn.js-2.0.0.tgz", @@ -3284,52 +2743,35 @@ } }, "node_modules/@vitejs/plugin-react": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.3.4.tgz", - "integrity": "sha512-SCCPBJtYLdE8PX/7ZQAs1QAZ8Jqwih+0VBLum1EGqmCCQal+MIUqLCzj3ZUy8ufbC0cAM4LRlSTm7IQJwWT4ug==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.3.0.tgz", + "integrity": "sha512-H9E955aVvD2F4zNHCw4eIZbIfF6xKldlh7MNu+hSU7xwQzh65lI/N+CJWqmfhi0PEjDXIt/H7T7J/4wU63KJiw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/core": "^7.26.0", - "@babel/plugin-transform-react-jsx-self": "^7.25.9", - "@babel/plugin-transform-react-jsx-source": "^7.25.9", - "@types/babel__core": "^7.20.5", - "react-refresh": "^0.14.2" + "@rolldown/pluginutils": "^1.0.1" }, "engines": { - "node": "^14.18.0 || >=16.0.0" + "node": "^20.19.0 || >=22.12.0" }, "peerDependencies": { - "vite": "^4.2.0 || ^5.0.0 || ^6.0.0" - } - }, - "node_modules/agent-base": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", - "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 14" - } - }, - "node_modules/ansi-colors": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", - "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" + "@rolldown/plugin-babel": "^0.1.7 || ^0.2.0 || ^0.3.0", + "babel-plugin-react-compiler": "^1.0.0", + "oxc-transform-react": ">=0.152.0 <0.157.0", + "vite": "^8.0.0" + }, + "peerDependenciesMeta": { + "@rolldown/plugin-babel": { + "optional": true + }, + "babel-plugin-react-compiler": { + "optional": true + }, + "oxc-transform-react": { + "optional": true + } } }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true, - "license": "Python-2.0" - }, "node_modules/aria-hidden": { "version": "1.2.6", "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz", @@ -3342,98 +2784,6 @@ "node": ">=10" } }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/baseline-browser-mapping": { - "version": "2.11.35", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.35.tgz", - "integrity": "sha512-GNk8KX52CHqeNKGk8+7tZnQab/2k1t/BgrUHPKNdijzpEhF1saPQZHVKb6m5loSAxB39gyrTYw34Qf9CQ3u1qQ==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "baseline-browser-mapping": "dist/cli.cjs" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/brace-expansion": { - "version": "2.1.7", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.7.tgz", - "integrity": "sha512-uZbew1NqdmPDTMJ8ah1y+b+9QEJrfkXFk3RcTQw3X0jW/xRUvFKsg1CfQdSYGdTbXZWExtU3J3ccxtnfw1Fi0g==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/browserslist": { - "version": "4.29.5", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.29.5.tgz", - "integrity": "sha512-khTmKu5NGYTotqcYo8Bew2k4RAE9PuXRSFRXG2lQBrCEQHyeQ/vX6gKMxfokwywBsLiXZMnHsmWMG1pnO8J7uQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "baseline-browser-mapping": "^2.11.33", - "caniuse-lite": "^1.0.30001819", - "electron-to-chromium": "^1.5.464", - "node-releases": "^2.0.60", - "update-browserslist-db": "^1.3.4" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001823", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001823.tgz", - "integrity": "sha512-TQ5s/djDjNk1axreUW+4rULH+BmdCMLiJkhaXnO5wqivG7tITkSUj4ItIdzqdZHKaXcHAV8dhH3JxOM7/7bwqw==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "CC-BY-4.0" - }, - "node_modules/change-case": { - "version": "5.4.4", - "resolved": "https://registry.npmjs.org/change-case/-/change-case-5.4.4.tgz", - "integrity": "sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w==", - "dev": true, - "license": "MIT" - }, "node_modules/chevrotain": { "version": "13.2.0", "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-13.2.0.tgz", @@ -3450,13 +2800,6 @@ "node": ">=22.0.0" } }, - "node_modules/colorette": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz", - "integrity": "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==", - "dev": true, - "license": "MIT" - }, "node_modules/commander": { "version": "15.1.0", "resolved": "https://registry.npmjs.org/commander/-/commander-15.1.0.tgz", @@ -3466,13 +2809,6 @@ "node": ">=22.12.0" } }, - "node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true, - "license": "MIT" - }, "node_modules/cookie": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz", @@ -4017,24 +3353,6 @@ "integrity": "sha512-QDTCU0M0MxR3hQfnlDJfwekQiaanm1ubOD231u73WBckQ/fsamwRLiE2GBz6D3a/xF1NgfiDLJjXBa1hYOYTtQ==", "license": "MIT" }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, "node_modules/delaunator": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.1.0.tgz", @@ -4044,6 +3362,16 @@ "robust-predicates": "^3.0.2" } }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, "node_modules/detect-node-es": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", @@ -4059,18 +3387,11 @@ "@types/trusted-types": "^2.0.7" } }, - "node_modules/electron-to-chromium": { - "version": "1.5.478", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.478.tgz", - "integrity": "sha512-pftG+ma5Lm8O6/p45bhYT6StBN5ziQymaRzmCZwFl8DwWHKPPD93FdOmP1aqftcepolQYvrcyTLa17kE8Yf+jg==", - "dev": true, - "license": "ISC" - }, "node_modules/elkjs": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/elkjs/-/elkjs-0.9.3.tgz", - "integrity": "sha512-f/ZeWvW/BCXbhGEf1Ujp29EASo/lk1FDnETgNKwJrsVvGZhUWCZyg3xLJjAsxfOmt8KjswHmI5EwCQcPMpOYhQ==", - "license": "EPL-2.0" + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/elkjs/-/elkjs-0.12.1.tgz", + "integrity": "sha512-IhMYKHE4S2vtx0QrhBP3lYOIKDeIiJXBrdq9MGYkuB8ZHqhrBnHNfSUndjXFewrX1CPK8chwq+2NA0K0hliYuw==", + "license": "EPL-2.0 OR GPL-3.0-or-later" }, "node_modules/es-toolkit": { "version": "1.53.2", @@ -4084,65 +3405,6 @@ "tests/browser-compat" ] }, - "node_modules/esbuild": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", - "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.12", - "@esbuild/android-arm": "0.25.12", - "@esbuild/android-arm64": "0.25.12", - "@esbuild/android-x64": "0.25.12", - "@esbuild/darwin-arm64": "0.25.12", - "@esbuild/darwin-x64": "0.25.12", - "@esbuild/freebsd-arm64": "0.25.12", - "@esbuild/freebsd-x64": "0.25.12", - "@esbuild/linux-arm": "0.25.12", - "@esbuild/linux-arm64": "0.25.12", - "@esbuild/linux-ia32": "0.25.12", - "@esbuild/linux-loong64": "0.25.12", - "@esbuild/linux-mips64el": "0.25.12", - "@esbuild/linux-ppc64": "0.25.12", - "@esbuild/linux-riscv64": "0.25.12", - "@esbuild/linux-s390x": "0.25.12", - "@esbuild/linux-x64": "0.25.12", - "@esbuild/netbsd-arm64": "0.25.12", - "@esbuild/netbsd-x64": "0.25.12", - "@esbuild/openbsd-arm64": "0.25.12", - "@esbuild/openbsd-x64": "0.25.12", - "@esbuild/openharmony-arm64": "0.25.12", - "@esbuild/sunos-x64": "0.25.12", - "@esbuild/win32-arm64": "0.25.12", - "@esbuild/win32-ia32": "0.25.12", - "@esbuild/win32-x64": "0.25.12" - } - }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true, - "license": "MIT" - }, "node_modules/fdir": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", @@ -4176,16 +3438,6 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/get-nonce": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", @@ -4201,20 +3453,6 @@ "integrity": "sha512-3GKBOn+m2LX9iq+JC1064cSFprJY4jL1jCXTcpnfER5HYE2l/4EfWSGzkPa/ZDBmYI0ZOEj5VHV/eKnPGkHuOg==", "license": "MIT" }, - "node_modules/https-proxy-agent": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", - "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.2", - "debug": "4" - }, - "engines": { - "node": ">= 14" - } - }, "node_modules/iconv-lite": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", @@ -4237,19 +3475,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/index-to-position": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/index-to-position/-/index-to-position-1.2.0.tgz", - "integrity": "sha512-Yg7+ztRkqslMAS2iFaU+Oa4KTSidr63OsFGlOrJoW981kIYO3CGCS3wA95P1mUi/IVSJkn0D479KTJpVpvFNuw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/internmap": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", @@ -4259,140 +3484,313 @@ "node": ">=12" } }, - "node_modules/js-levenshtein": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz", - "integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==", + "node_modules/katex": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/katex/-/katex-0.19.1.tgz", + "integrity": "sha512-jG8uKntjSEcm2EpQOh0XturpPuuC9r3Sq5HLHdsFdWZT27E672SF19QEi+of0/YeOy15lDgRhKvr5614uRrEfA==", + "funding": [ + "https://opencollective.com/katex", + "https://github.com/sponsors/katex" + ], + "license": "MIT", + "dependencies": { + "commander": "^15.0.0" + }, + "bin": { + "katex": "cli.js" + } + }, + "node_modules/khroma": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/khroma/-/khroma-2.1.0.tgz", + "integrity": "sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw==" + }, + "node_modules/layout-base": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/layout-base/-/layout-base-1.0.2.tgz", + "integrity": "sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg==", + "license": "MIT" + }, + "node_modules/lightningcss": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.33.0.tgz", + "integrity": "sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.33.0", + "lightningcss-darwin-arm64": "1.33.0", + "lightningcss-darwin-x64": "1.33.0", + "lightningcss-freebsd-x64": "1.33.0", + "lightningcss-linux-arm-gnueabihf": "1.33.0", + "lightningcss-linux-arm64-gnu": "1.33.0", + "lightningcss-linux-arm64-musl": "1.33.0", + "lightningcss-linux-x64-gnu": "1.33.0", + "lightningcss-linux-x64-musl": "1.33.0", + "lightningcss-win32-arm64-msvc": "1.33.0", + "lightningcss-win32-x64-msvc": "1.33.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.33.0.tgz", + "integrity": "sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.33.0.tgz", + "integrity": "sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.33.0.tgz", + "integrity": "sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.33.0.tgz", + "integrity": "sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.33.0.tgz", + "integrity": "sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.33.0.tgz", + "integrity": "sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "MIT", + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=0.10.0" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "license": "MIT" - }, - "node_modules/js-yaml": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.2.tgz", - "integrity": "sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==", + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.33.0.tgz", + "integrity": "sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==", + "cpu": [ + "arm64" + ], "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/puzrin" - }, - { - "type": "github", - "url": "https://github.com/sponsors/nodeca" - } + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" ], - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" + "engines": { + "node": ">= 12.0.0" }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/jsesc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", - "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.33.0.tgz", + "integrity": "sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==", + "cpu": [ + "x64" + ], "dev": true, - "license": "MIT", - "bin": { - "jsesc": "bin/jsesc" - }, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.33.0.tgz", + "integrity": "sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==", + "cpu": [ + "x64" + ], "dev": true, - "license": "MIT" + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.33.0.tgz", + "integrity": "sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "MIT", - "bin": { - "json5": "lib/cli.js" - }, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=6" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/katex": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/katex/-/katex-0.19.1.tgz", - "integrity": "sha512-jG8uKntjSEcm2EpQOh0XturpPuuC9r3Sq5HLHdsFdWZT27E672SF19QEi+of0/YeOy15lDgRhKvr5614uRrEfA==", - "funding": [ - "https://opencollective.com/katex", - "https://github.com/sponsors/katex" + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.33.0.tgz", + "integrity": "sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==", + "cpu": [ + "x64" ], - "license": "MIT", - "dependencies": { - "commander": "^15.0.0" + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" }, - "bin": { - "katex": "cli.js" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/khroma": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/khroma/-/khroma-2.1.0.tgz", - "integrity": "sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw==" - }, - "node_modules/layout-base": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/layout-base/-/layout-base-1.0.2.tgz", - "integrity": "sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg==", - "license": "MIT" - }, "node_modules/lodash-es": { "version": "4.18.1", "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.18.1.tgz", "integrity": "sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==", "license": "MIT" }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "license": "MIT", - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^3.0.2" - } - }, "node_modules/lucide-react": { - "version": "0.468.0", - "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.468.0.tgz", - "integrity": "sha512-6koYRhnM2N0GGZIdXzSeiNwguv1gt/FAjZOiPl76roBi3xKEXa4WmfpxgQwTTL4KipXjefrnf3oV4IsYhi4JFA==", + "version": "1.71.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-1.71.0.tgz", + "integrity": "sha512-8YtvF+bqT/EMqAXU7kWvYdRu+TV9j4kS1eIS7IbN1j1Z1DgupbrTL0nDIygdqgBDTD7AJPP607VdVgzDTar4zA==", "license": "ISC", "peerDependencies": { - "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc" + "@types/react": "*", + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, "node_modules/marked": { @@ -4408,9 +3806,9 @@ } }, "node_modules/mermaid": { - "version": "12.2.0", - "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-12.2.0.tgz", - "integrity": "sha512-w7nr/SFrLO7BaVTs3dQTvYSV6nYSBj0Yy9DjBhsIJtAcHqRzXSq4Pg32ujHZ/AdWsAMNEvvhbm5dt9E2tOiHzw==", + "version": "12.3.0", + "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-12.3.0.tgz", + "integrity": "sha512-4113TdXeLAsMruJ79OpFL5O8+LTFXhQqZ260rF3tgUmiNAtRm4Uume04I+65PRN6yZ69J4f8rVYWW8zRk65UYw==", "license": "MIT", "dependencies": { "@braintree/sanitize-url": "^7.1.2", @@ -4426,16 +3824,15 @@ "d3-sankey": "^0.12.3", "dagre-d3-es": "7.0.14", "dayjs": "^1.11.21", - "dompurify": "^3.4.12", - "elkjs": "^0.9.3", + "dompurify": "^3.4.17", + "elkjs": "^0.12.0", "es-toolkit": "^1.45.1", "katex": "^0.18.0", "khroma": "^2.1.0", "marked": "^16.3.0", "roughjs": "^4.6.6", "stylis": "^4.3.6", - "ts-dedent": "^2.2.0", - "uuid": "^11.1.0 || ^12 || ^13 || ^14.0.0" + "ts-dedent": "^2.2.0" }, "engines": { "node": ">=22.12.0" @@ -4457,26 +3854,6 @@ "katex": "cli.js" } }, - "node_modules/minimatch": { - "version": "5.1.9", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", - "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, - "license": "MIT" - }, "node_modules/nanoid": { "version": "3.3.20", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.20.tgz", @@ -4496,61 +3873,12 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, - "node_modules/node-releases": { - "version": "2.0.63", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.63.tgz", - "integrity": "sha512-6li2QanLsAXpIH2R6j77MzRyvOyrvdTqlKtO4CgBdHGNvN99ZZfyxszHc5o5+IZBWD5u6Hzwg83JoGXmqZNG9Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/openapi-typescript": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/openapi-typescript/-/openapi-typescript-7.4.4.tgz", - "integrity": "sha512-7j3nktnRzlQdlHnHsrcr6Gqz8f80/RhfA2I8s1clPI+jkY0hLNmnYVKBfuUEli5EEgK1B6M+ibdS5REasPlsUw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@redocly/openapi-core": "^1.25.9", - "ansi-colors": "^4.1.3", - "change-case": "^5.4.4", - "parse-json": "^8.1.0", - "supports-color": "^9.4.0", - "yargs-parser": "^21.1.1" - }, - "bin": { - "openapi-typescript": "bin/cli.js" - }, - "peerDependencies": { - "typescript": "^5.x" - } - }, "node_modules/package-manager-detector": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-1.9.0.tgz", "integrity": "sha512-zAMfbta9nPA8AKkA4WdmNAT8R8s6Dk0/xwPsqNnRidMFcLo1YkLuPDTgs2f64XdzS8vbLNnoJ+uUIkgbz7oRHA==", "license": "MIT" }, - "node_modules/parse-json": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-8.3.0.tgz", - "integrity": "sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.26.2", - "index-to-position": "^1.1.0", - "type-fest": "^4.39.1" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/path-data-parser": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/path-data-parser/-/path-data-parser-0.1.0.tgz", @@ -4578,13 +3906,13 @@ } }, "node_modules/playwright": { - "version": "1.64.1", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.64.1.tgz", - "integrity": "sha512-HCrVhHr5QQuwYoswEUGTb7gGp522yflbv/ST8nF4sFWGuLjQCt17Q/EubpGGSNKYn1tsTCPZxqHhHCfVURu7UA==", + "version": "1.65.0", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.65.0.tgz", + "integrity": "sha512-F3AMWcR44qMBt4kq+6Kb6mX7bjGXshktKFOPULd7reED6ZJWevjbNRqysP7q+AATE9kdPEZBibex1BYsvpVoeA==", "dev": true, "license": "Apache-2.0", "dependencies": { - "playwright-core": "1.64.1" + "playwright-core": "1.65.0" }, "bin": { "playwright": "cli.js" @@ -4594,9 +3922,9 @@ } }, "node_modules/playwright-core": { - "version": "1.64.1", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.64.1.tgz", - "integrity": "sha512-BC4s8y6SEVA6Q1rSxZTto8hI1KUI3xXlHGZgvGqP4IqPdI/a6FX9H29IDNz7vKo9l21b6LfYosScPL6M3xxyDQ==", + "version": "1.65.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.65.0.tgz", + "integrity": "sha512-vNSKgH6YqtN7cdT/L334zo0a+YwkrpicyrHJlWWPIm/Q+Nn2SWInil01oT0mbu96U4GgoRtCYQD9CzJQgju+lA==", "dev": true, "license": "Apache-2.0", "bin": { @@ -4606,16 +3934,6 @@ "node": ">=20" } }, - "node_modules/pluralize": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", - "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, "node_modules/points-on-curve": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/points-on-curve/-/points-on-curve-0.2.0.tgz", @@ -4739,38 +4057,24 @@ } }, "node_modules/react": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", - "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "version": "19.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-19.3.1.tgz", + "integrity": "sha512-QNhWdt7nrgVWWQG58QuGsAR3jv3Hbe4mb4vz7w2csnHavciZJgda1CPNaldF6eVxv90ud3jUXpKlHL69gO38yw==", "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0" - }, "engines": { "node": ">=0.10.0" } }, "node_modules/react-dom": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", - "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "version": "19.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.3.1.tgz", + "integrity": "sha512-Y0bARz53lhEC1NMCASs0/j+faB/zqt3R8hpvg1e8+61ZVJ4UL0UdC4cBbXfZMcIuhrfgeILTLe+ZeBCavQPtKQ==", "license": "MIT", "dependencies": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.2" + "scheduler": "^0.28.0" }, "peerDependencies": { - "react": "^18.3.1" - } - }, - "node_modules/react-refresh": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz", - "integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" + "react": "^19.3.1" } }, "node_modules/react-remove-scroll": { @@ -4880,66 +4184,45 @@ } } }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/robust-predicates": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.3.tgz", "integrity": "sha512-NS3levdsRIUOmiJ8FZWCP7LG3QpJyrs/TE0Zpf1yvZu8cAJJ6QMW92H1c7kWpdIHo8RvmLxN/o2JXTKHp74lUA==", "license": "Unlicense" }, - "node_modules/rollup": { - "version": "4.68.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.68.0.tgz", - "integrity": "sha512-BIHWnc1Qjdy+WLfOdcSd67sxO4iW6pTnhdZosg+7ywSaiMWxxzKldkkNpUJqeXYAiJzyB14P2cIjqC6tlb6xzw==", + "node_modules/rolldown": { + "version": "1.2.19", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.19.tgz", + "integrity": "sha512-QIiV1J9d0pzN4jeeTH4sjPy0AZ6cAy2cG0ExeoE1+U8Rvj+hR3gYkokx0YbeUNGlZqiQJJ2utcETe0oKXwzsuA==", "dev": true, "license": "MIT", "dependencies": { - "@types/estree": "^1.0.10" + "@oxc-project/types": "=0.156.0", + "@rolldown/pluginutils": "^1.0.0" }, "bin": { - "rollup": "dist/bin/rollup" + "rolldown": "bin/cli.mjs" }, "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" + "node": "^20.19.0 || >=22.12.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.68.0", - "@rollup/rollup-android-arm64": "4.68.0", - "@rollup/rollup-android-x64": "4.68.0", - "@rollup/rollup-darwin-arm64": "4.68.0", - "@rollup/rollup-darwin-x64": "4.68.0", - "@rollup/rollup-freebsd-arm64": "4.68.0", - "@rollup/rollup-freebsd-x64": "4.68.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.68.0", - "@rollup/rollup-linux-arm-musleabihf": "4.68.0", - "@rollup/rollup-linux-arm64-gnu": "4.68.0", - "@rollup/rollup-linux-arm64-musl": "4.68.0", - "@rollup/rollup-linux-loong64-gnu": "4.68.0", - "@rollup/rollup-linux-loong64-musl": "4.68.0", - "@rollup/rollup-linux-ppc64-gnu": "4.68.0", - "@rollup/rollup-linux-ppc64-musl": "4.68.0", - "@rollup/rollup-linux-riscv64-gnu": "4.68.0", - "@rollup/rollup-linux-riscv64-musl": "4.68.0", - "@rollup/rollup-linux-s390x-gnu": "4.68.0", - "@rollup/rollup-linux-x64-gnu": "4.68.0", - "@rollup/rollup-linux-x64-musl": "4.68.0", - "@rollup/rollup-openbsd-x64": "4.68.0", - "@rollup/rollup-openharmony-arm64": "4.68.0", - "@rollup/rollup-win32-arm64-msvc": "4.68.0", - "@rollup/rollup-win32-ia32-msvc": "4.68.0", - "@rollup/rollup-win32-x64-gnu": "4.68.0", - "@rollup/rollup-win32-x64-msvc": "4.68.0", - "fsevents": "~2.3.2" + "@rolldown/binding-android-arm-eabi": "1.2.19", + "@rolldown/binding-android-arm64": "1.2.19", + "@rolldown/binding-darwin-arm64": "1.2.19", + "@rolldown/binding-darwin-x64": "1.2.19", + "@rolldown/binding-freebsd-x64": "1.2.19", + "@rolldown/binding-linux-arm-gnueabihf": "1.2.19", + "@rolldown/binding-linux-arm64-gnu": "1.2.19", + "@rolldown/binding-linux-arm64-musl": "1.2.19", + "@rolldown/binding-linux-ppc64-gnu": "1.2.19", + "@rolldown/binding-linux-s390x-gnu": "1.2.19", + "@rolldown/binding-linux-x64-gnu": "1.2.19", + "@rolldown/binding-linux-x64-musl": "1.2.19", + "@rolldown/binding-openharmony-arm64": "1.2.19", + "@rolldown/binding-wasm32-wasi": "1.2.19", + "@rolldown/binding-win32-arm64-msvc": "1.2.19", + "@rolldown/binding-win32-x64-msvc": "1.2.19" } }, "node_modules/roughjs": { @@ -4967,23 +4250,10 @@ "license": "MIT" }, "node_modules/scheduler": { - "version": "0.23.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", - "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0" - } - }, - "node_modules/semver": { - "version": "6.3.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.2.tgz", - "integrity": "sha512-GYrCADwpu6yV5OAvchkQ27Z5wwMxWAEMg5NNWjyHh/5DboFFqbdbvYNIvZouQpxXyeMPoTOh0vdPYKlf0ZswdQ==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.28.0.tgz", + "integrity": "sha512-juorfCmIkIw8tT+p5BXSm6PJjQF/ycEYmKyzURCIt/RaZIhL+PulbQ9Yu2z1HdOJDdqDTlxA1+xKBmHXJsczAw==", + "license": "MIT" }, "node_modules/set-cookie-parser": { "version": "2.7.3", @@ -5007,19 +4277,6 @@ "integrity": "sha512-5Z9ZpRzfuH6l/UAvCPAPUo3665Nk2wLaZU3x+TLHKVzIz33+sbJqbtrYoC3KD4/uVOr2Zp+L0LySezP9OHV9yA==", "license": "MIT" }, - "node_modules/supports-color": { - "version": "9.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-9.4.0.tgz", - "integrity": "sha512-VL+lNrEoIXww1coLPOmiEmK/0sGigko5COxI09KzHc2VJXJsQ37UaQ+8quuxjDeA7+KnLGTWRyOXSLLR2Wb4jw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, "node_modules/tinyexec": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.3.1.tgz", @@ -5061,71 +4318,41 @@ "integrity": "sha512-a4Ux9VKuIMHsOS7ENbEq6hK2ZGYIT27Rtl0E4eD9KqwxhKiQeMZE/9xb3IdYwWaSOyIBQLExhQgXDTYoiCxnWA==", "license": "0BSD" }, - "node_modules/type-fest": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", - "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/typescript": { - "version": "5.6.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", - "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-7.0.2.tgz", + "integrity": "sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA==", "dev": true, "license": "Apache-2.0", "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" + "tsc": "bin/tsc" }, "engines": { - "node": ">=14.17" - } - }, - "node_modules/update-browserslist-db": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.3.4.tgz", - "integrity": "sha512-t8wonIOdQyOjtPd2VktlBu6QjTVTks6v8bSi7kd0r2Vll8TK1JYDZtRRdbmCHOAMphkZgrzK+L+vXK4pyZ8t4A==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "escalade": "^3.2.0", - "picocolors": "^1.1.1" - }, - "bin": { - "update-browserslist-db": "cli.js" + "node": ">=16.20.0" }, - "peerDependencies": { - "browserslist": ">= 4.21.0" + "optionalDependencies": { + "@typescript/typescript-aix-ppc64": "7.0.2", + "@typescript/typescript-darwin-arm64": "7.0.2", + "@typescript/typescript-darwin-x64": "7.0.2", + "@typescript/typescript-freebsd-arm64": "7.0.2", + "@typescript/typescript-freebsd-x64": "7.0.2", + "@typescript/typescript-linux-arm": "7.0.2", + "@typescript/typescript-linux-arm64": "7.0.2", + "@typescript/typescript-linux-loong64": "7.0.2", + "@typescript/typescript-linux-mips64el": "7.0.2", + "@typescript/typescript-linux-ppc64": "7.0.2", + "@typescript/typescript-linux-riscv64": "7.0.2", + "@typescript/typescript-linux-s390x": "7.0.2", + "@typescript/typescript-linux-x64": "7.0.2", + "@typescript/typescript-netbsd-arm64": "7.0.2", + "@typescript/typescript-netbsd-x64": "7.0.2", + "@typescript/typescript-openbsd-arm64": "7.0.2", + "@typescript/typescript-openbsd-x64": "7.0.2", + "@typescript/typescript-sunos-x64": "7.0.2", + "@typescript/typescript-win32-arm64": "7.0.2", + "@typescript/typescript-win32-x64": "7.0.2" } }, - "node_modules/uri-js-replace": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/uri-js-replace/-/uri-js-replace-1.0.2.tgz", - "integrity": "sha512-VeBBt/nMxedczht3KDL2yBBMJqIxpCQLMZp3UJ1otcWwUHdQW4IiyHpJivExzSK+FdxTowRfGL4FmwDqH9+S8Q==", - "dev": true, - "license": "MIT" - }, "node_modules/use-callback-ref": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz", @@ -5169,38 +4396,24 @@ } } }, - "node_modules/uuid": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.1.tgz", - "integrity": "sha512-vIYxrBCC/N/K+Js3qSN88go7kIfNPssr/hHCesKCQNAjmgvYS2oqr69kIufEG+O4+PfezOH4EbIeHCfFov8ZgQ==", - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "license": "MIT", - "bin": { - "uuid": "dist/esm/bin/uuid" - } - }, "node_modules/vite": { - "version": "6.4.5", - "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.5.tgz", - "integrity": "sha512-4enwjFfi4IwtEh0w+jPzpLVOFQiPHmmzPxcHXQOyEur47o6u0jE573DmGpjA+7irXoMLYRZD5ZaFUEneS3abPg==", + "version": "8.3.7", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.3.7.tgz", + "integrity": "sha512-oxh0dMxrayBr33ScJvvBJ2HBQ2jc1TBrXKR2NyL/MJ9WPuX19mN2DXWUmywKdyw5RFVQBo8hmtb2FMC0LHrnng==", "dev": true, "license": "MIT", "dependencies": { - "esbuild": "^0.25.0", - "fdir": "^6.4.4", - "picomatch": "^4.0.2", - "postcss": "^8.5.3", - "rollup": "^4.34.9", - "tinyglobby": "^0.2.13" + "lightningcss": "^1.33.0", + "picomatch": "^4.0.7", + "postcss": "^8.5.32", + "rolldown": "~1.2.18", + "tinyglobby": "^0.2.17" }, "bin": { "vite": "bin/vite.js" }, "engines": { - "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + "node": "^20.19.0 || >=22.12.0" }, "funding": { "url": "https://github.com/vitejs/vite?sponsor=1" @@ -5209,14 +4422,15 @@ "fsevents": "~2.3.3" }, "peerDependencies": { - "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.7.1 || ^0.8.0", + "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", - "less": "*", - "lightningcss": "^1.21.0", - "sass": "*", - "sass-embedded": "*", - "stylus": "*", - "sugarss": "*", + "less": "^4.0.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" @@ -5225,13 +4439,16 @@ "@types/node": { "optional": true }, - "jiti": { + "@vitejs/devtools": { "optional": true }, - "less": { + "esbuild": { + "optional": true + }, + "jiti": { "optional": true }, - "lightningcss": { + "less": { "optional": true }, "sass": { @@ -5256,30 +4473,6 @@ "optional": true } } - }, - "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true, - "license": "ISC" - }, - "node_modules/yaml-ast-parser": { - "version": "0.0.43", - "resolved": "https://registry.npmjs.org/yaml-ast-parser/-/yaml-ast-parser-0.0.43.tgz", - "integrity": "sha512-2PTINUwsRqSd+s8XxKaJWQlUuEMHJQyEuh2edBbW8KNJz0SJPwUSD2zRWqezFEdN7IzAgeuYHFUCF7o8zRdZ0A==", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=12" - } } } } diff --git a/web/package.json b/web/package.json index 775b4f2..f72d4f2 100644 --- a/web/package.json +++ b/web/package.json @@ -7,29 +7,28 @@ "dev": "vite", "build": "tsc -b && vite build", "typecheck": "tsc -b", - "gen:api": "openapi-typescript openapi.json -o src/api/schema.d.ts", + "gen:api": "npm ci --prefix tools/gen-api --no-audit --no-fund --silent && tools/gen-api/node_modules/.bin/openapi-typescript openapi.json -o src/api/schema.d.ts", "e2e": "playwright test" }, "dependencies": { "@fontsource-variable/inter": "5.3.0", "@fontsource/jetbrains-mono": "5.3.0", - "@tanstack/react-query": "5.62.7", - "@tanstack/react-virtual": "3.11.1", + "@tanstack/react-query": "5.107.1", + "@tanstack/react-virtual": "3.14.26", "katex": "^0.19.1", - "lucide-react": "0.468.0", - "mermaid": "12.2.0", + "lucide-react": "1.71.0", + "mermaid": "12.3.0", "radix-ui": "1.8.1", - "react": "18.3.1", - "react-dom": "18.3.1", + "react": "19.3.1", + "react-dom": "19.3.1", "react-router-dom": "7.18.5" }, "devDependencies": { - "@playwright/test": "1.64.1", - "@types/react": "18.3.12", - "@types/react-dom": "18.3.1", - "@vitejs/plugin-react": "4.3.4", - "openapi-typescript": "7.4.4", - "typescript": "5.6.3", - "vite": "6.4.5" + "@playwright/test": "1.65.0", + "@types/react": "19.3.0", + "@types/react-dom": "19.3.0", + "@vitejs/plugin-react": "^6.3.0", + "typescript": "7.0.2", + "vite": "^8.3.7" } } diff --git a/web/src/api/schema.d.ts b/web/src/api/schema.d.ts index 2e170d7..e5acd10 100644 --- a/web/src/api/schema.d.ts +++ b/web/src/api/schema.d.ts @@ -732,8 +732,10 @@ export interface paths { path?: never; cookie?: never; }; - /** One file of a job's artifacts archive (text and a few media types shown, - * anything else downloaded). */ + /** + * One file of a job's artifacts archive (text and a few media types shown, + * anything else downloaded). + */ get: operations["artifact_file"]; put?: never; post?: never; @@ -1156,8 +1158,10 @@ export interface paths { path?: never; cookie?: never; }; - /** How many merge requests are in each state (cheaper than listing them), with - * the list's filters (`state`, `page` and `per_page` are ignored). */ + /** + * How many merge requests are in each state (cheaper than listing them), with + * the list's filters (`state`, `page` and `per_page` are ignored). + */ get: operations["count"]; put?: never; post?: never; @@ -1782,9 +1786,11 @@ export interface paths { path?: never; cookie?: never; }; - /** The last commit of each entry of a directory (a `git log -1 -- ` per + /** + * The last commit of each entry of a directory (a `git log -1 -- ` per * entry, fast with the commit-graph's changed-path filters). Cached per - * commit once complete. */ + * commit once complete. + */ get: operations["last_commits"]; put?: never; post?: never; @@ -1803,8 +1809,10 @@ export interface paths { }; get?: never; put?: never; - /** Signatures of several commits (a commit list): sha → verification; unsigned - * commits are left out. */ + /** + * Signatures of several commits (a commit list): sha → verification; unsigned + * commits are left out. + */ post: operations["signatures"]; delete?: never; options?: never; @@ -2015,9 +2023,11 @@ export interface paths { path?: never; cookie?: never; }; - /** Description templates on the default branch: `merge_request` from + /** + * Description templates on the default branch: `merge_request` from * `.gitlab/merge_request_templates/*.md` (or GitHub's pull request template), - * `issue` from `.gitlab/issue_templates/*.md` (or `.github/ISSUE_TEMPLATE/*.md`). */ + * `issue` from `.gitlab/issue_templates/*.md` (or `.github/ISSUE_TEMPLATE/*.md`). + */ get: operations["templates"]; put?: never; post?: never; @@ -2036,8 +2046,10 @@ export interface paths { }; get?: never; put?: never; - /** Upload a file (multipart, part `file`) to show or link in Markdown, or to attach - * to a release. */ + /** + * Upload a file (multipart, part `file`) to show or link in Markdown, or to attach + * to a release. + */ post: operations["upload"]; delete?: never; options?: never; @@ -2169,8 +2181,10 @@ export interface paths { /** What a signed unsubscribe link is for (changes nothing: link scanners GET). */ get: operations["unsubscribe_info"]; put?: never; - /** One-click unsubscribe (RFC 8058, `List-Unsubscribe-Post`): the link's - * signature is the authorization; the project's emails stop for that person. */ + /** + * One-click unsubscribe (RFC 8058, `List-Unsubscribe-Post`): the link's + * signature is the authorization; the project's emails stop for that person. + */ post: operations["unsubscribe"]; delete?: never; options?: never; @@ -2331,8 +2345,10 @@ export interface paths { path?: never; cookie?: never; }; - /** A user's contribution calendar and recent activity, counting only projects - * the viewer can see. */ + /** + * A user's contribution calendar and recent activity, counting only projects + * the viewer can see. + */ get: operations["contributions"]; put?: never; post?: never; @@ -2385,8 +2401,10 @@ export interface components { /** @enum {string} */ ActionKind: "create" | "update" | "delete" | "move"; Activity: { - /** @description pushed, opened_merge_request, merged_merge_request, opened_issue, - * closed_issue, commented_merge_request, commented_issue, approved */ + /** + * @description pushed, opened_merge_request, merged_merge_request, opened_issue, + * closed_issue, commented_merge_request, commented_issue, approved + */ action: string; /** Format: date-time */ at: string; @@ -2640,7 +2658,7 @@ export interface components { scope?: string; }; AutoMergeBody: { - method?: null | components["schemas"]["MergeMethod"]; + method?: components["schemas"]["MergeMethod"] | null; /** @description Default: the MR's own choice. */ remove_source_branch?: boolean | null; /** @description The source head the user reviewed (from merge_status.head_sha). */ @@ -2699,7 +2717,7 @@ export interface components { image: boolean; kind: components["schemas"]["EntryKind"]; language: string; - lfs?: null | components["schemas"]["LfsInfo"]; + lfs?: components["schemas"]["LfsInfo"] | null; /** @description Highlighted HTML, one entry per line. */ lines: string[]; /** @description Rendered Markdown, for `.md` files. */ @@ -2712,21 +2730,25 @@ export interface components { too_large: boolean; }; BlobScan: { - /** @description False while it runs, or when it stopped at its limits (then the orphans - * are partial too). */ + /** + * @description False while it runs, or when it stopped at its limits (then the orphans + * are partial too). + */ complete: boolean; error?: string | null; /** Format: date-time */ finished_at?: string | null; - /** @description What nothing references, by family (objects older than a day; a dry - * run: nothing is deleted). */ + /** + * @description What nothing references, by family (objects older than a day; a dry + * run: nothing is deleted). + */ orphans: components["schemas"]["OrphanGroup"][]; prefixes: components["schemas"]["PrefixUsage"][]; /** Format: date-time */ started_at: string; }; BranchDto: { - commit?: null | components["schemas"]["CommitSummary"]; + commit?: components["schemas"]["CommitSummary"] | null; default: boolean; name: string; protected: boolean; @@ -2760,8 +2782,10 @@ export interface components { pipeline_status?: string | null; /** Format: int64 */ project_id: number; - /** @description Lands as its own commits rebased onto what is ahead (rebase / - * fast-forward), not a merge commit. */ + /** + * @description Lands as its own commits rebased onto what is ahead (rebase / + * fast-forward), not a merge commit. + */ rebase: boolean; /** @description Deletes the source branch once merged. */ remove_source_branch: boolean; @@ -2966,7 +2990,7 @@ export interface components { visibility?: string; }; CreateImportBody: { - options?: null | components["schemas"]["Options"]; + options?: components["schemas"]["Options"] | null; projects: components["schemas"]["ImportProjectBody"][]; source: string; /** Format: int64 */ @@ -2998,8 +3022,10 @@ export interface components { * @description A milestone of the project. */ milestone_id?: number | null; - /** @description Delete the source branch when the MR merges. Off by default, as in - * GitLab's API (the web form ticks it). */ + /** + * @description Delete the source branch when the MR merges. Off by default, as in + * GitLab's API (the web form ticks it). + */ remove_source_branch?: boolean | null; reviewer_ids?: number[] | null; source_branch: string; @@ -3016,7 +3042,7 @@ export interface components { body: string; /** Format: int64 */ parent_id?: number | null; - position?: null | components["schemas"]["NewPosition"]; + position?: components["schemas"]["NewPosition"] | null; }; CreateProject: { default_branch?: string | null; @@ -3231,7 +3257,7 @@ export interface components { protected: boolean; }; EnvironmentSummary: components["schemas"]["Environment"] & { - last_deployment?: null | components["schemas"]["Deployment"]; + last_deployment?: components["schemas"]["Deployment"] | null; }; /** @description Projects with open critical or high findings on their default branch. */ ExposedProject: { @@ -3369,7 +3395,7 @@ export interface components { can_admin: boolean; can_create_project: boolean; can_create_subgroup: boolean; - policy?: null | components["schemas"]["OrgPolicyDto"]; + policy?: components["schemas"]["OrgPolicyDto"] | null; }; GroupDto: { /** @description The avatar's URL (versioned), when it has one. */ @@ -3451,8 +3477,10 @@ export interface components { HookBody: { /** @description push, merge_request, note, release, pipeline, build */ events: string[]; - /** @description `generic` (default: the JSON payload) or a chat app: `slack`, - * `mattermost`, `discord`, `matrix`, `teams`. */ + /** + * @description `generic` (default: the JSON payload) or a chat app: `slack`, + * `mattermost`, `discord`, `matrix`, `teams`. + */ format?: string | null; secret?: string | null; url: string; @@ -3685,13 +3713,13 @@ export interface components { coverage?: number | null; /** Format: date-time */ created_at: string; - downstream?: null | components["schemas"]["PipelineLink"]; + downstream?: components["schemas"]["PipelineLink"] | null; /** * Format: double * @description Seconds spent running (so far, while running). */ duration?: number | null; - environment?: null | components["schemas"]["JobEnvironment"]; + environment?: components["schemas"]["JobEnvironment"] | null; /** Format: int32 */ exit_code?: number | null; failure_reason?: string | null; @@ -3850,7 +3878,7 @@ export interface components { }; LoginResponse: { challenge?: string | null; - session?: null | components["schemas"]["SessionInfo"]; + session?: components["schemas"]["SessionInfo"] | null; two_factor_required: boolean; }; LookupBody: { @@ -3942,7 +3970,7 @@ export interface components { }; MergeRequestBody: { message?: string | null; - method?: null | components["schemas"]["MergeMethod"]; + method?: components["schemas"]["MergeMethod"] | null; /** @description Default: the MR's own choice (`remove_source_branch`). */ remove_source_branch?: boolean | null; /** @description The source head the user reviewed (from merge_status.head_sha). */ @@ -4024,14 +4052,14 @@ export interface components { approvals: components["schemas"]["Approval"][]; approved_by_me: boolean; assignees: components["schemas"]["UserBrief"][]; - auto_merge_user?: null | components["schemas"]["UserBrief"]; + auto_merge_user?: components["schemas"]["UserBrief"] | null; can_approve: boolean; can_edit: boolean; /** @description Sanitized HTML of the description (Markdown). */ description_html: string; labels: components["schemas"]["Label"][]; reviewers: components["schemas"]["Reviewer"][]; - stack?: null | components["schemas"]["StackView"]; + stack?: components["schemas"]["StackView"] | null; /** @description Newest first. */ versions: components["schemas"]["MrDiff"][]; }; @@ -4058,7 +4086,7 @@ export interface components { assignees: components["schemas"]["UserBrief"][]; labels: components["schemas"]["Label"][]; reviewers: components["schemas"]["Reviewer"][]; - stack?: null | components["schemas"]["StackBadge"]; + stack?: components["schemas"]["StackBadge"] | null; }; /** @description What a merge request's pipeline finds, against the default branch. */ MrSecurity: { @@ -4080,7 +4108,7 @@ export interface components { report_types: string[]; }; MrTests: { - base?: null | components["schemas"]["Totals"]; + base?: components["schemas"]["Totals"] | null; /** * Format: int64 * @description The target branch's latest finished pipeline with test reports. @@ -4088,7 +4116,7 @@ export interface components { base_pipeline_iid?: number | null; /** @description Failing here and on the target branch. */ existing_failures: components["schemas"]["ComparedFailure"][]; - head?: null | components["schemas"]["Totals"]; + head?: components["schemas"]["Totals"] | null; /** * Format: int64 * @description The merge request's head pipeline with test reports. @@ -4220,7 +4248,7 @@ export interface components { /** @description Sanitized HTML of the body (Markdown). */ body_html: string; outdated: boolean; - position?: null | components["schemas"]["MappedPosition"]; + position?: components["schemas"]["MappedPosition"] | null; /** * Format: int32 * @description Version the comment was written on. @@ -4263,11 +4291,13 @@ export interface components { OrphanGroup: { /** Format: int64 */ bytes: number; - /** @description `lfs` (no LFS record), `lfs_unused` (a record no project uses), `registry` + /** + * @description `lfs` (no LFS record), `lfs_unused` (a record no project uses), `registry` * (no blob record), `registry_uploads` (no upload in progress), `ci` (no * artifact or log record), `uploads`, `avatars` (of a deleted user, project * or group), `tmp` (interrupted writes), or `unrecognized` (keys Forgust does - * not write: listed, never called orphans). */ + * not write: listed, never called orphans). + */ family: string; /** Format: int64 */ objects: number; @@ -4310,7 +4340,7 @@ export interface components { }; /** @description The project's Pages site. */ PagesInfo: { - deployment?: null | components["schemas"]["PagesDeployment"]; + deployment?: components["schemas"]["PagesDeployment"] | null; /** @description The instance serves sites (`pages.domain` is set). */ enabled: boolean; /** @description Only public projects' sites are served. */ @@ -4319,7 +4349,7 @@ export interface components { url?: string | null; }; PathCommit: { - commit?: null | components["schemas"]["CommitInfo"]; + commit?: components["schemas"]["CommitInfo"] | null; path: string; }; Person: { @@ -4390,7 +4420,7 @@ export interface components { jobs: components["schemas"]["JobDto"][]; /** @description Stage names in order (only stages that have jobs). */ stages: string[]; - upstream?: null | components["schemas"]["PipelineLink"]; + upstream?: components["schemas"]["PipelineLink"] | null; }; PipelineLink: { /** Format: int64 */ @@ -4450,8 +4480,10 @@ export interface components { ProjectCiSettings: { /** @description Cancel older pipelines of a branch when a new commit's pipeline starts. */ auto_cancel_redundant: boolean; - /** @description Merge check: no new critical or high security finding left - * undismissed. */ + /** + * @description Merge check: no new critical or high security finding left + * undismissed. + */ block_new_security_findings: boolean; ci_config_path: string; /** Format: int32 */ @@ -4460,8 +4492,10 @@ export interface components { default_timeout_secs: number; instance_runners_enabled: boolean; job_token_scope_enabled: boolean; - /** @description Merge requests merge through a merge train (each tested on the merge - * of everything ahead of it). */ + /** + * @description Merge requests merge through a merge train (each tested on the merge + * of everything ahead of it). + */ merge_trains_enabled: boolean; only_merge_if_pipeline_succeeds: boolean; /** Format: int64 */ @@ -4477,7 +4511,7 @@ export interface components { empty_repo: boolean; /** @description Older paths that still redirect here. */ redirects: string[]; - storage_warning?: null | components["schemas"]["Warning"]; + storage_warning?: components["schemas"]["Warning"] | null; }; ProjectDto: { /** @description Read-only since then (its Owner can unarchive it). */ @@ -4540,8 +4574,8 @@ export interface components { }; /** @description What a project keeps, against its quotas. */ ProjectStorageUse: components["schemas"]["StorageUse"] & { - namespace?: null | components["schemas"]["QuotaUse"]; - quota?: null | components["schemas"]["QuotaUse"]; + namespace?: components["schemas"]["QuotaUse"] | null; + quota?: components["schemas"]["QuotaUse"] | null; /** Format: int64 */ repository_bytes: number; /** Format: int64 */ @@ -4550,8 +4584,10 @@ export interface components { ProtectBranch: { allow_deploy_keys?: boolean; allow_force_push?: boolean; - /** @description Merge requests into it need an approval from the code owners of the - * files they change (`CODEOWNERS`). */ + /** + * @description Merge requests into it need an approval from the code owners of the + * files they change (`CODEOWNERS`). + */ code_owner_approval_required?: boolean; merge_access_level?: string; /** @description Branch name or glob, e.g. `release/*`. */ @@ -4709,7 +4745,7 @@ export interface components { updated_at: string; }; ReleaseDto: components["schemas"]["Release"] & { - commit?: null | components["schemas"]["CommitBrief"]; + commit?: components["schemas"]["CommitBrief"] | null; description_html: string; links: components["schemas"]["LinkDto"][]; sources: components["schemas"]["Source"][]; @@ -4764,11 +4800,13 @@ export interface components { * @description Hours between runs (1 to 168). */ interval_hours: number; - last_run?: null | components["schemas"]["RenovateRun"]; + last_run?: components["schemas"]["RenovateRun"] | null; /** Format: date-time */ next_run_at?: string | null; - /** @description Renovate opens an onboarding merge request first; false: it runs with - * its defaults, no config file needed. */ + /** + * @description Renovate opens an onboarding merge request first; false: it runs with + * its defaults, no config file needed. + */ onboarding: boolean; }; RepoStats: { @@ -5058,10 +5096,12 @@ export interface components { */ last_scan_pipeline_iid?: number | null; }; - /** @description Built-in security scanners (ADR-0024): projects turn them on and + /** + * @description Built-in security scanners (ADR-0024): projects turn them on and * Forgust runs them as CI jobs on the instance's runners. Administrators * change these in Admin > Security scanning (stored over this). Config - * section `[security_scanning]`. */ + * section `[security_scanning]`. + */ SecurityScanningConfig: { /** @default true */ enabled: boolean; @@ -5101,7 +5141,7 @@ export interface components { SessionInfo: { /** @description Send back as `X-CSRF-Token` on POST/PUT/DELETE. */ csrf_token: string; - impersonator?: null | components["schemas"]["UserDto"]; + impersonator?: components["schemas"]["UserDto"] | null; user: components["schemas"]["UserDto"]; }; SetQuota: { @@ -5281,7 +5321,7 @@ export interface components { * @description Repositories not measured yet (sizes refresh after pushes and hourly). */ repositories_unmeasured: number; - scan?: null | components["schemas"]["BlobScan"]; + scan?: components["schemas"]["BlobScan"] | null; /** Format: int64 */ total: number; }; @@ -5313,7 +5353,7 @@ export interface components { }; TagDto: { annotated: boolean; - commit?: null | components["schemas"]["CommitSummary"]; + commit?: components["schemas"]["CommitSummary"] | null; name: string; /** @description A protected tag rule matches it. */ protected: boolean; @@ -5417,8 +5457,10 @@ export interface components { }; TotpCode: { code: string; - /** @description The account's password: a borrowed session must not be able to put its - * own second factor on the account. */ + /** + * @description The account's password: a borrowed session must not be able to put its + * own second factor on the account. + */ password?: string; }; TotpDisable: { @@ -5437,8 +5479,10 @@ export interface components { complete: boolean; /** @description Log text from `offset` (raw bytes as UTF-8, invalid sequences replaced). */ content: string; - /** @description More bytes are there already: read again from `size` (a log is sent in - * pieces of at most 1 MB). */ + /** + * @description More bytes are there already: read again from `size` (a log is sent in + * pieces of at most 1 MB). + */ more: boolean; /** * Format: int64 @@ -5472,7 +5516,7 @@ export interface components { TreeResponse: { commit: string; entries: components["schemas"]["TreeEntry"][]; - last_commit?: null | components["schemas"]["CommitInfo"]; + last_commit?: components["schemas"]["CommitInfo"] | null; path: string; }; Unsubscription: { @@ -5503,8 +5547,10 @@ export interface components { title?: string | null; }; UpdateMe: { - /** @description Needed to change the email address (a borrowed session must not be - * able to move the account to another inbox). */ + /** + * @description Needed to change the email address (a borrowed session must not be + * able to move the account to another inbox). + */ current_password?: string; email: string; name: string; @@ -5572,8 +5618,10 @@ export interface components { /** Format: date-time */ created_at: string; email?: string | null; - /** @description Shown with the email: whether it is confirmed, and a new address - * waiting for its confirmation link. */ + /** + * @description Shown with the email: whether it is confirmed, and a new address + * waiting for its confirmation link. + */ email_verified?: boolean | null; /** Format: int64 */ id: number; @@ -5619,9 +5667,11 @@ export interface components { signature_type: string; /** @description The key owner's username, when the key is registered. */ signer?: string | null; - /** @description `verified`; `unverified` (good signature, but the committer email is not + /** + * @description `verified`; `unverified` (good signature, but the committer email is not * the key owner's confirmed address); `unknown_key` (no user registered - * the key); `bad_signature`; `unsupported` (X.509). */ + * the key); `bad_signature`; `unsupported` (X.509). + */ verification_status: string; }; /** @description How full a project or its namespace was when last measured (the fuller one). */ @@ -5641,8 +5691,10 @@ export interface components { created_at: string; enabled: boolean; events: string[]; - /** @description `generic` (the JSON payload), or a chat app: `slack`, `mattermost`, - * `discord`, `matrix`, `teams`. */ + /** + * @description `generic` (the JSON payload), or a chat app: `slack`, `mattermost`, + * `discord`, `matrix`, `teams`. + */ format: string; /** Format: int64 */ id: number; diff --git a/web/src/components/Contributions.tsx b/web/src/components/Contributions.tsx index f1da8c0..e0e6bed 100644 --- a/web/src/components/Contributions.tsx +++ b/web/src/components/Contributions.tsx @@ -1,4 +1,4 @@ -import { useEffect, useMemo, useRef } from "react"; +import { useEffect, useMemo, useRef, type ReactElement } from "react"; import { Link } from "react-router-dom"; import { useQuery } from "@tanstack/react-query"; import { CircleDot, GitCommitHorizontal, GitMerge, MessageSquare, ThumbsUp } from "lucide-react"; @@ -102,7 +102,7 @@ export function ContributionCalendar({ days }: { days: S["Day"][] }) { ); } -const ACTIVITY: Record = { +const ACTIVITY: Record = { pushed: { icon: , verb: "pushed to" }, opened_merge_request: { icon: , verb: "opened" }, merged_merge_request: { icon: , verb: "merged" }, diff --git a/web/src/components/HoverCards.tsx b/web/src/components/HoverCards.tsx index 1681a5b..e70d3de 100644 --- a/web/src/components/HoverCards.tsx +++ b/web/src/components/HoverCards.tsx @@ -73,7 +73,7 @@ function Tip({ text, rect }: { text: string; rect: DOMRect }) { */ function useTips() { const [tip, setTip] = useState<{ text: string; rect: DOMRect } | null>(null); - const t = useRef(); + const t = useRef(undefined); useEffect(() => { const enter = (e: Event) => { const el = (e.target as Element | null)?.closest?.("[title], [data-title]") as HTMLElement | SVGElement | null; @@ -132,8 +132,8 @@ function useTips() { export function HoverCards() { const tip = useTips(); const [card, setCard] = useState<{ target: Target; rect: DOMRect; anchor: HTMLAnchorElement } | null>(null); - const showT = useRef(); - const hideT = useRef(); + const showT = useRef(undefined); + const hideT = useRef(undefined); const over = useRef(false); useEffect(() => { @@ -161,13 +161,17 @@ export function HoverCards() { clearTimeout(showT.current); setCard(null); }; + // a scroll moves an open card off its link, so it goes; a card about to show + // stays pending (scrolling a link under a still pointer, or into view first), + // and reads the link's position when it shows + const scrolled = () => setCard(null); const key = (e: KeyboardEvent) => e.key === "Escape" && close(); document.addEventListener("mouseover", enter); document.addEventListener("mouseout", leave); document.addEventListener("focusin", enter); document.addEventListener("focusout", leave); document.addEventListener("keydown", key); - window.addEventListener("scroll", close, true); + window.addEventListener("scroll", scrolled, true); window.addEventListener("popstate", close); return () => { document.removeEventListener("mouseover", enter); @@ -175,7 +179,7 @@ export function HoverCards() { document.removeEventListener("focusin", enter); document.removeEventListener("focusout", leave); document.removeEventListener("keydown", key); - window.removeEventListener("scroll", close, true); + window.removeEventListener("scroll", scrolled, true); window.removeEventListener("popstate", close); }; }, []); diff --git a/web/src/components/hscroll.tsx b/web/src/components/hscroll.tsx index 307b427..fef8c13 100644 --- a/web/src/components/hscroll.tsx +++ b/web/src/components/hscroll.tsx @@ -71,7 +71,7 @@ export function remeasure(v: { measure: () => void; getVirtualItems: () => unkno } /** The element's content width, kept up to date. */ -export function useWidth(ref: RefObject): number { +export function useWidth(ref: RefObject): number { const [w, setW] = useState(0); useLayoutEffect(() => { const el = ref.current; @@ -97,7 +97,7 @@ export type HScroll = { * every bar. Gestures: trackpad / shift+wheel and swipes over a row, its * bars, and dragging a text selection past either edge of the code. */ -export function useHScroll(scope: RefObject, ranges: number[]): HScroll { +export function useHScroll(scope: RefObject, ranges: number[]): HScroll { const xs = useRef(new Map()); const rs = useRef(ranges); rs.current = ranges; diff --git a/web/src/main.tsx b/web/src/main.tsx index aae8506..926da87 100644 --- a/web/src/main.tsx +++ b/web/src/main.tsx @@ -2,7 +2,7 @@ import "@fontsource-variable/inter"; import "@fontsource/jetbrains-mono/400.css"; import "@fontsource/jetbrains-mono/500.css"; import "@fontsource/jetbrains-mono/600.css"; -import { StrictMode, Suspense, lazy } from "react"; +import { StrictMode, Suspense, lazy, type ReactElement } from "react"; import { createRoot } from "react-dom/client"; import { BrowserRouter, Navigate, Route, Routes, useLocation } from "react-router-dom"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; @@ -39,7 +39,7 @@ const queryClient = new QueryClient({ }, }); -function RequireUser({ children }: { children: JSX.Element }) { +function RequireUser({ children }: { children: ReactElement }) { const { user, loading } = useSession(); const loc = useLocation(); if (loading) return ; diff --git a/web/src/pages/Dashboard.tsx b/web/src/pages/Dashboard.tsx index eb1818d..32f3f32 100644 --- a/web/src/pages/Dashboard.tsx +++ b/web/src/pages/Dashboard.tsx @@ -1,4 +1,4 @@ -import { useState } from "react"; +import { useState, type ReactElement } from "react"; import { Link } from "react-router-dom"; import { useQuery } from "@tanstack/react-query"; import { Globe, Lock, Shield } from "lucide-react"; @@ -6,7 +6,7 @@ import { api, qs, timeAgo, type S } from "../api/client"; import { Empty, FilterTabs, ListHead, Q, SearchField, Tile, useDebounced } from "../components/ui"; import { useGroups, usePrefetch } from "../prefetch"; -const VIS_ICON: Record = { +const VIS_ICON: Record = { private: , internal: , public: , diff --git a/web/src/pages/Work.tsx b/web/src/pages/Work.tsx index d030d59..15a3ac2 100644 --- a/web/src/pages/Work.tsx +++ b/web/src/pages/Work.tsx @@ -1,4 +1,4 @@ -import { useState } from "react"; +import { useState, type ReactNode, type ReactElement } from "react"; import { Link } from "react-router-dom"; import { useQuery, useQueryClient } from "@tanstack/react-query"; import { AtSign, Check, CircleDot, Eye, GitMerge, UserCheck } from "lucide-react"; @@ -10,7 +10,7 @@ import { useWork } from "../prefetch"; type Tab = "todos" | "reviews" | "mrs" | "issues"; -const ACTION: Record = { +const ACTION: Record = { assigned: { icon: , text: "assigned you" }, review_requested: { icon: , text: "asked you to review" }, mentioned: { icon: , text: "mentioned you" }, @@ -110,7 +110,38 @@ function Todos() { ); } -function MrRows({ list, empty, review }: { list: S["WorkMr"][]; empty: string; review?: boolean }) { +/** A review request still waiting for you (no state yet counts as waiting): the + * tab's count and the first section use this one rule. */ +const isWaiting = (m: S["WorkMr"]) => !m.review_state || m.review_state === "unreviewed"; + +function ListSection({ title, children }: { title: string; children: ReactNode }) { + return ( +
+

{title}

+ {children} +
+ ); +} + +/** Review requests, those still waiting for you first. */ +function ReviewRequests({ list }: { list: S["WorkMr"][] }) { + if (list.length === 0) return No review requests. When someone asks you to review a merge request, it shows up here.; + const reviewed = list.filter((m) => !isWaiting(m)); + return ( +
+ + + + {reviewed.length > 0 && ( + + + + )} +
+ ); +} + +function MrRows({ list, empty, review }: { list: S["WorkMr"][]; empty?: string; review?: boolean }) { if (list.length === 0) return {empty}; return (
@@ -131,7 +162,7 @@ function MrRows({ list, empty, review }: { list: S["WorkMr"][]; empty: string; r {m.project_path}!{m.iid} by {m.author_username ? : "ghost"} - {review && m.review_state && {REVIEW_TEXT[m.review_state] ?? m.review_state}} + {review && m.review_state && {REVIEW_TEXT[m.review_state] ?? m.review_state}}
@@ -148,7 +179,6 @@ export function Work() { const w = useWork(); const [tab, setTab] = useState("todos"); const d = w.data; - const waiting = d?.review_requests.filter((m) => m.review_state === "unreviewed").length; return (
@@ -158,7 +188,7 @@ export function Work() { onChange={setTab} options={[ { value: "todos", label: "To-do", count: d?.todos_pending }, - { value: "reviews", label: "Review requests", count: waiting }, + { value: "reviews", label: "Review requests", count: d?.review_requests.filter(isWaiting).length }, { value: "mrs", label: "Merge requests", count: d ? d.assigned_merge_requests.length + d.your_merge_requests.length : undefined }, { value: "issues", label: "Issues", count: d?.assigned_issues.length }, ]} @@ -169,17 +199,15 @@ export function Work() { {(d) => tab === "reviews" ? ( - + ) : tab === "mrs" ? (
-
-

Assigned to you

+ -
-
-

Opened by you

+ + -
+
) : d.assigned_issues.length === 0 ? ( No open issue is assigned to you. diff --git a/web/src/pages/project/Code.tsx b/web/src/pages/project/Code.tsx index c853168..9b14426 100644 --- a/web/src/pages/project/Code.tsx +++ b/web/src/pages/project/Code.tsx @@ -1,4 +1,4 @@ -import { useEffect, useMemo, useRef, useState } from "react"; +import { useEffect, useMemo, useRef, useState, type ReactElement } from "react"; import { Link, useLocation, useNavigate } from "react-router-dom"; import { useQuery } from "@tanstack/react-query"; import { useWindowVirtualizer } from "@tanstack/react-virtual"; @@ -130,7 +130,7 @@ export function PathCrumbs({ ctx, gitRef, path }: { ctx: Ctx; gitRef: string; pa ); } -const ICONS: Record = { +const ICONS: Record = { tree: , blob: , executable: , diff --git a/web/src/shell/palette.tsx b/web/src/shell/palette.tsx index 3f09242..6cc8ed9 100644 --- a/web/src/shell/palette.tsx +++ b/web/src/shell/palette.tsx @@ -1,4 +1,4 @@ -import { useEffect, useMemo, useRef, useState } from "react"; +import { useEffect, useMemo, useRef, useState, type ReactElement } from "react"; import { createPortal } from "react-dom"; import { useNavigate } from "react-router-dom"; import { useQuery } from "@tanstack/react-query"; @@ -65,7 +65,7 @@ export function openPalette(mode: Mode = "all") { window.dispatchEvent(new CustomEvent(OPEN, { detail: mode })); } -type Entry = { key: string; label: string; hint?: string; icon: JSX.Element; to: string }; +type Entry = { key: string; label: string; hint?: string; icon: ReactElement; to: string }; /** Subsequence match, scored so contiguous and basename hits rank first. */ function fuzzy(needle: string, hay: string): number { diff --git a/web/tools/gen-api/package-lock.json b/web/tools/gen-api/package-lock.json new file mode 100644 index 0000000..c8ae537 --- /dev/null +++ b/web/tools/gen-api/package-lock.json @@ -0,0 +1,392 @@ +{ + "name": "forgust-gen-api", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "forgust-gen-api", + "devDependencies": { + "openapi-typescript": "7.13.0", + "typescript": "6.0.3" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@redocly/ajv": { + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/@redocly/ajv/-/ajv-8.11.2.tgz", + "integrity": "sha512-io1JpnwtIcvojV7QKDUSIuMN/ikdOUd1ReEnUnMKGfDVridQZ31J0MmIuqwuRjWDZfmvr+Q0MqCcfHM2gTivOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js-replace": "^1.0.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@redocly/config": { + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@redocly/config/-/config-0.22.0.tgz", + "integrity": "sha512-gAy93Ddo01Z3bHuVdPWfCwzgfaYgMdaZPcfL7JZ7hWJoK9V0lXDbigTWkhiPFAaLWzbOJ+kbUQG1+XwIm0KRGQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@redocly/openapi-core": { + "version": "1.34.24", + "resolved": "https://registry.npmjs.org/@redocly/openapi-core/-/openapi-core-1.34.24.tgz", + "integrity": "sha512-jDFMu4zirFVOF9nEWCT31s7OzzVhkxZkb4lO3yZhkdPXAOspLo10ED9thVgm6gtI0dJBTLa+mNP0IYeZpVSYGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@redocly/ajv": "8.11.2", + "@redocly/config": "0.22.0", + "colorette": "1.4.0", + "https-proxy-agent": "7.0.6", + "js-levenshtein": "1.1.6", + "js-yaml": "4.3.2", + "minimatch": "5.1.9", + "pluralize": "8.0.0", + "yaml-ast-parser": "0.0.43" + }, + "engines": { + "node": ">=18.17.0", + "npm": ">=9.5.0" + } + }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.8.tgz", + "integrity": "sha512-BnlDzDYQoplTsZSvPi86CNzmbcb07X8ufR8fk1zivaiEJlXJkiq1MQyDCVmlWcsWbj6aWXqHnrwwevbrm/Saig==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/change-case": { + "version": "5.4.4", + "resolved": "https://registry.npmjs.org/change-case/-/change-case-5.4.4.tgz", + "integrity": "sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/colorette": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz", + "integrity": "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==", + "dev": true, + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/index-to-position": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/index-to-position/-/index-to-position-1.2.0.tgz", + "integrity": "sha512-Yg7+ztRkqslMAS2iFaU+Oa4KTSidr63OsFGlOrJoW981kIYO3CGCS3wA95P1mUi/IVSJkn0D479KTJpVpvFNuw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/js-levenshtein": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz", + "integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.2.tgz", + "integrity": "sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/minimatch": { + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", + "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/openapi-typescript": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/openapi-typescript/-/openapi-typescript-7.13.0.tgz", + "integrity": "sha512-EFP392gcqXS7ntPvbhBzbF8TyBA+baIYEm791Hy5YkjDYKTnk/Tn5OQeKm5BIZvJihpp8Zzr4hzx0Irde1LNGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@redocly/openapi-core": "^1.34.6", + "ansi-colors": "^4.1.3", + "change-case": "^5.4.4", + "parse-json": "^8.3.0", + "supports-color": "^10.2.2", + "yargs-parser": "^21.1.1" + }, + "bin": { + "openapi-typescript": "bin/cli.js" + }, + "peerDependencies": { + "typescript": "^5.x" + } + }, + "node_modules/parse-json": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-8.3.0.tgz", + "integrity": "sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.26.2", + "index-to-position": "^1.1.0", + "type-fest": "^4.39.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/pluralize": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", + "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/supports-color": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-10.2.2.tgz", + "integrity": "sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/type-fest": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", + "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/uri-js-replace": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/uri-js-replace/-/uri-js-replace-1.0.2.tgz", + "integrity": "sha512-VeBBt/nMxedczht3KDL2yBBMJqIxpCQLMZp3UJ1otcWwUHdQW4IiyHpJivExzSK+FdxTowRfGL4FmwDqH9+S8Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/yaml-ast-parser": { + "version": "0.0.43", + "resolved": "https://registry.npmjs.org/yaml-ast-parser/-/yaml-ast-parser-0.0.43.tgz", + "integrity": "sha512-2PTINUwsRqSd+s8XxKaJWQlUuEMHJQyEuh2edBbW8KNJz0SJPwUSD2zRWqezFEdN7IzAgeuYHFUCF7o8zRdZ0A==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + } + } +} diff --git a/web/tools/gen-api/package.json b/web/tools/gen-api/package.json new file mode 100644 index 0000000..4f21e3a --- /dev/null +++ b/web/tools/gen-api/package.json @@ -0,0 +1,14 @@ +{ + "name": "forgust-gen-api", + "private": true, + "description": "openapi-typescript for `npm run gen:api`, on its own: it needs TypeScript's JavaScript API, which TypeScript 7 (the project's compiler) no longer has", + "devDependencies": { + "openapi-typescript": "7.13.0", + "typescript": "6.0.3" + }, + "overrides": { + "openapi-typescript": { + "typescript": "$typescript" + } + } +}