From d5a2d3b26b4662baa7274f82f8b61ca683049a4f Mon Sep 17 00:00:00 2001 From: Danny Avila Date: Mon, 1 Jun 2026 08:43:32 -0400 Subject: [PATCH 01/14] =?UTF-8?q?=F0=9F=8F=B7=EF=B8=8F=20ci:=20Sync=20Helm?= =?UTF-8?q?=20Chart=20Tags=20(#13446)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ci: Sync Helm chart tags * ci: Address Helm tag sync review --- .github/scripts/sync-helm-chart-tags.sh | 232 +++++++++++++++++++++ .github/workflows/helmcharts.yml | 54 +++-- .github/workflows/sync-helm-chart-tags.yml | 73 +++++++ 3 files changed, 342 insertions(+), 17 deletions(-) create mode 100755 .github/scripts/sync-helm-chart-tags.sh create mode 100644 .github/workflows/sync-helm-chart-tags.yml diff --git a/.github/scripts/sync-helm-chart-tags.sh b/.github/scripts/sync-helm-chart-tags.sh new file mode 100755 index 000000000000..518fe1eb61b9 --- /dev/null +++ b/.github/scripts/sync-helm-chart-tags.sh @@ -0,0 +1,232 @@ +#!/usr/bin/env bash +set -euo pipefail + +CHART_PATH="${CHART_PATH:-helm/librechat/Chart.yaml}" +DEFAULT_BRANCH="${DEFAULT_BRANCH:-main}" +BASE_REF="${BASE_REF:-refs/remotes/origin/${DEFAULT_BRANCH}}" +BACKFILL_FROM_VERSION="${BACKFILL_FROM_VERSION:-1.9.0}" +PUSH_TAGS="${PUSH_TAGS:-false}" +TAG_PREFIX="${TAG_PREFIX:-chart-}" +GITHUB_SERVER_URL="${GITHUB_SERVER_URL:-https://github.com}" +DISPATCH_WORKFLOW="${DISPATCH_WORKFLOW:-}" +RELEASE_EXISTING_TAG="${RELEASE_EXISTING_TAG:-}" +SEMVER_REGEX='^(0|[1-9][0-9]*)[.](0|[1-9][0-9]*)[.](0|[1-9][0-9]*)(-[0-9A-Za-z-]+([.][0-9A-Za-z-]+)*)?([+][0-9A-Za-z-]+([.][0-9A-Za-z-]+)*)?$' + +fail() { + printf '::error::%s\n' "$1" >&2 + exit 1 +} + +git_with_auth() { + if [ -n "${GITHUB_TOKEN:-}" ]; then + git -c "http.${GITHUB_SERVER_URL}/.extraheader=AUTHORIZATION: bearer ${GITHUB_TOKEN}" "$@" + return + fi + + git "$@" +} + +dispatch_release() { + tag="$1" + + if [ -z "$DISPATCH_WORKFLOW" ]; then + return + fi + + if [ -z "${GITHUB_REPOSITORY:-}" ]; then + fail "GITHUB_REPOSITORY is required to dispatch ${DISPATCH_WORKFLOW}" + fi + + if [[ ! "$GITHUB_REPOSITORY" =~ ^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$ ]]; then + fail "Unexpected repository name: ${GITHUB_REPOSITORY}" + fi + + if [[ ! "$DISPATCH_WORKFLOW" =~ ^[A-Za-z0-9_.-]+[.]ya?ml$ ]]; then + fail "Unexpected workflow file: ${DISPATCH_WORKFLOW}" + fi + + token="${GH_TOKEN:-${GITHUB_TOKEN:-}}" + if [ -z "$token" ]; then + fail "GH_TOKEN or GITHUB_TOKEN is required to dispatch ${DISPATCH_WORKFLOW}" + fi + + command -v gh >/dev/null || + fail "GitHub CLI is required to dispatch ${DISPATCH_WORKFLOW}" + + GH_TOKEN="$token" gh workflow run "$DISPATCH_WORKFLOW" \ + --repo "$GITHUB_REPOSITORY" \ + --ref "$DEFAULT_BRANCH" \ + -f "chart_tag=${tag}" +} + +version_less_than() { + left="${1%%[-+]*}" + right="${2%%[-+]*}" + + IFS=. read -r left_major left_minor left_patch <<<"$left" + IFS=. read -r right_major right_minor right_patch <<<"$right" + + if (( left_major != right_major )); then + (( left_major < right_major )) + return + fi + + if (( left_minor != right_minor )); then + (( left_minor < right_minor )) + return + fi + + (( left_patch < right_patch )) +} + +validate_chart_tag() { + tag="$1" + version="${tag#${TAG_PREFIX}}" + + git check-ref-format "refs/tags/${tag}" >/dev/null || + fail "Refusing to use invalid tag ${tag}" + + if [[ "$tag" != "${TAG_PREFIX}"* || ! "$version" =~ $SEMVER_REGEX ]]; then + fail "Chart tags must use the form ${TAG_PREFIX}, for example ${TAG_PREFIX}2.0.5" + fi +} + +dispatch_existing_tag() { + tag="$1" + + if [ -z "$tag" ]; then + return + fi + + validate_chart_tag "$tag" + + if [ "$PUSH_TAGS" != "true" ]; then + printf 'Would dispatch release workflow for existing %s.\n' "$tag" + return + fi + + if ! git_with_auth ls-remote --exit-code --tags origin "refs/tags/${tag}" >/dev/null 2>&1; then + fail "Remote tag ${tag} does not exist" + fi + + printf 'Dispatching release workflow for existing %s.\n' "$tag" + dispatch_release "$tag" +} + +chart_version_at() { + git show "${1}:${CHART_PATH}" 2>/dev/null | awk ' + /^version:[[:space:]]*/ { + value = $0 + sub(/^version:[[:space:]]*/, "", value) + sub(/[[:space:]]*#.*/, "", value) + gsub(/^[[:space:]"'\''"]+|[[:space:]"'\''"]+$/, "", value) + print value + exit + } + ' +} + +case "$PUSH_TAGS" in + true | false) ;; + *) fail "PUSH_TAGS must be true or false" ;; +esac + +if [[ ! "$BACKFILL_FROM_VERSION" =~ $SEMVER_REGEX ]]; then + fail "BACKFILL_FROM_VERSION must be a valid SemVer value" +fi + +git rev-parse --verify "${BASE_REF}^{commit}" >/dev/null || + fail "Unable to resolve ${BASE_REF}; fetch ${DEFAULT_BRANCH} before running this script" + +history_file="$(mktemp)" +versions_file="$(mktemp)" +seen_file="$(mktemp)" +missing_file="$(mktemp)" +cleanup() { + rm -f "$history_file" "$versions_file" "$seen_file" "$missing_file" +} +trap cleanup EXIT + +git log --first-parent --reverse --format=%H "$BASE_REF" -- "$CHART_PATH" >"$history_file" + +if [ ! -s "$history_file" ]; then + fail "No history found for ${CHART_PATH} on ${BASE_REF}" +fi + +while IFS= read -r commit; do + version="$(chart_version_at "$commit")" + + if [ -z "$version" ]; then + continue + fi + + if [[ ! "$version" =~ $SEMVER_REGEX ]]; then + fail "${CHART_PATH} has invalid SemVer '${version}' at ${commit}" + fi + + if version_less_than "$version" "$BACKFILL_FROM_VERSION"; then + continue + fi + + if grep -Fqx "$version" "$seen_file"; then + continue + fi + + printf '%s\n' "$version" >>"$seen_file" + printf '%s\t%s\n' "$version" "$commit" >>"$versions_file" +done <"$history_file" + +if [ ! -s "$versions_file" ]; then + fail "No chart versions found in ${CHART_PATH}" +fi + +while IFS="$(printf '\t')" read -r version commit; do + tag="${TAG_PREFIX}${version}" + + validate_chart_tag "$tag" + + if git rev-parse --quiet --verify "refs/tags/${tag}" >/dev/null; then + continue + fi + + printf '%s\t%s\n' "$tag" "$commit" >>"$missing_file" +done <"$versions_file" + +if [ ! -s "$missing_file" ]; then + printf 'All chart versions on %s already have %s tags.\n' "$BASE_REF" "$TAG_PREFIX" + dispatch_existing_tag "$RELEASE_EXISTING_TAG" + exit 0 +fi + +while IFS="$(printf '\t')" read -r tag commit; do + short_commit="$(git rev-parse --short "$commit")" + + if [ "$PUSH_TAGS" != "true" ]; then + printf 'Would create %s at %s.\n' "$tag" "$short_commit" + continue + fi + + if git_with_auth ls-remote --exit-code --tags origin "refs/tags/${tag}" >/dev/null 2>&1; then + printf 'Remote tag %s already exists; dispatching release workflow.\n' "$tag" + dispatch_release "$tag" + continue + fi + + git tag "$tag" "$commit" + + if git_with_auth push origin "refs/tags/${tag}"; then + printf 'Created %s at %s.\n' "$tag" "$short_commit" + dispatch_release "$tag" + continue + fi + + if git_with_auth ls-remote --exit-code --tags origin "refs/tags/${tag}" >/dev/null 2>&1; then + printf 'Remote tag %s was created concurrently; dispatching release workflow.\n' "$tag" + dispatch_release "$tag" + continue + fi + + fail "Failed to push ${tag}" +done <"$missing_file" + +dispatch_existing_tag "$RELEASE_EXISTING_TAG" diff --git a/.github/workflows/helmcharts.yml b/.github/workflows/helmcharts.yml index 9e08c189a71a..019e4b0e1554 100644 --- a/.github/workflows/helmcharts.yml +++ b/.github/workflows/helmcharts.yml @@ -5,18 +5,52 @@ on: push: tags: - "chart-*" + workflow_dispatch: + inputs: + chart_tag: + description: "Existing chart tag to release, for example chart-2.0.5" + required: true + type: string jobs: release: permissions: - contents: write + contents: read packages: write runs-on: ubuntu-latest + env: + CHART_REPOSITORY: ${{ github.repository_owner }}/librechat-chart steps: + - name: Resolve chart tag + id: chart-version + env: + EVENT_NAME: ${{ github.event_name }} + INPUT_CHART_TAG: ${{ inputs.chart_tag || '' }} + REF_NAME: ${{ github.ref_name }} + run: | + set -euo pipefail + CHART_TAG="$REF_NAME" + if [ "$EVENT_NAME" = "workflow_dispatch" ]; then + CHART_TAG="$INPUT_CHART_TAG" + fi + + CHART_VERSION="${CHART_TAG#chart-}" + SEMVER_REGEX='^[0-9]+[.][0-9]+[.][0-9]+(-[0-9A-Za-z.-]+)?([+][0-9A-Za-z.-]+)?$' + if [[ "$CHART_TAG" != chart-* || ! "$CHART_VERSION" =~ $SEMVER_REGEX ]]; then + echo "::error::Chart tags must use the form chart-, for example chart-2.0.3" + exit 1 + fi + + printf 'CHART_REF=refs/tags/%s\n' "$CHART_TAG" >> "$GITHUB_OUTPUT" + printf 'CHART_TAG=%s\n' "$CHART_TAG" >> "$GITHUB_OUTPUT" + printf 'CHART_VERSION=%s\n' "$CHART_VERSION" >> "$GITHUB_OUTPUT" + - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 0 + persist-credentials: false + ref: ${{ steps.chart-version.outputs.CHART_REF }} - name: Configure Git run: | @@ -35,20 +69,6 @@ jobs: cd ../librechat-rag-api helm dependency build - - name: Get Chart Version - id: chart-version - env: - REF_NAME: ${{ github.ref_name }} - run: | - set -euo pipefail - CHART_VERSION="${REF_NAME#chart-}" - SEMVER_REGEX='^[0-9]+[.][0-9]+[.][0-9]+(-[0-9A-Za-z.-]+)?([+][0-9A-Za-z.-]+)?$' - if [[ "$REF_NAME" != chart-* || ! "$CHART_VERSION" =~ $SEMVER_REGEX ]]; then - echo "::error::Chart tags must use the form chart-, for example chart-2.0.3" - exit 1 - fi - printf 'CHART_VERSION=%s\n' "$CHART_VERSION" >> "$GITHUB_OUTPUT" - # Log in to GitHub Container Registry - name: Log in to GitHub Container Registry uses: docker/login-action@v3 @@ -63,7 +83,7 @@ jobs: uses: appany/helm-oci-chart-releaser@v0.4.2 with: name: librechat - repository: ${{ github.actor }}/librechat-chart + repository: ${{ env.CHART_REPOSITORY }} tag: ${{ steps.chart-version.outputs.CHART_VERSION }} path: helm/librechat registry: ghcr.io @@ -75,7 +95,7 @@ jobs: uses: appany/helm-oci-chart-releaser@v0.4.2 with: name: librechat-rag-api - repository: ${{ github.actor }}/librechat-chart + repository: ${{ env.CHART_REPOSITORY }} tag: ${{ steps.chart-version.outputs.CHART_VERSION }} path: helm/librechat-rag-api registry: ghcr.io diff --git a/.github/workflows/sync-helm-chart-tags.yml b/.github/workflows/sync-helm-chart-tags.yml new file mode 100644 index 000000000000..fe3b5e28d19c --- /dev/null +++ b/.github/workflows/sync-helm-chart-tags.yml @@ -0,0 +1,73 @@ +name: Sync Helm Chart Tags + +on: + push: + branches: + - main + workflow_dispatch: + inputs: + release_existing_tag: + description: "Existing chart-* tag to dispatch if tag creation succeeded but release dispatch failed" + required: false + type: string + +permissions: + actions: write + contents: write + +concurrency: + group: sync-helm-chart-tags + cancel-in-progress: false + +jobs: + sync: + name: Sync chart tags + if: github.ref == 'refs/heads/main' + runs-on: ubuntu-latest + timeout-minutes: 10 + env: + BASE_REF: refs/remotes/origin/main + BACKFILL_FROM_VERSION: 1.9.0 + CHART_PATH: helm/librechat/Chart.yaml + DEFAULT_BRANCH: main + DISPATCH_WORKFLOW: helmcharts.yml + GITHUB_SERVER_URL: ${{ github.server_url }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_REPOSITORY: ${{ github.repository }} + RELEASE_EXISTING_TAG: ${{ inputs.release_existing_tag || '' }} + REPO_DIR: ${{ runner.temp }}/librechat + TAG_PREFIX: chart- + steps: + - name: Fetch main and tags + shell: bash + run: | + set -euo pipefail + + if [[ ! "$GITHUB_REPOSITORY" =~ ^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$ ]]; then + echo "::error::Unexpected repository name: $GITHUB_REPOSITORY" + exit 1 + fi + + if [[ "$GITHUB_SERVER_URL" != "https://github.com" ]]; then + echo "::error::Unexpected GitHub server URL: $GITHUB_SERVER_URL" + exit 1 + fi + + rm -rf "$REPO_DIR" + git init "$REPO_DIR" + cd "$REPO_DIR" + git remote add origin "${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}.git" + git -c "http.${GITHUB_SERVER_URL}/.extraheader=AUTHORIZATION: bearer ${GITHUB_TOKEN}" \ + fetch --prune --force --tags origin \ + "+refs/heads/${DEFAULT_BRANCH}:refs/remotes/origin/${DEFAULT_BRANCH}" + git checkout --detach "$BASE_REF" + + - name: Create missing chart tags + shell: bash + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PUSH_TAGS: "true" + run: | + set -euo pipefail + cd "$REPO_DIR" + .github/scripts/sync-helm-chart-tags.sh From fb282a2afa316b327f8c2030e85d4641fa6ac42c Mon Sep 17 00:00:00 2001 From: Danny Avila Date: Mon, 1 Jun 2026 10:03:18 -0400 Subject: [PATCH 02/14] =?UTF-8?q?=F0=9F=90=B3=20chore:=20Upgrade=20Docker?= =?UTF-8?q?=20Builds=20To=20Node=2024=20(#13448)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore: upgrade docker builds to node 24 * test: avoid array at in telemetry spec --- .devcontainer/Dockerfile | 2 +- .do/gitnexus/Dockerfile | 2 +- .github/CONTRIBUTING.md | 2 +- .github/workflows/backend-review.yml | 42 +++++------ .github/workflows/cache-integration-tests.yml | 4 +- .github/workflows/client.yml | 4 +- .github/workflows/data-provider.yml | 4 +- .github/workflows/data-schemas.yml | 4 +- .github/workflows/eslint-ci.yml | 4 +- .github/workflows/frontend-review.yml | 24 +++--- .github/workflows/gitnexus-index.yml | 2 +- .github/workflows/locize-i18n-sync.yml | 2 +- .github/workflows/unused-packages.yml | 4 +- .nvmrc | 1 + CLAUDE.md | 2 +- Dockerfile | 2 +- Dockerfile.multi | 2 +- client/package.json | 2 +- package-lock.json | 73 ++++++++++++++++--- package.json | 2 +- packages/api/package.json | 2 +- packages/api/src/telemetry/sdk.spec.ts | 3 +- packages/data-provider/package.json | 2 +- packages/data-schemas/package.json | 2 +- 24 files changed, 123 insertions(+), 70 deletions(-) create mode 100644 .nvmrc diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 7f5566fb9791..5d5454e97bef 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,4 +1,4 @@ -FROM node:18-bullseye +FROM node:24.16.0-bullseye RUN useradd -m -s /bin/bash vscode RUN mkdir -p /workspaces && chown -R vscode:vscode /workspaces diff --git a/.do/gitnexus/Dockerfile b/.do/gitnexus/Dockerfile index a1266d5a1332..58a79e087e77 100644 --- a/.do/gitnexus/Dockerfile +++ b/.do/gitnexus/Dockerfile @@ -5,7 +5,7 @@ # startup. A fresh index only requires rsync + container restart — no # image rebuild on every push. -FROM node:24-slim +FROM node:24.16.0-slim ARG GITNEXUS_VERSION=1.5.3 diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index ae9e6d8e4ba7..6524947ba223 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -26,7 +26,7 @@ Project maintainers have the right and responsibility to remove, edit, or reject ## 1. Development Setup -1. Use Node.js v20.19.0+ or ^22.12.0 or >= 23.0.0. +1. Use Node.js v24.16.0. 2. Run `npm run smart-reinstall` to install dependencies (uses Turborepo). Use `npm run reinstall` for a clean install, or `npm ci` for a fresh lockfile-based install. 3. Build all compiled code: `npm run build`. 4. Setup and run unit tests: diff --git a/.github/workflows/backend-review.yml b/.github/workflows/backend-review.yml index 46366b2df05c..e25e884feeb8 100644 --- a/.github/workflows/backend-review.yml +++ b/.github/workflows/backend-review.yml @@ -20,10 +20,10 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Use Node.js 20.19 + - name: Use Node.js 24.16.0 uses: actions/setup-node@v4 with: - node-version: '20.19' + node-version: '24.16.0' - name: Restore node_modules cache id: cache-node-modules @@ -35,7 +35,7 @@ jobs: packages/api/node_modules packages/data-provider/node_modules packages/data-schemas/node_modules - key: node-modules-backend-${{ runner.os }}-20.19-${{ hashFiles('package-lock.json') }} + key: node-modules-backend-${{ runner.os }}-24.16.0-${{ hashFiles('package-lock.json') }} - name: Install dependencies if: steps.cache-node-modules.outputs.cache-hit != 'true' @@ -103,10 +103,10 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Use Node.js 20.19 + - name: Use Node.js 24.16.0 uses: actions/setup-node@v4 with: - node-version: '20.19' + node-version: '24.16.0' - name: Restore node_modules cache id: cache-node-modules @@ -118,7 +118,7 @@ jobs: packages/api/node_modules packages/data-provider/node_modules packages/data-schemas/node_modules - key: node-modules-backend-${{ runner.os }}-20.19-${{ hashFiles('package-lock.json') }} + key: node-modules-backend-${{ runner.os }}-24.16.0-${{ hashFiles('package-lock.json') }} - name: Install dependencies if: steps.cache-node-modules.outputs.cache-hit != 'true' @@ -162,10 +162,10 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Use Node.js 20.19 + - name: Use Node.js 24.16.0 uses: actions/setup-node@v4 with: - node-version: '20.19' + node-version: '24.16.0' - name: Restore node_modules cache id: cache-node-modules @@ -177,7 +177,7 @@ jobs: packages/api/node_modules packages/data-provider/node_modules packages/data-schemas/node_modules - key: node-modules-backend-${{ runner.os }}-20.19-${{ hashFiles('package-lock.json') }} + key: node-modules-backend-${{ runner.os }}-24.16.0-${{ hashFiles('package-lock.json') }} - name: Install dependencies if: steps.cache-node-modules.outputs.cache-hit != 'true' @@ -231,10 +231,10 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Use Node.js 20.19 + - name: Use Node.js 24.16.0 uses: actions/setup-node@v4 with: - node-version: '20.19' + node-version: '24.16.0' - name: Restore node_modules cache id: cache-node-modules @@ -246,7 +246,7 @@ jobs: packages/api/node_modules packages/data-provider/node_modules packages/data-schemas/node_modules - key: node-modules-backend-${{ runner.os }}-20.19-${{ hashFiles('package-lock.json') }} + key: node-modules-backend-${{ runner.os }}-24.16.0-${{ hashFiles('package-lock.json') }} - name: Install dependencies if: steps.cache-node-modules.outputs.cache-hit != 'true' @@ -289,10 +289,10 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Use Node.js 20.19 + - name: Use Node.js 24.16.0 uses: actions/setup-node@v4 with: - node-version: '20.19' + node-version: '24.16.0' - name: Restore node_modules cache id: cache-node-modules @@ -304,7 +304,7 @@ jobs: packages/api/node_modules packages/data-provider/node_modules packages/data-schemas/node_modules - key: node-modules-backend-${{ runner.os }}-20.19-${{ hashFiles('package-lock.json') }} + key: node-modules-backend-${{ runner.os }}-24.16.0-${{ hashFiles('package-lock.json') }} - name: Install dependencies if: steps.cache-node-modules.outputs.cache-hit != 'true' @@ -327,10 +327,10 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Use Node.js 20.19 + - name: Use Node.js 24.16.0 uses: actions/setup-node@v4 with: - node-version: '20.19' + node-version: '24.16.0' - name: Restore node_modules cache id: cache-node-modules @@ -342,7 +342,7 @@ jobs: packages/api/node_modules packages/data-provider/node_modules packages/data-schemas/node_modules - key: node-modules-backend-${{ runner.os }}-20.19-${{ hashFiles('package-lock.json') }} + key: node-modules-backend-${{ runner.os }}-24.16.0-${{ hashFiles('package-lock.json') }} - name: Install dependencies if: steps.cache-node-modules.outputs.cache-hit != 'true' @@ -375,10 +375,10 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Use Node.js 20.19 + - name: Use Node.js 24.16.0 uses: actions/setup-node@v4 with: - node-version: '20.19' + node-version: '24.16.0' - name: Restore node_modules cache id: cache-node-modules @@ -390,7 +390,7 @@ jobs: packages/api/node_modules packages/data-provider/node_modules packages/data-schemas/node_modules - key: node-modules-backend-${{ runner.os }}-20.19-${{ hashFiles('package-lock.json') }} + key: node-modules-backend-${{ runner.os }}-24.16.0-${{ hashFiles('package-lock.json') }} - name: Install dependencies if: steps.cache-node-modules.outputs.cache-hit != 'true' diff --git a/.github/workflows/cache-integration-tests.yml b/.github/workflows/cache-integration-tests.yml index c8f10f388bf0..3e4c5418ae7c 100644 --- a/.github/workflows/cache-integration-tests.yml +++ b/.github/workflows/cache-integration-tests.yml @@ -28,10 +28,10 @@ jobs: - name: Checkout repository uses: actions/checkout@v4 - - name: Use Node.js 20.x + - name: Use Node.js 24.16.0 uses: actions/setup-node@v4 with: - node-version: 20 + node-version: '24.16.0' cache: 'npm' - name: Install Redis tools diff --git a/.github/workflows/client.yml b/.github/workflows/client.yml index 881efa0ebea6..e4dc8c562644 100644 --- a/.github/workflows/client.yml +++ b/.github/workflows/client.yml @@ -27,7 +27,7 @@ jobs: - name: Use Node.js uses: actions/setup-node@v4 with: - node-version: '20.x' + node-version: '24.16.0' - name: Install client dependencies run: cd packages/client && npm ci @@ -77,7 +77,7 @@ jobs: - name: Use Node.js uses: actions/setup-node@v4 with: - node-version: '20.x' + node-version: '24.16.0' registry-url: 'https://registry.npmjs.org' - name: Install npm with OIDC support diff --git a/.github/workflows/data-provider.yml b/.github/workflows/data-provider.yml index 3a9db4d8e56e..eae746ece94a 100644 --- a/.github/workflows/data-provider.yml +++ b/.github/workflows/data-provider.yml @@ -23,7 +23,7 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: - node-version: 20 + node-version: '24.16.0' - run: cd packages/data-provider && npm ci - run: cd packages/data-provider && npm run build - name: Pack package @@ -50,7 +50,7 @@ jobs: steps: - uses: actions/setup-node@v4 with: - node-version: 20 + node-version: '24.16.0' registry-url: 'https://registry.npmjs.org' - name: Install npm with OIDC support diff --git a/.github/workflows/data-schemas.yml b/.github/workflows/data-schemas.yml index 977a6eb4c33e..bb8f90ea8428 100644 --- a/.github/workflows/data-schemas.yml +++ b/.github/workflows/data-schemas.yml @@ -27,7 +27,7 @@ jobs: - name: Use Node.js uses: actions/setup-node@v4 with: - node-version: '20.x' + node-version: '24.16.0' - name: Install dependencies run: cd packages/data-schemas && npm ci @@ -77,7 +77,7 @@ jobs: - name: Use Node.js uses: actions/setup-node@v4 with: - node-version: '20.x' + node-version: '24.16.0' registry-url: 'https://registry.npmjs.org' - name: Install npm with OIDC support diff --git a/.github/workflows/eslint-ci.yml b/.github/workflows/eslint-ci.yml index 85de6fa18e37..3710f8a02ee6 100644 --- a/.github/workflows/eslint-ci.yml +++ b/.github/workflows/eslint-ci.yml @@ -27,10 +27,10 @@ jobs: with: fetch-depth: 0 - - name: Set up Node.js 20.x + - name: Set up Node.js 24.16.0 uses: actions/setup-node@v4 with: - node-version: 20 + node-version: '24.16.0' cache: npm - name: Install dependencies diff --git a/.github/workflows/frontend-review.yml b/.github/workflows/frontend-review.yml index 0021124192ed..b84d145bee2a 100644 --- a/.github/workflows/frontend-review.yml +++ b/.github/workflows/frontend-review.yml @@ -20,10 +20,10 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Use Node.js 20.19 + - name: Use Node.js 24.16.0 uses: actions/setup-node@v4 with: - node-version: '20.19' + node-version: '24.16.0' - name: Restore node_modules cache id: cache-node-modules @@ -34,7 +34,7 @@ jobs: client/node_modules packages/client/node_modules packages/data-provider/node_modules - key: node-modules-frontend-${{ runner.os }}-20.19-${{ hashFiles('package-lock.json') }} + key: node-modules-frontend-${{ runner.os }}-24.16.0-${{ hashFiles('package-lock.json') }} - name: Install dependencies if: steps.cache-node-modules.outputs.cache-hit != 'true' @@ -84,10 +84,10 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Use Node.js 20.19 + - name: Use Node.js 24.16.0 uses: actions/setup-node@v4 with: - node-version: '20.19' + node-version: '24.16.0' - name: Restore node_modules cache id: cache-node-modules @@ -98,7 +98,7 @@ jobs: client/node_modules packages/client/node_modules packages/data-provider/node_modules - key: node-modules-frontend-${{ runner.os }}-20.19-${{ hashFiles('package-lock.json') }} + key: node-modules-frontend-${{ runner.os }}-24.16.0-${{ hashFiles('package-lock.json') }} - name: Install dependencies if: steps.cache-node-modules.outputs.cache-hit != 'true' @@ -128,10 +128,10 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Use Node.js 20.19 + - name: Use Node.js 24.16.0 uses: actions/setup-node@v4 with: - node-version: '20.19' + node-version: '24.16.0' - name: Restore node_modules cache id: cache-node-modules @@ -142,7 +142,7 @@ jobs: client/node_modules packages/client/node_modules packages/data-provider/node_modules - key: node-modules-frontend-${{ runner.os }}-20.19-${{ hashFiles('package-lock.json') }} + key: node-modules-frontend-${{ runner.os }}-24.16.0-${{ hashFiles('package-lock.json') }} - name: Install dependencies if: steps.cache-node-modules.outputs.cache-hit != 'true' @@ -172,10 +172,10 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Use Node.js 20.19 + - name: Use Node.js 24.16.0 uses: actions/setup-node@v4 with: - node-version: '20.19' + node-version: '24.16.0' - name: Restore node_modules cache id: cache-node-modules @@ -186,7 +186,7 @@ jobs: client/node_modules packages/client/node_modules packages/data-provider/node_modules - key: node-modules-frontend-${{ runner.os }}-20.19-${{ hashFiles('package-lock.json') }} + key: node-modules-frontend-${{ runner.os }}-24.16.0-${{ hashFiles('package-lock.json') }} - name: Install dependencies if: steps.cache-node-modules.outputs.cache-hit != 'true' diff --git a/.github/workflows/gitnexus-index.yml b/.github/workflows/gitnexus-index.yml index d3b8ca95e228..21c3f6932131 100644 --- a/.github/workflows/gitnexus-index.yml +++ b/.github/workflows/gitnexus-index.yml @@ -136,7 +136,7 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v4 with: - node-version: 24 + node-version: '24.16.0' - name: Install GitNexus CLI working-directory: ${{ runner.temp }} diff --git a/.github/workflows/locize-i18n-sync.yml b/.github/workflows/locize-i18n-sync.yml index 18266a18e369..f5b80b865a0c 100644 --- a/.github/workflows/locize-i18n-sync.yml +++ b/.github/workflows/locize-i18n-sync.yml @@ -22,7 +22,7 @@ jobs: - name: Set Up Node.js uses: actions/setup-node@v4 with: - node-version: 20 + node-version: '24.16.0' - name: Install locize CLI run: npm install -g locize-cli diff --git a/.github/workflows/unused-packages.yml b/.github/workflows/unused-packages.yml index a957bed2e8dd..5401d37d5b55 100644 --- a/.github/workflows/unused-packages.yml +++ b/.github/workflows/unused-packages.yml @@ -20,10 +20,10 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Use Node.js 20.x + - name: Use Node.js 24.16.0 uses: actions/setup-node@v4 with: - node-version: 20 + node-version: '24.16.0' cache: 'npm' - name: Install depcheck diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 000000000000..b832e4001dbc --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +24.16.0 diff --git a/CLAUDE.md b/CLAUDE.md index 81362cfc5701..8172a6140562 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -143,7 +143,7 @@ Multi-line imports count total character length across all lines. Consolidate va | `npm run frontend:dev` | Start frontend dev server with HMR (port 3090, requires backend running) | | `npm run build:data-provider` | Rebuild `packages/data-provider` after changes | -- Node.js: v20.19.0+ or ^22.12.0 or >= 23.0.0 +- Node.js: v24.16.0 - Database: MongoDB - Backend runs on `http://localhost:3080/`; frontend dev server on `http://localhost:3090/` diff --git a/Dockerfile b/Dockerfile index be5c5b9935ef..6253913262ae 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,7 @@ # v0.8.6 # Base node image -FROM node:20-alpine AS node +FROM node:24.16.0-alpine AS node RUN apk upgrade --no-cache RUN apk add --no-cache jemalloc diff --git a/Dockerfile.multi b/Dockerfile.multi index 17c88c739de4..745e54b8a4cc 100644 --- a/Dockerfile.multi +++ b/Dockerfile.multi @@ -10,7 +10,7 @@ ARG BUILD_BRANCH= ARG BUILD_DATE= # Base for all builds -FROM node:20-alpine AS base-min +FROM node:24.16.0-alpine AS base-min ARG NPM_CI_TIMEOUT_SECONDS=1500 ARG NPM_CI_ATTEMPTS=2 RUN apk upgrade --no-cache diff --git a/client/package.json b/client/package.json index 99e5c6af3f3c..3ac6e25dcbae 100644 --- a/client/package.json +++ b/client/package.json @@ -133,7 +133,7 @@ "@types/jest": "^29.5.14", "@types/js-cookie": "^3.0.6", "@types/lodash": "^4.17.15", - "@types/node": "^20.19.35", + "@types/node": "^24.12.4", "@types/react": "^18.2.11", "@types/react-dom": "^18.2.4", "@vitejs/plugin-react": "^5.1.4", diff --git a/package-lock.json b/package-lock.json index 600eddd53a4c..b4d073a6560e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -514,7 +514,7 @@ "@types/jest": "^29.5.14", "@types/js-cookie": "^3.0.6", "@types/lodash": "^4.17.15", - "@types/node": "^20.19.35", + "@types/node": "^24.12.4", "@types/react": "^18.2.11", "@types/react-dom": "^18.2.4", "@vitejs/plugin-react": "^5.1.4", @@ -1228,13 +1228,13 @@ } }, "client/node_modules/@types/node": { - "version": "20.19.35", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.35.tgz", - "integrity": "sha512-Uarfe6J91b9HAUXxjvSOdiO2UPOKLm07Q1oh0JHxoZ1y8HoqxDAu3gVrsrOHeiio0kSsoVBt4wFrKOm0dKxVPQ==", + "version": "24.12.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.12.4.tgz", + "integrity": "sha512-GUUEShf+PBCGW2KaXwcIt3Yk+e3pkKwWKb9GSyM9WQVE+ep2jzmHdGsHzu4wgcZy5fN9FBdVzjpBQsYlpfpgLA==", "dev": true, "license": "MIT", "dependencies": { - "undici-types": "~6.21.0" + "undici-types": "~7.16.0" } }, "client/node_modules/@vitejs/plugin-react": { @@ -1430,9 +1430,9 @@ } }, "client/node_modules/undici-types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", - "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", "dev": true, "license": "MIT" }, @@ -44035,7 +44035,7 @@ "@types/jest": "^29.5.2", "@types/jsonwebtoken": "^9.0.0", "@types/multer": "^1.4.13", - "@types/node": "^20.3.0", + "@types/node": "^24.12.4", "@types/node-fetch": "^2.6.13", "@types/react": "^18.2.18", "@types/sanitize-html": "^2.13.0", @@ -44135,6 +44135,16 @@ "keyv": "^5.3.4" } }, + "packages/api/node_modules/@types/node": { + "version": "24.12.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.12.4.tgz", + "integrity": "sha512-GUUEShf+PBCGW2KaXwcIt3Yk+e3pkKwWKb9GSyM9WQVE+ep2jzmHdGsHzu4wgcZy5fN9FBdVzjpBQsYlpfpgLA==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.16.0" + } + }, "packages/api/node_modules/rimraf": { "version": "6.1.3", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-6.1.3.tgz", @@ -44155,6 +44165,13 @@ "url": "https://github.com/sponsors/isaacs" } }, + "packages/api/node_modules/undici-types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "dev": true, + "license": "MIT" + }, "packages/client": { "name": "@librechat/client", "version": "0.4.60", @@ -44653,7 +44670,7 @@ "@rollup/plugin-terser": "^1.0.0", "@types/jest": "^29.5.2", "@types/js-yaml": "^4.0.9", - "@types/node": "^20.3.0", + "@types/node": "^24.12.4", "@types/react": "^18.2.18", "@types/winston": "^2.4.4", "jest": "^30.2.0", @@ -44692,6 +44709,16 @@ } } }, + "packages/data-provider/node_modules/@types/node": { + "version": "24.12.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.12.4.tgz", + "integrity": "sha512-GUUEShf+PBCGW2KaXwcIt3Yk+e3pkKwWKb9GSyM9WQVE+ep2jzmHdGsHzu4wgcZy5fN9FBdVzjpBQsYlpfpgLA==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.16.0" + } + }, "packages/data-provider/node_modules/rimraf": { "version": "6.1.3", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-6.1.3.tgz", @@ -44712,6 +44739,13 @@ "url": "https://github.com/sponsors/isaacs" } }, + "packages/data-provider/node_modules/undici-types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "dev": true, + "license": "MIT" + }, "packages/data-schemas": { "name": "@librechat/data-schemas", "version": "0.0.52", @@ -44726,7 +44760,7 @@ "@rollup/plugin-typescript": "^12.1.2", "@types/express": "^5.0.0", "@types/jest": "^29.5.2", - "@types/node": "^20.3.0", + "@types/node": "^24.12.4", "jest": "^30.2.0", "jest-junit": "^16.0.0", "mongodb-memory-server": "^11.0.1", @@ -44772,6 +44806,16 @@ } } }, + "packages/data-schemas/node_modules/@types/node": { + "version": "24.12.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.12.4.tgz", + "integrity": "sha512-GUUEShf+PBCGW2KaXwcIt3Yk+e3pkKwWKb9GSyM9WQVE+ep2jzmHdGsHzu4wgcZy5fN9FBdVzjpBQsYlpfpgLA==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.16.0" + } + }, "packages/data-schemas/node_modules/logform": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/logform/-/logform-2.7.0.tgz", @@ -44818,6 +44862,13 @@ "url": "https://github.com/sponsors/isaacs" } }, + "packages/data-schemas/node_modules/undici-types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "dev": true, + "license": "MIT" + }, "packages/data-schemas/node_modules/winston": { "version": "3.17.0", "resolved": "https://registry.npmjs.org/winston/-/winston-3.17.0.tgz", diff --git a/package.json b/package.json index 6bd266663c1c..25091fdd983e 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "LibreChat", "version": "v0.8.6", "description": "", - "packageManager": "npm@11.10.0", + "packageManager": "npm@11.13.0", "workspaces": [ "api", "client", diff --git a/packages/api/package.json b/packages/api/package.json index 4776884241f3..e8fe6d74adca 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -65,7 +65,7 @@ "@types/jest": "^29.5.2", "@types/jsonwebtoken": "^9.0.0", "@types/multer": "^1.4.13", - "@types/node": "^20.3.0", + "@types/node": "^24.12.4", "@types/node-fetch": "^2.6.13", "@types/react": "^18.2.18", "@types/sanitize-html": "^2.13.0", diff --git a/packages/api/src/telemetry/sdk.spec.ts b/packages/api/src/telemetry/sdk.spec.ts index f43762237ac8..9e79a49d9c9f 100644 --- a/packages/api/src/telemetry/sdk.spec.ts +++ b/packages/api/src/telemetry/sdk.spec.ts @@ -506,7 +506,8 @@ describe('telemetry SDK lifecycle', () => { mockShutdown.mockRejectedValueOnce(new Error('flush failed')); initializeTelemetry({ OTEL_TRACING_ENABLED: 'true' }); - const taskFn = (registerShutdownTask as jest.Mock).mock.calls.at(-1)?.[1] as + const shutdownTaskCalls = (registerShutdownTask as jest.Mock).mock.calls; + const taskFn = shutdownTaskCalls[shutdownTaskCalls.length - 1]?.[1] as | (() => Promise) | undefined; expect(taskFn).toBeDefined(); diff --git a/packages/data-provider/package.json b/packages/data-provider/package.json index d85f01c4f37d..bb597b3b33a1 100644 --- a/packages/data-provider/package.json +++ b/packages/data-provider/package.json @@ -60,7 +60,7 @@ "@rollup/plugin-terser": "^1.0.0", "@types/jest": "^29.5.2", "@types/js-yaml": "^4.0.9", - "@types/node": "^20.3.0", + "@types/node": "^24.12.4", "@types/react": "^18.2.18", "@types/winston": "^2.4.4", "jest": "^30.2.0", diff --git a/packages/data-schemas/package.json b/packages/data-schemas/package.json index 5debadc14814..b9afab139f4b 100644 --- a/packages/data-schemas/package.json +++ b/packages/data-schemas/package.json @@ -52,7 +52,7 @@ "@rollup/plugin-typescript": "^12.1.2", "@types/express": "^5.0.0", "@types/jest": "^29.5.2", - "@types/node": "^20.3.0", + "@types/node": "^24.12.4", "jest": "^30.2.0", "jest-junit": "^16.0.0", "mongodb-memory-server": "^11.0.1", From e21146c04417a4bf092dd97124369a1188ff2e84 Mon Sep 17 00:00:00 2001 From: Danny Avila Date: Mon, 1 Jun 2026 11:44:36 -0400 Subject: [PATCH 03/14] =?UTF-8?q?=E2=9B=91=EF=B8=8F=20ci:=20Fix=20Helm=20T?= =?UTF-8?q?ag=20Sync=20Workflow=20Planning=20(#13451)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/helmcharts.yml | 10 ++++++---- .github/workflows/sync-helm-chart-tags.yml | 21 ++++++++++++++++----- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/.github/workflows/helmcharts.yml b/.github/workflows/helmcharts.yml index 019e4b0e1554..9e0308ec727b 100644 --- a/.github/workflows/helmcharts.yml +++ b/.github/workflows/helmcharts.yml @@ -25,7 +25,7 @@ jobs: id: chart-version env: EVENT_NAME: ${{ github.event_name }} - INPUT_CHART_TAG: ${{ inputs.chart_tag || '' }} + INPUT_CHART_TAG: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.chart_tag || '' }} REF_NAME: ${{ github.ref_name }} run: | set -euo pipefail @@ -41,9 +41,11 @@ jobs: exit 1 fi - printf 'CHART_REF=refs/tags/%s\n' "$CHART_TAG" >> "$GITHUB_OUTPUT" - printf 'CHART_TAG=%s\n' "$CHART_TAG" >> "$GITHUB_OUTPUT" - printf 'CHART_VERSION=%s\n' "$CHART_VERSION" >> "$GITHUB_OUTPUT" + { + printf 'CHART_REF=refs/tags/%s\n' "$CHART_TAG" + printf 'CHART_TAG=%s\n' "$CHART_TAG" + printf 'CHART_VERSION=%s\n' "$CHART_VERSION" + } >> "$GITHUB_OUTPUT" - name: Checkout uses: actions/checkout@v4 diff --git a/.github/workflows/sync-helm-chart-tags.yml b/.github/workflows/sync-helm-chart-tags.yml index fe3b5e28d19c..e029a256c17a 100644 --- a/.github/workflows/sync-helm-chart-tags.yml +++ b/.github/workflows/sync-helm-chart-tags.yml @@ -12,19 +12,30 @@ on: type: string permissions: - actions: write - contents: write + contents: read concurrency: group: sync-helm-chart-tags cancel-in-progress: false jobs: + noop: + name: Ignore non-main push + if: github.event_name == 'push' && github.ref != 'refs/heads/main' + runs-on: ubuntu-latest + timeout-minutes: 1 + steps: + - name: Skip tag sync + run: echo "Helm chart tag sync only runs on main pushes or manual dispatch." + sync: name: Sync chart tags - if: github.ref == 'refs/heads/main' + if: github.event_name == 'workflow_dispatch' || github.ref == 'refs/heads/main' runs-on: ubuntu-latest timeout-minutes: 10 + permissions: + actions: write + contents: write env: BASE_REF: refs/remotes/origin/main BACKFILL_FROM_VERSION: 1.9.0 @@ -34,8 +45,8 @@ jobs: GITHUB_SERVER_URL: ${{ github.server_url }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_REPOSITORY: ${{ github.repository }} - RELEASE_EXISTING_TAG: ${{ inputs.release_existing_tag || '' }} - REPO_DIR: ${{ runner.temp }}/librechat + RELEASE_EXISTING_TAG: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.release_existing_tag || '' }} + REPO_DIR: /tmp/librechat-sync TAG_PREFIX: chart- steps: - name: Fetch main and tags From 7dba640c9fad9a55a5c1f479627fa4aca02113e3 Mon Sep 17 00:00:00 2001 From: Danny Avila Date: Mon, 1 Jun 2026 15:47:58 -0400 Subject: [PATCH 04/14] =?UTF-8?q?=E2=9A=A1=20chore:=20Upgrade=20Vite=20For?= =?UTF-8?q?=20Node=2024=20(#13450)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore: upgrade vite for node 24 * fix: restore production vite boot * fix: preserve dynamic pwa shell --- client/package.json | 12 +- client/src/components/Skills/index.ts | 1 - client/src/main.jsx | 2 +- client/src/polyfills/regeneratorRuntime.js | 3 + client/vite.config.ts | 325 +-- package-lock.json | 2188 +++++++++----------- 6 files changed, 1202 insertions(+), 1329 deletions(-) create mode 100644 client/src/polyfills/regeneratorRuntime.js diff --git a/client/package.json b/client/package.json index 3ac6e25dcbae..d7906026dd3d 100644 --- a/client/package.json +++ b/client/package.json @@ -111,7 +111,7 @@ "remark-gfm": "^4.0.0", "remark-math": "^6.0.0", "remark-supersub": "^1.0.0", - "sse.js": "^2.5.0", + "sse.js": "^2.8.0", "swr": "^2.3.8", "tailwind-merge": "^1.9.1", "tailwindcss-animate": "^1.0.5", @@ -136,7 +136,7 @@ "@types/node": "^24.12.4", "@types/react": "^18.2.11", "@types/react-dom": "^18.2.4", - "@vitejs/plugin-react": "^5.1.4", + "@vitejs/plugin-react": "^6.0.2", "autoprefixer": "^10.4.20", "babel-plugin-replace-ts-export-assignment": "^0.0.2", "babel-plugin-root-import": "^6.6.0", @@ -155,9 +155,9 @@ "postcss-preset-env": "^11.2.0", "tailwindcss": "^3.4.1", "typescript": "^5.3.3", - "vite": "^7.3.1", - "vite-plugin-compression2": "^2.2.1", - "vite-plugin-node-polyfills": "^0.25.0", - "vite-plugin-pwa": "^1.2.0" + "vite": "^8.0.16", + "vite-plugin-compression2": "^2.5.3", + "vite-plugin-node-polyfills": "^0.28.0", + "vite-plugin-pwa": "^1.3.0" } } diff --git a/client/src/components/Skills/index.ts b/client/src/components/Skills/index.ts index dcf7a32137c0..6adbdb28f851 100644 --- a/client/src/components/Skills/index.ts +++ b/client/src/components/Skills/index.ts @@ -2,7 +2,6 @@ export * from './buttons'; export * from './dialogs'; export * from './display'; export * from './forms'; -export * from './layouts'; export * from './lists'; export * from './sidebar'; export * from './tree'; diff --git a/client/src/main.jsx b/client/src/main.jsx index 53b483f8d20d..d7dd8e0f6e3f 100644 --- a/client/src/main.jsx +++ b/client/src/main.jsx @@ -1,4 +1,4 @@ -import 'regenerator-runtime/runtime'; +import './polyfills/regeneratorRuntime'; import { createRoot } from 'react-dom/client'; import './locales/i18n'; import App from './App'; diff --git a/client/src/polyfills/regeneratorRuntime.js b/client/src/polyfills/regeneratorRuntime.js new file mode 100644 index 000000000000..28c5a8d86c36 --- /dev/null +++ b/client/src/polyfills/regeneratorRuntime.js @@ -0,0 +1,3 @@ +import regeneratorRuntime from 'regenerator-runtime/runtime'; + +globalThis.regeneratorRuntime ??= regeneratorRuntime; diff --git a/client/vite.config.ts b/client/vite.config.ts index 9d0335df742b..060fdf7b1cb2 100644 --- a/client/vite.config.ts +++ b/client/vite.config.ts @@ -12,7 +12,7 @@ const require = createRequire(import.meta.url); /** * vite-plugin-node-polyfills uses @rollup/plugin-inject to replace bare globals (e.g. `process`) * with imports like `import process from 'vite-plugin-node-polyfills/shims/process'`. When the - * consuming module (e.g. recoil) is hoisted to the monorepo root, Vite 7's ESM resolver walks up + * consuming module (e.g. recoil) is hoisted to the monorepo root, Vite's ESM resolver walks up * from there and never finds the shims (installed only in client/node_modules). This map resolves * the shim specifiers to absolute paths via CJS require.resolve anchored to the client directory. */ @@ -84,7 +84,8 @@ export default defineConfig(({ command }) => ({ ], globIgnores: ['images/**/*', '**/*.map', 'index.html', 'assets/rum.*.js'], maximumFileSizeToCacheInBytes: 4 * 1024 * 1024, - navigateFallbackDenylist: [/^\/oauth/, /^\/api/], + /** LibreChat mutates index.html per request for subpath and language support. */ + navigateFallback: null, }, includeAssets: [], manifest: { @@ -133,164 +134,186 @@ export default defineConfig(({ command }) => ({ sourcemap: process.env.NODE_ENV === 'development', outDir: './dist', minify: 'terser', - rollupOptions: { + rolldownOptions: { preserveEntrySignatures: 'strict', output: { - manualChunks(id: string) { - const normalizedId = id.replace(/\\/g, '/'); - if (normalizedId.includes('node_modules')) { - if (normalizedId.includes('@hyperdx/')) { - return 'rum'; - } + codeSplitting: { + groups: [ + { + name(id: string) { + const normalizedId = id.replace(/\\/g, '/'); + if (normalizedId.includes('node_modules')) { + if (normalizedId.includes('/node_modules/regenerator-runtime/')) { + return 'polyfills'; + } - // IMPORTANT: mermaid and ALL its dependencies must be in the same chunk - // to avoid initialization order issues. This includes chevrotain, langium, - // dagre-d3-es, and their nested lodash-es dependencies. - if ( - normalizedId.includes('mermaid') || - normalizedId.includes('dagre-d3-es') || - normalizedId.includes('chevrotain') || - normalizedId.includes('langium') || - normalizedId.includes('lodash-es') - ) { - return 'mermaid'; - } + if (normalizedId.includes('@hyperdx/')) { + return 'rum'; + } - if (normalizedId.includes('@codesandbox/sandpack')) { - return 'sandpack'; - } - if (normalizedId.includes('react-vtree')) { - return 'react-vtree'; - } - if (normalizedId.includes('react-virtualized')) { - return 'virtualization'; - } - if (normalizedId.includes('i18next') || normalizedId.includes('react-i18next')) { - return 'i18n'; - } - // Only regular lodash (not lodash-es which goes to mermaid chunk) - if (normalizedId.includes('/lodash/')) { - return 'utilities'; - } - if (normalizedId.includes('date-fns')) { - return 'date-utils'; - } - if (normalizedId.includes('@dicebear')) { - return 'avatars'; - } - if ( - normalizedId.includes('react-dnd') || - normalizedId.includes('dnd-core') || - normalizedId.includes('react-flip-toolkit') || - normalizedId.includes('flip-toolkit') - ) { - return 'react-interactions'; - } - if (normalizedId.includes('react-hook-form')) { - return 'forms'; - } - if (normalizedId.includes('react-router-dom')) { - return 'routing'; - } - if ( - normalizedId.includes('qrcode.react') || - normalizedId.includes('@marsidev/react-turnstile') - ) { - return 'security-ui'; - } + // IMPORTANT: mermaid and ALL its dependencies must be in the same chunk + // to avoid initialization order issues. This includes chevrotain, langium, + // dagre-d3-es, and their nested lodash-es dependencies. + if ( + normalizedId.includes('mermaid') || + normalizedId.includes('dagre-d3-es') || + normalizedId.includes('chevrotain') || + normalizedId.includes('langium') || + normalizedId.includes('lodash-es') + ) { + return 'mermaid'; + } - if (normalizedId.includes('@codemirror/view')) { - return 'codemirror-view'; - } - if (normalizedId.includes('@codemirror/state')) { - return 'codemirror-state'; - } - if (normalizedId.includes('@codemirror/language')) { - return 'codemirror-language'; - } - if (normalizedId.includes('@codemirror')) { - return 'codemirror-core'; - } + if (normalizedId.includes('@codesandbox/sandpack')) { + return 'sandpack'; + } + if (normalizedId.includes('react-vtree')) { + return 'react-vtree'; + } + if (normalizedId.includes('react-virtualized')) { + return 'virtualization'; + } + if (normalizedId.includes('i18next') || normalizedId.includes('react-i18next')) { + return 'i18n'; + } + // Only regular lodash (not lodash-es which goes to mermaid chunk) + if (normalizedId.includes('/lodash/')) { + return 'utilities'; + } + if (normalizedId.includes('date-fns')) { + return 'date-utils'; + } + if (normalizedId.includes('@dicebear')) { + return 'avatars'; + } + if ( + normalizedId.includes('react-dnd') || + normalizedId.includes('dnd-core') || + normalizedId.includes('react-flip-toolkit') || + normalizedId.includes('flip-toolkit') + ) { + return 'react-interactions'; + } + if (normalizedId.includes('react-hook-form')) { + return 'forms'; + } + if (normalizedId.includes('react-router-dom')) { + return 'routing'; + } + if ( + normalizedId.includes('qrcode.react') || + normalizedId.includes('@marsidev/react-turnstile') + ) { + return 'security-ui'; + } - if ( - normalizedId.includes('react-markdown') || - normalizedId.includes('remark-') || - normalizedId.includes('rehype-') - ) { - return 'markdown-processing'; - } - if (normalizedId.includes('monaco-editor') || normalizedId.includes('@monaco-editor')) { - return 'code-editor'; - } - if (normalizedId.includes('react-window') || normalizedId.includes('react-virtual')) { - return 'virtualization'; - } - if ( - normalizedId.includes('zod') || - normalizedId.includes('yup') || - normalizedId.includes('joi') - ) { - return 'validation'; - } - if ( - normalizedId.includes('axios') || - normalizedId.includes('ky') || - normalizedId.includes('fetch') - ) { - return 'http-client'; - } - if ( - normalizedId.includes('react-spring') || - normalizedId.includes('react-transition-group') - ) { - return 'animations'; - } - if (normalizedId.includes('react-select') || normalizedId.includes('downshift')) { - return 'advanced-inputs'; - } - if (normalizedId.includes('heic-to')) { - return 'heic-converter'; - } + if (normalizedId.includes('@codemirror/view')) { + return 'codemirror-view'; + } + if (normalizedId.includes('@codemirror/state')) { + return 'codemirror-state'; + } + if (normalizedId.includes('@codemirror/language')) { + return 'codemirror-language'; + } + if (normalizedId.includes('@codemirror')) { + return 'codemirror-core'; + } - // Existing chunks - if (normalizedId.includes('@radix-ui')) { - return 'radix-ui'; - } - if (normalizedId.includes('framer-motion')) { - return 'framer-motion'; - } - if ( - normalizedId.includes('node_modules/highlight.js') || - normalizedId.includes('node_modules/lowlight') - ) { - return 'markdown_highlight'; - } - if (normalizedId.includes('katex') || normalizedId.includes('node_modules/katex')) { - return 'math-katex'; - } - if (normalizedId.includes('node_modules/hast-util-raw')) { - return 'markdown_large'; - } - if (normalizedId.includes('@tanstack')) { - return 'tanstack-vendor'; - } - if (normalizedId.includes('@headlessui')) { - return 'headlessui'; - } + if ( + normalizedId.includes('react-markdown') || + normalizedId.includes('remark-') || + normalizedId.includes('rehype-') + ) { + return 'markdown-processing'; + } + if ( + normalizedId.includes('monaco-editor') || + normalizedId.includes('@monaco-editor') + ) { + return 'code-editor'; + } + if ( + normalizedId.includes('react-window') || + normalizedId.includes('react-virtual') + ) { + return 'virtualization'; + } + if ( + normalizedId.includes('zod') || + normalizedId.includes('yup') || + normalizedId.includes('joi') + ) { + return 'validation'; + } + if ( + normalizedId.includes('axios') || + normalizedId.includes('ky') || + normalizedId.includes('fetch') + ) { + return 'http-client'; + } + if ( + normalizedId.includes('react-spring') || + normalizedId.includes('react-transition-group') + ) { + return 'animations'; + } + if (normalizedId.includes('react-select') || normalizedId.includes('downshift')) { + return 'advanced-inputs'; + } + if (normalizedId.includes('heic-to')) { + return 'heic-converter'; + } - if (normalizedId.includes('@icons-pack/react-simple-icons/icons/')) { - return; - } + // Existing chunks + if (normalizedId.includes('@radix-ui')) { + return 'radix-ui'; + } + if (normalizedId.includes('framer-motion')) { + return 'framer-motion'; + } + if ( + normalizedId.includes('node_modules/highlight.js') || + normalizedId.includes('node_modules/lowlight') + ) { + return 'markdown_highlight'; + } + if ( + normalizedId.includes('katex') || + normalizedId.includes('node_modules/katex') + ) { + return 'math-katex'; + } + if (normalizedId.includes('node_modules/hast-util-raw')) { + return 'markdown_large'; + } + if (normalizedId.includes('@tanstack')) { + return 'tanstack-vendor'; + } + if (normalizedId.includes('@headlessui')) { + return 'headlessui'; + } - // Everything else falls into a generic vendor chunk. - return 'vendor'; - } - // Create a separate chunk for all locale files under src/locales. - if (normalizedId.includes('/src/locales/')) { - return 'locales'; - } - // Let Rollup decide automatically for any other files. - return null; + if (normalizedId.includes('@icons-pack/react-simple-icons/icons/')) { + return null; + } + + // Everything else falls into a generic vendor chunk. + return 'vendor'; + } + if (normalizedId.includes('/src/polyfills/')) { + return 'polyfills'; + } + // Create a separate chunk for all locale files under src/locales. + if (normalizedId.includes('/src/locales/')) { + return 'locales'; + } + // Let Rolldown decide automatically for any other files. + return null; + }, + }, + ], }, entryFileNames: 'assets/[name].[hash].js', chunkFileNames: 'assets/[name].[hash].js', diff --git a/package-lock.json b/package-lock.json index b4d073a6560e..e5b549fa476c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -492,7 +492,7 @@ "remark-gfm": "^4.0.0", "remark-math": "^6.0.0", "remark-supersub": "^1.0.0", - "sse.js": "^2.5.0", + "sse.js": "^2.8.0", "swr": "^2.3.8", "tailwind-merge": "^1.9.1", "tailwindcss-animate": "^1.0.5", @@ -517,7 +517,7 @@ "@types/node": "^24.12.4", "@types/react": "^18.2.11", "@types/react-dom": "^18.2.4", - "@vitejs/plugin-react": "^5.1.4", + "@vitejs/plugin-react": "^6.0.2", "autoprefixer": "^10.4.20", "babel-plugin-replace-ts-export-assignment": "^0.0.2", "babel-plugin-root-import": "^6.6.0", @@ -536,10 +536,10 @@ "postcss-preset-env": "^11.2.0", "tailwindcss": "^3.4.1", "typescript": "^5.3.3", - "vite": "^7.3.1", - "vite-plugin-compression2": "^2.2.1", - "vite-plugin-node-polyfills": "^0.25.0", - "vite-plugin-pwa": "^1.2.0" + "vite": "^8.0.16", + "vite-plugin-compression2": "^2.5.3", + "vite-plugin-node-polyfills": "^0.28.0", + "vite-plugin-pwa": "^1.3.0" } }, "client/node_modules/@babel/code-frame": { @@ -563,6 +563,7 @@ "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", @@ -594,6 +595,7 @@ "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/parser": "^7.29.0", "@babel/types": "^7.29.0", @@ -611,6 +613,7 @@ "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/compat-data": "^7.28.6", "@babel/helper-validator-option": "^7.27.1", @@ -628,6 +631,7 @@ "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/traverse": "^7.28.6", "@babel/types": "^7.28.6" @@ -642,6 +646,7 @@ "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/helper-module-imports": "^7.28.6", "@babel/helper-validator-identifier": "^7.28.5", @@ -660,6 +665,7 @@ "integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/template": "^7.28.6", "@babel/types": "^7.28.6" @@ -705,6 +711,7 @@ "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", @@ -775,431 +782,6 @@ "react-dom": "^16.8.0 || ^17 || ^18" } }, - "client/node_modules/@esbuild/aix-ppc64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", - "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" - } - }, - "client/node_modules/@esbuild/android-arm": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", - "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "client/node_modules/@esbuild/android-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", - "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "client/node_modules/@esbuild/android-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", - "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "client/node_modules/@esbuild/darwin-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", - "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "client/node_modules/@esbuild/darwin-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", - "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "client/node_modules/@esbuild/freebsd-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", - "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "client/node_modules/@esbuild/freebsd-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", - "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "client/node_modules/@esbuild/linux-arm": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", - "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "client/node_modules/@esbuild/linux-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", - "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "client/node_modules/@esbuild/linux-ia32": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", - "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "client/node_modules/@esbuild/linux-loong64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", - "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "client/node_modules/@esbuild/linux-mips64el": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", - "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "client/node_modules/@esbuild/linux-ppc64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", - "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "client/node_modules/@esbuild/linux-riscv64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", - "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "client/node_modules/@esbuild/linux-s390x": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", - "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "client/node_modules/@esbuild/linux-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", - "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "client/node_modules/@esbuild/netbsd-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", - "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "client/node_modules/@esbuild/netbsd-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", - "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "client/node_modules/@esbuild/openbsd-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", - "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "client/node_modules/@esbuild/openbsd-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", - "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "client/node_modules/@esbuild/sunos-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", - "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "client/node_modules/@esbuild/win32-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", - "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "client/node_modules/@esbuild/win32-ia32": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", - "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "client/node_modules/@esbuild/win32-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", - "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, "client/node_modules/@react-spring/web": { "version": "9.7.5", "resolved": "https://registry.npmjs.org/@react-spring/web/-/web-9.7.5.tgz", @@ -1227,35 +809,30 @@ "pretty-format": "^29.0.0" } }, - "client/node_modules/@types/node": { - "version": "24.12.4", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.12.4.tgz", - "integrity": "sha512-GUUEShf+PBCGW2KaXwcIt3Yk+e3pkKwWKb9GSyM9WQVE+ep2jzmHdGsHzu4wgcZy5fN9FBdVzjpBQsYlpfpgLA==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~7.16.0" - } - }, "client/node_modules/@vitejs/plugin-react": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.1.4.tgz", - "integrity": "sha512-VIcFLdRi/VYRU8OL/puL7QXMYafHmqOnwTZY50U1JPlCNj30PxCMx65c494b1K9be9hX83KVt0+gTEwTWLqToA==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.0.2.tgz", + "integrity": "sha512-DlSMqo4WhThw4vB8Mpn0Woe9J+Jfq1geJ61AKW0QEgLzGMNwtIMdxbDUzLxcun8W7NbJO0e2Jg/Nxm3cCSVzzg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/core": "^7.29.0", - "@babel/plugin-transform-react-jsx-self": "^7.27.1", - "@babel/plugin-transform-react-jsx-source": "^7.27.1", - "@rolldown/pluginutils": "1.0.0-rc.3", - "@types/babel__core": "^7.20.5", - "react-refresh": "^0.18.0" + "@rolldown/pluginutils": "^1.0.0" }, "engines": { "node": "^20.19.0 || >=22.12.0" }, "peerDependencies": { - "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" + "@rolldown/plugin-babel": "^0.1.7 || ^0.2.0", + "babel-plugin-react-compiler": "^1.0.0", + "vite": "^8.0.0" + }, + "peerDependenciesMeta": { + "@rolldown/plugin-babel": { + "optional": true + }, + "babel-plugin-react-compiler": { + "optional": true + } } }, "client/node_modules/babel-plugin-transform-import-meta": { @@ -1272,99 +849,6 @@ "@babel/core": "^7.10.0" } }, - "client/node_modules/browserslist": { - "version": "4.24.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.4.tgz", - "integrity": "sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==", - "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": { - "caniuse-lite": "^1.0.30001688", - "electron-to-chromium": "^1.5.73", - "node-releases": "^2.0.19", - "update-browserslist-db": "^1.1.1" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "client/node_modules/esbuild": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", - "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.27.3", - "@esbuild/android-arm": "0.27.3", - "@esbuild/android-arm64": "0.27.3", - "@esbuild/android-x64": "0.27.3", - "@esbuild/darwin-arm64": "0.27.3", - "@esbuild/darwin-x64": "0.27.3", - "@esbuild/freebsd-arm64": "0.27.3", - "@esbuild/freebsd-x64": "0.27.3", - "@esbuild/linux-arm": "0.27.3", - "@esbuild/linux-arm64": "0.27.3", - "@esbuild/linux-ia32": "0.27.3", - "@esbuild/linux-loong64": "0.27.3", - "@esbuild/linux-mips64el": "0.27.3", - "@esbuild/linux-ppc64": "0.27.3", - "@esbuild/linux-riscv64": "0.27.3", - "@esbuild/linux-s390x": "0.27.3", - "@esbuild/linux-x64": "0.27.3", - "@esbuild/netbsd-arm64": "0.27.3", - "@esbuild/netbsd-x64": "0.27.3", - "@esbuild/openbsd-arm64": "0.27.3", - "@esbuild/openbsd-x64": "0.27.3", - "@esbuild/openharmony-arm64": "0.27.3", - "@esbuild/sunos-x64": "0.27.3", - "@esbuild/win32-arm64": "0.27.3", - "@esbuild/win32-ia32": "0.27.3", - "@esbuild/win32-x64": "0.27.3" - } - }, - "client/node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, "client/node_modules/framer-motion": { "version": "11.18.2", "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-11.18.2.tgz", @@ -1401,19 +885,6 @@ "react": "^16.5.1 || ^17.0.0 || ^18.0.0" } }, - "client/node_modules/picomatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", - "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "client/node_modules/react-is": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", @@ -1425,171 +896,11 @@ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "license": "ISC", + "peer": true, "bin": { "semver": "bin/semver.js" } }, - "client/node_modules/undici-types": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", - "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", - "dev": true, - "license": "MIT" - }, - "client/node_modules/update-browserslist-db": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.2.tgz", - "integrity": "sha512-PPypAm5qvlD7XMZC3BujecnaOxwhrtoFR+Dqkk5Aa/6DssiH0ibKoketaj9w8LP7Bont1rYeoV5plxD7RTEPRg==", - "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" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "client/node_modules/vite": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.2.tgz", - "integrity": "sha512-Bby3NOsna2jsjfLVOHKes8sGwgl4TT0E6vvpYgnAYDIF/tie7MRaFthmKuHx1NSXjiTueXH3do80FMQgvEktRg==", - "dev": true, - "license": "MIT", - "dependencies": { - "esbuild": "^0.27.0", - "fdir": "^6.5.0", - "picomatch": "^4.0.3", - "postcss": "^8.5.6", - "rollup": "^4.43.0", - "tinyglobby": "^0.2.15" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - }, - "peerDependencies": { - "@types/node": "^20.19.0 || >=22.12.0", - "jiti": ">=1.21.0", - "less": "^4.0.0", - "lightningcss": "^1.21.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" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "jiti": { - "optional": true - }, - "less": { - "optional": true - }, - "lightningcss": { - "optional": true - }, - "sass": { - "optional": true - }, - "sass-embedded": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - }, - "tsx": { - "optional": true - }, - "yaml": { - "optional": true - } - } - }, - "client/node_modules/vite-plugin-node-polyfills": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/vite-plugin-node-polyfills/-/vite-plugin-node-polyfills-0.25.0.tgz", - "integrity": "sha512-rHZ324W3LhfGPxWwQb2N048TThB6nVvnipsqBUJEzh3R9xeK9KI3si+GMQxCuAcpPJBVf0LpDtJ+beYzB3/chg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@rollup/plugin-inject": "^5.0.5", - "node-stdlib-browser": "^1.3.1" - }, - "funding": { - "url": "https://github.com/sponsors/davidmyersdev" - }, - "peerDependencies": { - "vite": "^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" - } - }, - "client/node_modules/vite-plugin-pwa": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/vite-plugin-pwa/-/vite-plugin-pwa-1.2.0.tgz", - "integrity": "sha512-a2xld+SJshT9Lgcv8Ji4+srFJL4k/1bVbd1x06JIkvecpQkwkvCncD1+gSzcdm3s+owWLpMJerG3aN5jupJEVw==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "^4.3.6", - "pretty-bytes": "^6.1.1", - "tinyglobby": "^0.2.10", - "workbox-build": "^7.4.0", - "workbox-window": "^7.4.0" - }, - "engines": { - "node": ">=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/antfu" - }, - "peerDependencies": { - "@vite-pwa/assets-generator": "^1.0.0", - "vite": "^3.1.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0", - "workbox-build": "^7.4.0", - "workbox-window": "^7.4.0" - }, - "peerDependenciesMeta": { - "@vite-pwa/assets-generator": { - "optional": true - } - } - }, "node_modules/@aashutoshrathi/word-wrap": { "version": "1.2.6", "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", @@ -1660,14 +971,13 @@ } }, "node_modules/@apideck/better-ajv-errors": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/@apideck/better-ajv-errors/-/better-ajv-errors-0.3.6.tgz", - "integrity": "sha512-P+ZygBLZtkp0qqOAJJVX4oX/sFo5JR3eBWwwuqHHhK0GIgQOKWrAfiAaWX0aArHkRWHMuggFEgAZNxVPwPZYaA==", + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/@apideck/better-ajv-errors/-/better-ajv-errors-0.3.7.tgz", + "integrity": "sha512-TajUJwGWbDwkCx/CZi7tRE8PVB7simCvKJfHUsSdvps+aTM/PDPP4gkLmKnc+x3CE//y9i/nj74GqdL/hwk7Iw==", "dev": true, "license": "MIT", "dependencies": { - "json-schema": "^0.4.0", - "jsonpointer": "^5.0.0", + "jsonpointer": "^5.0.1", "leven": "^3.1.0" }, "engines": { @@ -6612,38 +5922,6 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-react-jsx-self": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz", - "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-source": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz", - "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/@babel/plugin-transform-react-pure-annotations": { "version": "7.23.3", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.23.3.tgz", @@ -9268,21 +8546,21 @@ } }, "node_modules/@emnapi/core": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.7.1.tgz", - "integrity": "sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", + "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", "dev": true, "license": "MIT", "optional": true, "dependencies": { - "@emnapi/wasi-threads": "1.1.0", + "@emnapi/wasi-threads": "1.2.1", "tslib": "^2.4.0" } }, "node_modules/@emnapi/runtime": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.7.1.tgz", - "integrity": "sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", + "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", "license": "MIT", "optional": true, "dependencies": { @@ -9290,9 +8568,9 @@ } }, "node_modules/@emnapi/wasi-threads": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz", - "integrity": "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", + "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", "dev": true, "license": "MIT", "optional": true, @@ -9300,23 +8578,6 @@ "tslib": "^2.4.0" } }, - "node_modules/@esbuild/openharmony-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", - "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": ">=18" - } - }, "node_modules/@eslint-community/eslint-utils": { "version": "4.9.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz", @@ -11835,9 +11096,10 @@ } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", - "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==" + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.31", @@ -14080,6 +13342,16 @@ "node": ">=14" } }, + "node_modules/@oxc-project/types": { + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.133.0.tgz", + "integrity": "sha512-KzkdCd6Uxqnf6l3HOw1xfatAlUURA0g14cvBYFyJ5SaNOQbOUvBr9PKArcPcrNIeRsBdgcUzOGrhKveVpvOIGA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, "node_modules/@paralleldrive/cuid2": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/@paralleldrive/cuid2/-/cuid2-2.2.2.tgz", @@ -18145,10 +17417,304 @@ } } }, + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.3.tgz", + "integrity": "sha512-454rs7jHngixp/NMxd5srYD57OnzSlZ/eFTETjORQHLwJG1lRtmNOJcBerZlfu4GjKqeq8aCCIQrMdHyhI51Hw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.3.tgz", + "integrity": "sha512-PcAhP+ynjURNyy8SKGl5DQP94aGuB/7JrXJb/t7P+hanXvQVMWzUvRRhBAcg/lNRadBhoUPqSoP4xw5tR/KBEA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.3.tgz", + "integrity": "sha512-9YpfeUvSE2RS7wysJ81uOZkXJz7f7Q55H2Gvp3VEw/EsahqDtrphrZ0EwDLK5vvKOzaCrBsjF8JmnMLcUt78Gg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.3.tgz", + "integrity": "sha512-yB1IlAsSNHncV6SCTL27/MVGR5htvQsoGxIv5KMGXALp+Ll1wYsn+x98M9MW7qa+NdSbvrrY7ANI4wLJ0n1e6g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.3.tgz", + "integrity": "sha512-Yi30IVAAfLUCy2MseFjbB1jAMDl1VMCAas5StnYp8da9+CKvMd2H2cbEjWcw5NPaPqzvYkVIaF1nNUG+b7u/sw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.3.tgz", + "integrity": "sha512-jsO7R8To+AdlYgUmN5sHSCZbfhtMBkO0WUx8iORQnPcMMdgr7qM2DQmMwgabs3GhNztdmoKkMKQFHD6DTMCIQw==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.3.tgz", + "integrity": "sha512-VWkUHwWriDciit80wleYwKILoR/KMvxh/IdwS/paX+ZgpuRpCrKLUdadJbc0NpBEiyhpYawsJ73j9aCvOH+f7Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.3.tgz", + "integrity": "sha512-5f1laC0SlIR0yDbFCd8acUhvJIag6N3zC5P7oUPN6wX0aOma+uKJ0wBDH5aq7I1PVI2ttTlhJwzwRIBnLiSGEg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.3.tgz", + "integrity": "sha512-Iq4ko0r4XsgbrF/LunNgHtAGLRRVE2kXonAXQ/MV0mC6jQpMOhW1SvtZja2EhC/kd05++bP78dsqBeIQyYJ6Yg==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.3.tgz", + "integrity": "sha512-B8m6tD5+/N5FeNQFbKlLA/2yVq9ycQP1SeedyEYYKWBNR3ZQbkvIUcNnDNM03lO1l5F2roiiFJGgvoLLyZXtSg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.3.tgz", + "integrity": "sha512-pSdpdUJHkuCxun9LE7jvgUB9qsRgaiyNNCX7m/AvHTcq67AiT/Yhoxvw5zPfhrM8k/BfP8ce/hMOpthKDpEUow==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.3.tgz", + "integrity": "sha512-OXXS3RKJgX2uLwM+gYyuH5omcH8fL1LJs96pZGgtetVCahON57+d4SJHzTgZiOjxgGkSnpXpOsWuPDGAKAigEg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.3.tgz", + "integrity": "sha512-JTtb8BWFynicNSoPrehsCzBtOKjZ6jhMiPFEmOiuXg1Fl8dn2KHQob+GuPSGR0dryQa1PQJbzjF3dqO/whhjLg==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "1.10.0", + "@emnapi/runtime": "1.10.0", + "@napi-rs/wasm-runtime": "^1.1.4" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-wasm32-wasi/node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz", + "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@tybys/wasm-util": "^0.10.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1" + } + }, + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.3.tgz", + "integrity": "sha512-gEdFFEN70A/jxb2svrWsN3aDL7OUtmvlOy+6fa2jxG8K0wQ1ZbdeLGnidov6Yu5/733dI5ySfzFlQ/cb0bSz1g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.3.tgz", + "integrity": "sha512-eXB7CHuaQdqmJcc3koCNtNPmT/bj2gc999kUFgBxG8Ac0NdgXc4rkCHhqrgrhN3zddvvvrgzj1e90SuSfmyIXA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-rc.3", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.3.tgz", - "integrity": "sha512-eybk3TjzzzV97Dlj5c+XrBFW57eTNhzod66y9HrBlzJ6NsCrWCp/2kaPS3K9wJmurBC0Tdw4yPjXKZqlznim3Q==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", + "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", "dev": true, "license": "MIT" }, @@ -18172,6 +17738,33 @@ } } }, + "node_modules/@rollup/plugin-babel": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-6.1.0.tgz", + "integrity": "sha512-dFZNuFD2YRcoomP4oYf+DvQNSUA9ih+A3vUqopQx5EdtPGo3WBnQcI/S8pwpz91UsGfL0HsMSOlaMld8HrbubA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.18.6", + "@rollup/pluginutils": "^5.0.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0", + "@types/babel__core": "^7.1.9", + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "@types/babel__core": { + "optional": true + }, + "rollup": { + "optional": true + } + } + }, "node_modules/@rollup/plugin-commonjs": { "version": "29.0.0", "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-29.0.0.tgz", @@ -18320,17 +17913,18 @@ } }, "node_modules/@rollup/plugin-terser": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.4.tgz", - "integrity": "sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-1.0.0.tgz", + "integrity": "sha512-FnCxhTBx6bMOYQrar6C8h3scPt8/JwIzw3+AJ2K++6guogH5fYaIFia+zZuhqv0eo1RN7W1Pz630SyvLbDjhtQ==", "dev": true, + "license": "MIT", "dependencies": { - "serialize-javascript": "^6.0.1", + "serialize-javascript": "^7.0.3", "smob": "^1.0.0", "terser": "^5.17.4" }, "engines": { - "node": ">=14.0.0" + "node": ">=20.0.0" }, "peerDependencies": { "rollup": "^2.0.0||^3.0.0||^4.0.0" @@ -19788,29 +19382,6 @@ "resolved": "https://registry.npmjs.org/@stitches/core/-/core-1.2.8.tgz", "integrity": "sha512-Gfkvwk9o9kE9r9XNBmJRfV8zONvXThnm1tcuojL04Uy5uRyqg93DC83lDebl0rocZCfKSjUv+fWYtMQmEDJldg==" }, - "node_modules/@surma/rollup-plugin-off-main-thread": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz", - "integrity": "sha512-lR8q/9W7hZpMWweNiAKU7NQerBnzQQLvi8qnTDU/fxItPhtZVMbPV3lbCwjhIlNBe9Bbr5V+KHshvWmVSG9cxQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "ejs": "^3.1.6", - "json5": "^2.2.0", - "magic-string": "^0.25.0", - "string.prototype.matchall": "^4.0.6" - } - }, - "node_modules/@surma/rollup-plugin-off-main-thread/node_modules/magic-string": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", - "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "sourcemap-codec": "^1.4.8" - } - }, "node_modules/@swc/helpers": { "version": "0.5.17", "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.17.tgz", @@ -20107,6 +19678,22 @@ "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==" }, + "node_modules/@trickfilm400/rollup-plugin-off-main-thread": { + "version": "3.0.0-pre1", + "resolved": "https://registry.npmjs.org/@trickfilm400/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-3.0.0-pre1.tgz", + "integrity": "sha512-/67zpWDBLV+oYAEL682s1ktXL0HgqX76f6gaVGkGnVZlBbm1zd0v4Bz8MFF2GGhoX9rvfq3KSQHubFHwa6w6/Q==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "ejs": "^3.1.10", + "json5": "^2.2.3", + "magic-string": "^0.30.21", + "string.prototype.matchall": "^4.0.12" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/@tsconfig/node10": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", @@ -20766,11 +20353,12 @@ } }, "node_modules/@types/node": { - "version": "20.11.16", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.16.tgz", - "integrity": "sha512-gKb0enTmRCzXSSUJDq6/sPcqrfCv2mkkG6Jt/clpn5eiCbKTY+SgZUxo+p8ZKMof5dCp9vHQUAB7wOUTod22wQ==", + "version": "24.12.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.12.4.tgz", + "integrity": "sha512-GUUEShf+PBCGW2KaXwcIt3Yk+e3pkKwWKb9GSyM9WQVE+ep2jzmHdGsHzu4wgcZy5fN9FBdVzjpBQsYlpfpgLA==", + "license": "MIT", "dependencies": { - "undici-types": "~5.26.4" + "undici-types": "~7.16.0" } }, "node_modules/@types/node-fetch": { @@ -26602,6 +26190,19 @@ "node": ">=0.10.0" } }, + "node_modules/eta": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/eta/-/eta-4.6.0.tgz", + "integrity": "sha512-lW6is4T1NFOYnmqGZIfvixqj7A7sSvScF+DN8EK6K58xI5MZ5UvYe0GjopxOXQtZvUn4eDdVuZ8XSoYWTMEKwA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/bgub/eta?sponsor=1" + } + }, "node_modules/etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", @@ -27193,9 +26794,9 @@ } }, "node_modules/filelist/node_modules/brace-expansion": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.3.tgz", - "integrity": "sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz", + "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==", "dev": true, "license": "MIT", "dependencies": { @@ -27437,11 +27038,12 @@ } }, "node_modules/foreground-child": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", - "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "license": "ISC", "dependencies": { - "cross-spawn": "^7.0.0", + "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" }, "engines": { @@ -31156,13 +30758,6 @@ "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", "dev": true }, - "node_modules/json-schema": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", - "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", - "dev": true, - "license": "(AFL-2.1 OR BSD-3-Clause)" - }, "node_modules/json-schema-to-ts": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/json-schema-to-ts/-/json-schema-to-ts-3.1.1.tgz", @@ -31627,6 +31222,279 @@ "immediate": "~3.0.5" } }, + "node_modules/lightningcss": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", + "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", + "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.32.0", + "lightningcss-darwin-arm64": "1.32.0", + "lightningcss-darwin-x64": "1.32.0", + "lightningcss-freebsd-x64": "1.32.0", + "lightningcss-linux-arm-gnueabihf": "1.32.0", + "lightningcss-linux-arm64-gnu": "1.32.0", + "lightningcss-linux-arm64-musl": "1.32.0", + "lightningcss-linux-x64-gnu": "1.32.0", + "lightningcss-linux-x64-musl": "1.32.0", + "lightningcss-win32-arm64-msvc": "1.32.0", + "lightningcss-win32-x64-msvc": "1.32.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", + "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", + "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.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", + "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", + "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.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", + "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", + "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.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", + "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", + "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.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", + "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", + "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.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", + "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "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-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", + "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "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-x64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", + "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "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-x64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", + "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", + "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", + "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, "node_modules/lilconfig": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", @@ -32346,13 +32214,13 @@ } }, "node_modules/magic-string": { - "version": "0.30.17", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", - "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0" + "@jridgewell/sourcemap-codec": "^1.5.5" } }, "node_modules/make-dir": { @@ -38127,16 +37995,6 @@ } } }, - "node_modules/react-refresh": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.18.0.tgz", - "integrity": "sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/react-remove-scroll": { "version": "2.5.5", "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.5.5.tgz", @@ -39454,6 +39312,40 @@ "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==", "license": "Unlicense" }, + "node_modules/rolldown": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.3.tgz", + "integrity": "sha512-i00lAJ2ks1BYr7rjNjKC7BcqAS7nVfiT3QX1SI5aY+AFHblCmaUf9OE9dbdzDvW6dJxbi2ZCZiy9v3CcwOiX3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oxc-project/types": "=0.133.0", + "@rolldown/pluginutils": "^1.0.0" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm64": "1.0.3", + "@rolldown/binding-darwin-arm64": "1.0.3", + "@rolldown/binding-darwin-x64": "1.0.3", + "@rolldown/binding-freebsd-x64": "1.0.3", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.3", + "@rolldown/binding-linux-arm64-gnu": "1.0.3", + "@rolldown/binding-linux-arm64-musl": "1.0.3", + "@rolldown/binding-linux-ppc64-gnu": "1.0.3", + "@rolldown/binding-linux-s390x-gnu": "1.0.3", + "@rolldown/binding-linux-x64-gnu": "1.0.3", + "@rolldown/binding-linux-x64-musl": "1.0.3", + "@rolldown/binding-openharmony-arm64": "1.0.3", + "@rolldown/binding-wasm32-wasi": "1.0.3", + "@rolldown/binding-win32-arm64-msvc": "1.0.3", + "@rolldown/binding-win32-x64-msvc": "1.0.3" + } + }, "node_modules/rollup": { "version": "4.59.0", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.59.0.tgz", @@ -40337,14 +40229,6 @@ "source-map": "^0.6.0" } }, - "node_modules/sourcemap-codec": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", - "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", - "deprecated": "Please use @jridgewell/sourcemap-codec instead", - "dev": true, - "license": "MIT" - }, "node_modules/space-separated-tokens": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", @@ -40369,9 +40253,9 @@ "license": "BSD-3-Clause" }, "node_modules/sse.js": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/sse.js/-/sse.js-2.5.0.tgz", - "integrity": "sha512-I7zYndqOOkNpz9KIdFZ8c8A7zs1YazNewBr8Nsi/tqThfJkVPuP1q7UE2h4B0RwoWZxbBYpd06uoW3NI3SaZXg==", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/sse.js/-/sse.js-2.8.0.tgz", + "integrity": "sha512-35RyyFYpzzHZgMw9D5GxwADbL6gnntSwW/rKXcuIy1KkYCPjW6oia0moNdNRhs34oVHU1Sjgovj3l7uIEZjrKA==", "license": "Apache-2.0" }, "node_modules/stable": { @@ -41492,14 +41376,14 @@ } }, "node_modules/tinyglobby": { - "version": "0.2.15", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", - "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", "dev": true, "license": "MIT", "dependencies": { "fdir": "^6.5.0", - "picomatch": "^4.0.3" + "picomatch": "^4.0.4" }, "engines": { "node": ">=12.0.0" @@ -42123,9 +42007,10 @@ } }, "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "license": "MIT" }, "node_modules/unicode-canonical-property-names-ecmascript": { "version": "2.0.1", @@ -42766,10 +42651,88 @@ "node": ">=4" } }, + "node_modules/vite": { + "version": "8.0.16", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.16.tgz", + "integrity": "sha512-h9bXPmJichP5fLmVQo3PyaGSDE2n3aPuomeAlVRm0JLmt4rY6zmPKd59HYI4LNW8oTK7tlTsuC7l/m7awx9Jcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "lightningcss": "^1.32.0", + "picomatch": "^4.0.4", + "postcss": "^8.5.15", + "rolldown": "1.0.3", + "tinyglobby": "^0.2.17" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.1.18", + "esbuild": "^0.27.0 || ^0.28.0", + "jiti": ">=1.21.0", + "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" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "@vitejs/devtools": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, "node_modules/vite-plugin-compression2": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/vite-plugin-compression2/-/vite-plugin-compression2-2.2.1.tgz", - "integrity": "sha512-LMDkgheJaFBmb8cB8ymgUpXHXnd3m4kmjEInvp59fOZMSaT/9oDUtqpO0ihr4ExGsnWfYcRe13/TNN3BEk2t/g==", + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/vite-plugin-compression2/-/vite-plugin-compression2-2.5.3.tgz", + "integrity": "sha512-ItPgqQWkcnBbVw7is9OKwiZ8v6+ju9rYROl5Lp6QfQDEx/d55AwJQb/KLpsQqsU9HoigYBsZ8tK6I02UwJNvEw==", "dev": true, "license": "MIT", "dependencies": { @@ -42777,6 +42740,67 @@ "tar-mini": "^0.2.0" } }, + "node_modules/vite-plugin-node-polyfills": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/vite-plugin-node-polyfills/-/vite-plugin-node-polyfills-0.28.0.tgz", + "integrity": "sha512-NXct/ci2ef4fRyCfTb8fk2HmR80Rv7icLd+cRH41TnUugDzdKMFKqFPpZYCFUInZMMem9bkLv5pkq02+7Xu7+w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rollup/plugin-inject": "^5.0.5", + "node-stdlib-browser": "^1.3.1" + }, + "funding": { + "url": "https://github.com/sponsors/davidmyersdev" + }, + "peerDependencies": { + "vite": "^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/vite-plugin-pwa": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/vite-plugin-pwa/-/vite-plugin-pwa-1.3.0.tgz", + "integrity": "sha512-c5kMgN+ITrOtHXp8PAtk2uOIEea6XjP/unCGxOWWBzQ6qa65qj/awHg0wf+QF9E/2u9vh86LqxPwzEPNbM2r5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.6", + "pretty-bytes": "^6.1.1", + "tinyglobby": "^0.2.10", + "workbox-build": "^7.4.1", + "workbox-window": "^7.4.1" + }, + "engines": { + "node": ">=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vite-pwa/assets-generator": "^1.0.0", + "vite": "^3.1.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0", + "workbox-build": "^7.4.1", + "workbox-window": "^7.4.1" + }, + "peerDependenciesMeta": { + "@vite-pwa/assets-generator": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/vm-browserify": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", @@ -43067,30 +43091,30 @@ "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==" }, "node_modules/workbox-background-sync": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/workbox-background-sync/-/workbox-background-sync-7.4.0.tgz", - "integrity": "sha512-8CB9OxKAgKZKyNMwfGZ1XESx89GryWTfI+V5yEj8sHjFH8MFelUwYXEyldEK6M6oKMmn807GoJFUEA1sC4XS9w==", + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/workbox-background-sync/-/workbox-background-sync-7.4.1.tgz", + "integrity": "sha512-HhT7KE8tOWDm02wRNshXUnUPofMlhenF2DBdUnDPOubhizzPeItkYTmAB6td1Z2cjYPa98vzEiPLEuzn5hN66g==", "dev": true, "license": "MIT", "dependencies": { "idb": "^7.0.1", - "workbox-core": "7.4.0" + "workbox-core": "7.4.1" } }, "node_modules/workbox-broadcast-update": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/workbox-broadcast-update/-/workbox-broadcast-update-7.4.0.tgz", - "integrity": "sha512-+eZQwoktlvo62cI0b+QBr40v5XjighxPq3Fzo9AWMiAosmpG5gxRHgTbGGhaJv/q/MFVxwFNGh/UwHZ/8K88lA==", + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/workbox-broadcast-update/-/workbox-broadcast-update-7.4.1.tgz", + "integrity": "sha512-uAlgslKLvbQY+suirIdnBCSYrcgBhjp81Nj4l1lj/Jmj0MJO2CJERnCJjT0GFVwmReV0N+zs78K6gqd5gr9/+A==", "dev": true, "license": "MIT", "dependencies": { - "workbox-core": "7.4.0" + "workbox-core": "7.4.1" } }, "node_modules/workbox-build": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/workbox-build/-/workbox-build-7.4.0.tgz", - "integrity": "sha512-Ntk1pWb0caOFIvwz/hfgrov/OJ45wPEhI5PbTywQcYjyZiVhT3UrwwUPl6TRYbTm4moaFYithYnl1lvZ8UjxcA==", + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/workbox-build/-/workbox-build-7.4.1.tgz", + "integrity": "sha512-SDhxIvEAde9Gy/5w4Yo1Jh/M49Z0qE3q0oteyE8zGq0DScxFqVBcCtIXFuLtmtxRQZCMbf0prco4VyEu3KBQuw==", "dev": true, "license": "MIT", "dependencies": { @@ -43098,39 +43122,39 @@ "@babel/core": "^7.24.4", "@babel/preset-env": "^7.11.0", "@babel/runtime": "^7.11.2", - "@rollup/plugin-babel": "^5.2.0", - "@rollup/plugin-node-resolve": "^15.2.3", - "@rollup/plugin-replace": "^2.4.1", - "@rollup/plugin-terser": "^0.4.3", - "@surma/rollup-plugin-off-main-thread": "^2.2.3", + "@rollup/plugin-babel": "^6.1.0", + "@rollup/plugin-node-resolve": "^16.0.3", + "@rollup/plugin-replace": "^6.0.3", + "@rollup/plugin-terser": "^1.0.0", + "@trickfilm400/rollup-plugin-off-main-thread": "^3.0.0-pre1", "ajv": "^8.6.0", "common-tags": "^1.8.0", + "eta": "^4.5.1", "fast-json-stable-stringify": "^2.1.0", "fs-extra": "^9.0.1", "glob": "^11.0.1", - "lodash": "^4.17.20", "pretty-bytes": "^5.3.0", - "rollup": "^2.79.2", + "rollup": "^4.53.3", "source-map": "^0.8.0-beta.0", "stringify-object": "^3.3.0", "strip-comments": "^2.0.1", "tempy": "^0.6.0", "upath": "^1.2.0", - "workbox-background-sync": "7.4.0", - "workbox-broadcast-update": "7.4.0", - "workbox-cacheable-response": "7.4.0", - "workbox-core": "7.4.0", - "workbox-expiration": "7.4.0", - "workbox-google-analytics": "7.4.0", - "workbox-navigation-preload": "7.4.0", - "workbox-precaching": "7.4.0", - "workbox-range-requests": "7.4.0", - "workbox-recipes": "7.4.0", - "workbox-routing": "7.4.0", - "workbox-strategies": "7.4.0", - "workbox-streams": "7.4.0", - "workbox-sw": "7.4.0", - "workbox-window": "7.4.0" + "workbox-background-sync": "7.4.1", + "workbox-broadcast-update": "7.4.1", + "workbox-cacheable-response": "7.4.1", + "workbox-core": "7.4.1", + "workbox-expiration": "7.4.1", + "workbox-google-analytics": "7.4.1", + "workbox-navigation-preload": "7.4.1", + "workbox-precaching": "7.4.1", + "workbox-range-requests": "7.4.1", + "workbox-recipes": "7.4.1", + "workbox-routing": "7.4.1", + "workbox-strategies": "7.4.1", + "workbox-streams": "7.4.1", + "workbox-sw": "7.4.1", + "workbox-window": "7.4.1" }, "engines": { "node": ">=20.0.0" @@ -43146,69 +43170,53 @@ "node": ">=18" } }, - "node_modules/workbox-build/node_modules/@rollup/plugin-babel": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz", - "integrity": "sha512-WFfdLWU/xVWKeRQnKmIAQULUI7Il0gZnBIH/ZFO069wYIfPu+8zrfp/KMW0atmELoRDq8FbiP3VCss9MhCut7Q==", + "node_modules/workbox-build/node_modules/@rollup/plugin-node-resolve": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-16.0.3.tgz", + "integrity": "sha512-lUYM3UBGuM93CnMPG1YocWu7X802BrNF3jW2zny5gQyLQgRFJhV1Sq0Zi74+dh/6NBx1DxFC4b4GXg9wUCG5Qg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.10.4", - "@rollup/pluginutils": "^3.1.0" + "@rollup/pluginutils": "^5.0.1", + "@types/resolve": "1.20.2", + "deepmerge": "^4.2.2", + "is-module": "^1.0.0", + "resolve": "^1.22.1" }, "engines": { - "node": ">= 10.0.0" + "node": ">=14.0.0" }, "peerDependencies": { - "@babel/core": "^7.0.0", - "@types/babel__core": "^7.1.9", - "rollup": "^1.20.0||^2.0.0" + "rollup": "^2.78.0||^3.0.0||^4.0.0" }, "peerDependenciesMeta": { - "@types/babel__core": { + "rollup": { "optional": true } } }, "node_modules/workbox-build/node_modules/@rollup/plugin-replace": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-2.4.2.tgz", - "integrity": "sha512-IGcu+cydlUMZ5En85jxHH4qj2hta/11BHq95iHEyb2sbgiN0eCdzvUcHw5gt9pBL5lTi4JDYJ1acCoMGpTvEZg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@rollup/pluginutils": "^3.1.0", - "magic-string": "^0.25.7" - }, - "peerDependencies": { - "rollup": "^1.20.0 || ^2.0.0" - } - }, - "node_modules/workbox-build/node_modules/@rollup/pluginutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", - "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-6.0.3.tgz", + "integrity": "sha512-J4RZarRvQAm5IF0/LwUUg+obsm+xZhYnbMXmXROyoSE1ATJe3oXSb9L5MMppdxP2ylNSjv6zFBwKYjcKMucVfA==", "dev": true, "license": "MIT", "dependencies": { - "@types/estree": "0.0.39", - "estree-walker": "^1.0.1", - "picomatch": "^2.2.2" + "@rollup/pluginutils": "^5.0.1", + "magic-string": "^0.30.3" }, "engines": { - "node": ">= 8.0.0" + "node": ">=14.0.0" }, "peerDependencies": { - "rollup": "^1.20.0||^2.0.0" + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } } }, - "node_modules/workbox-build/node_modules/@types/estree": { - "version": "0.0.39", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", - "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", - "dev": true, - "license": "MIT" - }, "node_modules/workbox-build/node_modules/balanced-match": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", @@ -43232,30 +43240,6 @@ "node": "18 || 20 || >=22" } }, - "node_modules/workbox-build/node_modules/estree-walker": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", - "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", - "dev": true, - "license": "MIT" - }, - "node_modules/workbox-build/node_modules/foreground-child": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", - "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", - "dev": true, - "license": "ISC", - "dependencies": { - "cross-spawn": "^7.0.6", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/workbox-build/node_modules/fs-extra": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", @@ -43314,33 +43298,23 @@ } }, "node_modules/workbox-build/node_modules/lru-cache": { - "version": "11.2.6", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.6.tgz", - "integrity": "sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==", + "version": "11.5.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.1.tgz", + "integrity": "sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==", "dev": true, "license": "BlueOak-1.0.0", "engines": { "node": "20 || >=22" } }, - "node_modules/workbox-build/node_modules/magic-string": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", - "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "sourcemap-codec": "^1.4.8" - } - }, "node_modules/workbox-build/node_modules/minimatch": { - "version": "10.2.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", - "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { - "brace-expansion": "^5.0.2" + "brace-expansion": "^5.0.5" }, "engines": { "node": "18 || 20 || >=22" @@ -43379,35 +43353,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/workbox-build/node_modules/rollup": { - "version": "2.80.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.80.0.tgz", - "integrity": "sha512-cIFJOD1DESzpjOBl763Kp1AH7UE/0fcdHe6rZXUdQ9c50uvgigvW97u3IcSeBwOkgqL/PXPBktBCh0KEu5L8XQ==", - "dev": true, - "license": "MIT", - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=10.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/workbox-build/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/workbox-build/node_modules/source-map": { "version": "0.8.0-beta.0", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz", @@ -43452,140 +43397,140 @@ } }, "node_modules/workbox-cacheable-response": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/workbox-cacheable-response/-/workbox-cacheable-response-7.4.0.tgz", - "integrity": "sha512-0Fb8795zg/x23ISFkAc7lbWes6vbw34DGFIMw31cwuHPgDEC/5EYm6m/ZkylLX0EnEbbOyOCLjKgFS/Z5g0HeQ==", + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/workbox-cacheable-response/-/workbox-cacheable-response-7.4.1.tgz", + "integrity": "sha512-8xaFoJdDc2OjrlbbL3gEeBO1WKcMwRqwLRupgqahYXu75yXajPLuwrbXMrIGZuWYXrQwk0xDjOxZ/ujCy/oJYw==", "dev": true, "license": "MIT", "dependencies": { - "workbox-core": "7.4.0" + "workbox-core": "7.4.1" } }, "node_modules/workbox-core": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/workbox-core/-/workbox-core-7.4.0.tgz", - "integrity": "sha512-6BMfd8tYEnN4baG4emG9U0hdXM4gGuDU3ectXuVHnj71vwxTFI7WOpQJC4siTOlVtGqCUtj0ZQNsrvi6kZZTAQ==", + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/workbox-core/-/workbox-core-7.4.1.tgz", + "integrity": "sha512-DT+vu46eh/2vRsSHTY4Xmc32Z1rr9PRlQUXr1Dx30ZuXRWwOsvZgGgcwxcasubQLQmbTNYZjv44LkBAQ4tT5tQ==", "dev": true, "license": "MIT" }, "node_modules/workbox-expiration": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/workbox-expiration/-/workbox-expiration-7.4.0.tgz", - "integrity": "sha512-V50p4BxYhtA80eOvulu8xVfPBgZbkxJ1Jr8UUn0rvqjGhLDqKNtfrDfjJKnLz2U8fO2xGQJTx/SKXNTzHOjnHw==", + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/workbox-expiration/-/workbox-expiration-7.4.1.tgz", + "integrity": "sha512-lRKUF7b+OGbeXkQk1s6MHXOa3d7Xxf7Of31W6c6hCfipfIyrtdWZ89stq21AHZMaoG7VNFoHply4Ox+rU31TWg==", "dev": true, "license": "MIT", "dependencies": { "idb": "^7.0.1", - "workbox-core": "7.4.0" + "workbox-core": "7.4.1" } }, "node_modules/workbox-google-analytics": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/workbox-google-analytics/-/workbox-google-analytics-7.4.0.tgz", - "integrity": "sha512-MVPXQslRF6YHkzGoFw1A4GIB8GrKym/A5+jYDUSL+AeJw4ytQGrozYdiZqUW1TPQHW8isBCBtyFJergUXyNoWQ==", + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/workbox-google-analytics/-/workbox-google-analytics-7.4.1.tgz", + "integrity": "sha512-Mks1JwLEt++ZAkF6sS1OpSh9RtAMIsiDgRpK+codiHGIPXeaUOgi4cPc3GFadUl8V5QPeypEk8Oxgl3HlwVzHw==", "dev": true, "license": "MIT", "dependencies": { - "workbox-background-sync": "7.4.0", - "workbox-core": "7.4.0", - "workbox-routing": "7.4.0", - "workbox-strategies": "7.4.0" + "workbox-background-sync": "7.4.1", + "workbox-core": "7.4.1", + "workbox-routing": "7.4.1", + "workbox-strategies": "7.4.1" } }, "node_modules/workbox-navigation-preload": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/workbox-navigation-preload/-/workbox-navigation-preload-7.4.0.tgz", - "integrity": "sha512-etzftSgdQfjMcfPgbfaZCfM2QuR1P+4o8uCA2s4rf3chtKTq/Om7g/qvEOcZkG6v7JZOSOxVYQiOu6PbAZgU6w==", + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/workbox-navigation-preload/-/workbox-navigation-preload-7.4.1.tgz", + "integrity": "sha512-C4KVsjPcYKJOhr631AxR9XoG2rLF3QiTk5aMv36MXOjtWvm8axwNFAtKUPGsWUwLXXAMgYM1En7fsvndaXeXRQ==", "dev": true, "license": "MIT", "dependencies": { - "workbox-core": "7.4.0" + "workbox-core": "7.4.1" } }, "node_modules/workbox-precaching": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/workbox-precaching/-/workbox-precaching-7.4.0.tgz", - "integrity": "sha512-VQs37T6jDqf1rTxUJZXRl3yjZMf5JX/vDPhmx2CPgDDKXATzEoqyRqhYnRoxl6Kr0rqaQlp32i9rtG5zTzIlNg==", + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/workbox-precaching/-/workbox-precaching-7.4.1.tgz", + "integrity": "sha512-cdr/9qByww7yzEp7zg/qI4ukUrrNjQLgN+ONQRpjy/VqGQXwkgHwr00KksGJK8v0VifwDXBb8a4cWNZH71jn3Q==", "dev": true, "license": "MIT", "dependencies": { - "workbox-core": "7.4.0", - "workbox-routing": "7.4.0", - "workbox-strategies": "7.4.0" + "workbox-core": "7.4.1", + "workbox-routing": "7.4.1", + "workbox-strategies": "7.4.1" } }, "node_modules/workbox-range-requests": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/workbox-range-requests/-/workbox-range-requests-7.4.0.tgz", - "integrity": "sha512-3Vq854ZNuP6Y0KZOQWLaLC9FfM7ZaE+iuQl4VhADXybwzr4z/sMmnLgTeUZLq5PaDlcJBxYXQ3U91V7dwAIfvw==", + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/workbox-range-requests/-/workbox-range-requests-7.4.1.tgz", + "integrity": "sha512-7i2oxAUE82gHdAJBCAQ04JzNOdRPqzuOzGfoUyJpFSmeqBNYGPrAH8GPoPjUQTfp+NycwrD2H68VtuF8qxv0vQ==", "dev": true, "license": "MIT", "dependencies": { - "workbox-core": "7.4.0" + "workbox-core": "7.4.1" } }, "node_modules/workbox-recipes": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/workbox-recipes/-/workbox-recipes-7.4.0.tgz", - "integrity": "sha512-kOkWvsAn4H8GvAkwfJTbwINdv4voFoiE9hbezgB1sb/0NLyTG4rE7l6LvS8lLk5QIRIto+DjXLuAuG3Vmt3cxQ==", + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/workbox-recipes/-/workbox-recipes-7.4.1.tgz", + "integrity": "sha512-gnbVfmV4/TtmQaM4x9AtuXhcdstJsep3XMVeztOrQVPT+R6+6DeBjGTCQ7fFCXm+4GEHUA5VEBTyi5+4gWGeog==", "dev": true, "license": "MIT", "dependencies": { - "workbox-cacheable-response": "7.4.0", - "workbox-core": "7.4.0", - "workbox-expiration": "7.4.0", - "workbox-precaching": "7.4.0", - "workbox-routing": "7.4.0", - "workbox-strategies": "7.4.0" + "workbox-cacheable-response": "7.4.1", + "workbox-core": "7.4.1", + "workbox-expiration": "7.4.1", + "workbox-precaching": "7.4.1", + "workbox-routing": "7.4.1", + "workbox-strategies": "7.4.1" } }, "node_modules/workbox-routing": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/workbox-routing/-/workbox-routing-7.4.0.tgz", - "integrity": "sha512-C/ooj5uBWYAhAqwmU8HYQJdOjjDKBp9MzTQ+otpMmd+q0eF59K+NuXUek34wbL0RFrIXe/KKT+tUWcZcBqxbHQ==", + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/workbox-routing/-/workbox-routing-7.4.1.tgz", + "integrity": "sha512-yubJGErZOusuidAenaL5ypfhQOa7urxP/f8E0ws7FPb4039RiWXUWBAyUkmUoOL/BcQGen3h0J8872d51IYxtA==", "dev": true, "license": "MIT", "dependencies": { - "workbox-core": "7.4.0" + "workbox-core": "7.4.1" } }, "node_modules/workbox-strategies": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/workbox-strategies/-/workbox-strategies-7.4.0.tgz", - "integrity": "sha512-T4hVqIi5A4mHi92+5EppMX3cLaVywDp8nsyUgJhOZxcfSV/eQofcOA6/EMo5rnTNmNTpw0rUgjAI6LaVullPpg==", + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/workbox-strategies/-/workbox-strategies-7.4.1.tgz", + "integrity": "sha512-GZxpaw9NbmOelj7667uZ2kpk5BFpOGbO4X0qjwh5ls8XQ8C+Lha5LQchTiUzsTFSS+NlUpftYAyOVXvQUrcqOQ==", "dev": true, "license": "MIT", "dependencies": { - "workbox-core": "7.4.0" + "workbox-core": "7.4.1" } }, "node_modules/workbox-streams": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/workbox-streams/-/workbox-streams-7.4.0.tgz", - "integrity": "sha512-QHPBQrey7hQbnTs5GrEVoWz7RhHJXnPT+12qqWM378orDMo5VMJLCkCM1cnCk+8Eq92lccx/VgRZ7WAzZWbSLg==", + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/workbox-streams/-/workbox-streams-7.4.1.tgz", + "integrity": "sha512-HWWtraKUbJknd9kgqGcpQ3G114HOPYvqs8HaJMDs2ebLNAimDkVDaWfAXE6Ybl+m8U6KsCE6pWyLYuigWmnAXw==", "dev": true, "license": "MIT", "dependencies": { - "workbox-core": "7.4.0", - "workbox-routing": "7.4.0" + "workbox-core": "7.4.1", + "workbox-routing": "7.4.1" } }, "node_modules/workbox-sw": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/workbox-sw/-/workbox-sw-7.4.0.tgz", - "integrity": "sha512-ltU+Kr3qWR6BtbdlMnCjobZKzeV1hN+S6UvDywBrwM19TTyqA03X66dzw1tEIdJvQ4lYKkBFox6IAEhoSEZ8Xw==", + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/workbox-sw/-/workbox-sw-7.4.1.tgz", + "integrity": "sha512-fez5f2DUlDJWTFYkCWQpY10N8gtztd849NswCbVFk0QlcSM4HT5A8x4g4ii650yem4I8tHY0R7JZahwp3ltIPw==", "dev": true, "license": "MIT" }, "node_modules/workbox-window": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/workbox-window/-/workbox-window-7.4.0.tgz", - "integrity": "sha512-/bIYdBLAVsNR3v7gYGaV4pQW3M3kEPx5E8vDxGvxo6khTrGtSSCS7QiFKv9ogzBgZiy0OXLP9zO28U/1nF1mfw==", + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/workbox-window/-/workbox-window-7.4.1.tgz", + "integrity": "sha512-notZDH2u8VXaqyuD7xaqIfEFi6SRM4SUSd7ewe9PDsVqADuepxX2ZMY3uvuZGxzY5ZOsGC/vD3A/3smFtJt4/A==", "dev": true, "license": "MIT", "dependencies": { "@types/trusted-types": "^2.0.2", - "workbox-core": "7.4.0" + "workbox-core": "7.4.1" } }, "node_modules/wrap-ansi": { @@ -44135,16 +44080,6 @@ "keyv": "^5.3.4" } }, - "packages/api/node_modules/@types/node": { - "version": "24.12.4", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.12.4.tgz", - "integrity": "sha512-GUUEShf+PBCGW2KaXwcIt3Yk+e3pkKwWKb9GSyM9WQVE+ep2jzmHdGsHzu4wgcZy5fN9FBdVzjpBQsYlpfpgLA==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~7.16.0" - } - }, "packages/api/node_modules/rimraf": { "version": "6.1.3", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-6.1.3.tgz", @@ -44165,13 +44100,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "packages/api/node_modules/undici-types": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", - "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", - "dev": true, - "license": "MIT" - }, "packages/client": { "name": "@librechat/client", "version": "0.4.60", @@ -44686,39 +44614,6 @@ "@tanstack/react-query": "^4.28.0" } }, - "packages/data-provider/node_modules/@rollup/plugin-terser": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-1.0.0.tgz", - "integrity": "sha512-FnCxhTBx6bMOYQrar6C8h3scPt8/JwIzw3+AJ2K++6guogH5fYaIFia+zZuhqv0eo1RN7W1Pz630SyvLbDjhtQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "serialize-javascript": "^7.0.3", - "smob": "^1.0.0", - "terser": "^5.17.4" - }, - "engines": { - "node": ">=20.0.0" - }, - "peerDependencies": { - "rollup": "^2.0.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } - }, - "packages/data-provider/node_modules/@types/node": { - "version": "24.12.4", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.12.4.tgz", - "integrity": "sha512-GUUEShf+PBCGW2KaXwcIt3Yk+e3pkKwWKb9GSyM9WQVE+ep2jzmHdGsHzu4wgcZy5fN9FBdVzjpBQsYlpfpgLA==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~7.16.0" - } - }, "packages/data-provider/node_modules/rimraf": { "version": "6.1.3", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-6.1.3.tgz", @@ -44739,13 +44634,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "packages/data-provider/node_modules/undici-types": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", - "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", - "dev": true, - "license": "MIT" - }, "packages/data-schemas": { "name": "@librechat/data-schemas", "version": "0.0.52", @@ -44783,39 +44671,6 @@ "winston-daily-rotate-file": "^5.0.0" } }, - "packages/data-schemas/node_modules/@rollup/plugin-terser": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-1.0.0.tgz", - "integrity": "sha512-FnCxhTBx6bMOYQrar6C8h3scPt8/JwIzw3+AJ2K++6guogH5fYaIFia+zZuhqv0eo1RN7W1Pz630SyvLbDjhtQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "serialize-javascript": "^7.0.3", - "smob": "^1.0.0", - "terser": "^5.17.4" - }, - "engines": { - "node": ">=20.0.0" - }, - "peerDependencies": { - "rollup": "^2.0.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } - }, - "packages/data-schemas/node_modules/@types/node": { - "version": "24.12.4", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.12.4.tgz", - "integrity": "sha512-GUUEShf+PBCGW2KaXwcIt3Yk+e3pkKwWKb9GSyM9WQVE+ep2jzmHdGsHzu4wgcZy5fN9FBdVzjpBQsYlpfpgLA==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~7.16.0" - } - }, "packages/data-schemas/node_modules/logform": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/logform/-/logform-2.7.0.tgz", @@ -44862,13 +44717,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "packages/data-schemas/node_modules/undici-types": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", - "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", - "dev": true, - "license": "MIT" - }, "packages/data-schemas/node_modules/winston": { "version": "3.17.0", "resolved": "https://registry.npmjs.org/winston/-/winston-3.17.0.tgz", From b483feae8bf9346b5e39e8b0860b1e9edaaef20b Mon Sep 17 00:00:00 2001 From: Danny Avila Date: Mon, 1 Jun 2026 18:00:30 -0400 Subject: [PATCH 05/14] =?UTF-8?q?=F0=9F=91=91=20refactor:=20Scope=20Role?= =?UTF-8?q?=20Cache=20Keys=20by=20Isolation=20Context=20(#13454)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ROLES cache is a single process-wide store, but role documents are per-tenant (unique index { name, tenantId }). getRoleByName checked the cache by role name BEFORE the tenant-scoped DB read, so a warm entry written under one tenant's context was served to another tenant — leaking that tenant's permission bits into the other's authorization decisions. Scope every ROLES cache key with scopedCacheKey(), which appends the active tenantId from the AsyncLocalStorage tenant context. It is a no-op when no tenant context is set (or under runAsSystem), so single-tenant deployments behave exactly as before. Adds role.cache.spec.ts with a real Map-backed cache: two tenants sharing a role name receive their own permissions, the cache key is tenant-scoped, the same-tenant fast path still avoids a second DB read, and single-tenant mode still uses the unscoped key. --- .../src/methods/role.cache.spec.ts | 141 ++++++++++++++++++ packages/data-schemas/src/methods/role.ts | 22 +-- 2 files changed, 154 insertions(+), 9 deletions(-) create mode 100644 packages/data-schemas/src/methods/role.cache.spec.ts diff --git a/packages/data-schemas/src/methods/role.cache.spec.ts b/packages/data-schemas/src/methods/role.cache.spec.ts new file mode 100644 index 000000000000..512c47ea8800 --- /dev/null +++ b/packages/data-schemas/src/methods/role.cache.spec.ts @@ -0,0 +1,141 @@ +import mongoose from 'mongoose'; +import { MongoMemoryServer } from 'mongodb-memory-server'; +import { PermissionTypes, Permissions } from 'librechat-data-provider'; +import type { IRole } from '..'; +import { createRoleMethods } from './role'; +import { createModels } from '../models'; +import { tenantStorage } from '../config/tenantContext'; + +jest.mock('~/config/winston', () => ({ + error: jest.fn(), + warn: jest.fn(), + info: jest.fn(), + debug: jest.fn(), +})); + +/** + * Real Map-backed cache. A jest.fn mock can only assert which key was passed; + * a real store reproduces the actual collision: when two tenants write under the + * same key, the second read serves the first tenant's value. + */ +function createMapCache() { + const store = new Map(); + return { + store, + get: async (k: string): Promise => store.get(k), + set: async (k: string, v: unknown): Promise => { + store.set(k, v); + }, + del: async (k: string): Promise => { + store.delete(k); + }, + }; +} + +const TENANT_A = 'tenant-aaaaaaaaaaaaaaaaaaaa'; +const TENANT_B = 'tenant-bbbbbbbbbbbbbbbbbbbb'; +const ROLE_NAME = 'EDITOR'; + +let mongoServer: MongoMemoryServer; +let Role: mongoose.Model; +let cache: ReturnType; +let getRoleByName: ReturnType['getRoleByName']; + +function runAs(tenantId: string, fn: () => Promise): Promise { + return tenantStorage.run({ tenantId }, fn); +} + +function usePromptsPermission(role: IRole | null | undefined): boolean | undefined { + const permissions = (role as unknown as { permissions?: Record> }) + ?.permissions; + return permissions?.[PermissionTypes.PROMPTS]?.[Permissions.USE]; +} + +async function seedRole(tenantId: string, useValue: boolean): Promise { + await runAs(tenantId, async () => { + await new Role({ + name: ROLE_NAME, + permissions: { [PermissionTypes.PROMPTS]: { [Permissions.USE]: useValue } }, + }).save(); + }); +} + +beforeAll(async () => { + mongoServer = await MongoMemoryServer.create(); + await mongoose.connect(mongoServer.getUri()); + createModels(mongoose); + Role = mongoose.models.Role as mongoose.Model; +}); + +afterAll(async () => { + await mongoose.disconnect(); + await mongoServer.stop(); +}); + +beforeEach(async () => { + await Role.deleteMany({}); + cache = createMapCache(); + const methods = createRoleMethods(mongoose, { getCache: () => cache }); + getRoleByName = methods.getRoleByName; +}); + +describe('getRoleByName cache is scoped to the active tenant', () => { + it('does not serve one tenant a cached role belonging to another tenant', async () => { + await seedRole(TENANT_A, true); + await seedRole(TENANT_B, false); + + const roleA = await runAs(TENANT_A, () => getRoleByName(ROLE_NAME)); + expect(usePromptsPermission(roleA)).toBe(true); + expect(cache.store.size).toBeGreaterThan(0); + + const roleB = await runAs(TENANT_B, () => getRoleByName(ROLE_NAME)); + expect(usePromptsPermission(roleB)).toBe(false); + + const roleAAgain = await runAs(TENANT_A, () => getRoleByName(ROLE_NAME)); + expect(usePromptsPermission(roleAAgain)).toBe(true); + }); + + it('appends the tenant id to the cache key', async () => { + await seedRole(TENANT_A, true); + await seedRole(TENANT_B, false); + + await runAs(TENANT_A, () => getRoleByName(ROLE_NAME)); + await runAs(TENANT_B, () => getRoleByName(ROLE_NAME)); + + expect(cache.store.has(`${ROLE_NAME}:${TENANT_A}`)).toBe(true); + expect(cache.store.has(`${ROLE_NAME}:${TENANT_B}`)).toBe(true); + expect(cache.store.has(ROLE_NAME)).toBe(false); + }); + + it('serves the cached value within the same tenant without a second DB read', async () => { + await seedRole(TENANT_A, true); + + const first = await runAs(TENANT_A, () => getRoleByName(ROLE_NAME)); + expect(usePromptsPermission(first)).toBe(true); + + const findOneSpy = jest.spyOn(Role, 'findOne'); + const second = await runAs(TENANT_A, () => getRoleByName(ROLE_NAME)); + expect(usePromptsPermission(second)).toBe(true); + expect(findOneSpy).not.toHaveBeenCalled(); + findOneSpy.mockRestore(); + }); + + it('uses the unscoped key when no tenant context is active (single-tenant)', async () => { + const previousDefault = process.env.DEFAULT_TENANT_ID; + delete process.env.DEFAULT_TENANT_ID; + try { + await seedRole(TENANT_A, true); + + const role = await getRoleByName(ROLE_NAME); + expect(usePromptsPermission(role)).toBe(true); + expect(cache.store.has(ROLE_NAME)).toBe(true); + expect(cache.store.has(`${ROLE_NAME}:${TENANT_A}`)).toBe(false); + } finally { + if (previousDefault === undefined) { + delete process.env.DEFAULT_TENANT_ID; + } else { + process.env.DEFAULT_TENANT_ID = previousDefault; + } + } + }); +}); diff --git a/packages/data-schemas/src/methods/role.ts b/packages/data-schemas/src/methods/role.ts index f0ffdb1700b3..ab3cce196f66 100644 --- a/packages/data-schemas/src/methods/role.ts +++ b/packages/data-schemas/src/methods/role.ts @@ -7,6 +7,7 @@ import { } from 'librechat-data-provider'; import type { Model } from 'mongoose'; import type { IRole, IUser } from '~/types'; +import { scopedCacheKey } from '~/config/tenantContext'; import logger from '~/config/winston'; const systemRoleValues = new Set(Object.values(SystemRoles)); @@ -94,7 +95,7 @@ export function createRoleMethods(mongoose: typeof import('mongoose'), deps: Rol const cache = deps.getCache?.(CacheKeys.ROLES); try { if (cache) { - const cachedRole = await cache.get(roleName); + const cachedRole = await cache.get(scopedCacheKey(roleName)); if (cachedRole) { return cachedRole as IRole; } @@ -109,12 +110,12 @@ export function createRoleMethods(mongoose: typeof import('mongoose'), deps: Rol if (!role && systemRoleValues.has(roleName)) { const newRole = await new Role(roleDefaults[roleName as keyof typeof roleDefaults]).save(); if (cache) { - await cache.set(roleName, newRole); + await cache.set(scopedCacheKey(roleName), newRole); } return newRole.toObject() as IRole; } if (cache) { - await cache.set(roleName, role); + await cache.set(scopedCacheKey(roleName), role); } return role as unknown as IRole; } catch (error) { @@ -135,9 +136,12 @@ export function createRoleMethods(mongoose: typeof import('mongoose'), deps: Rol .exec(); if (cache) { if (updates.name && updates.name !== roleName) { - await Promise.all([cache.set(roleName, null), cache.set(updates.name, role)]); + await Promise.all([ + cache.set(scopedCacheKey(roleName), null), + cache.set(scopedCacheKey(updates.name), role), + ]); } else { - await cache.set(roleName, role); + await cache.set(scopedCacheKey(roleName), role); } } return role as unknown as IRole; @@ -296,7 +300,7 @@ export function createRoleMethods(mongoose: typeof import('mongoose'), deps: Rol const cache = deps.getCache?.(CacheKeys.ROLES); const updatedRole = await Role.findOne({ name: roleName }).select('-__v').lean().exec(); if (cache) { - await cache.set(roleName, updatedRole); + await cache.set(scopedCacheKey(roleName), updatedRole); } logger.info(`Updated role '${roleName}' and removed old schema fields`); @@ -366,7 +370,7 @@ export function createRoleMethods(mongoose: typeof import('mongoose'), deps: Rol const cache = deps.getCache?.(CacheKeys.ROLES); if (cache) { const updatedRole = await Role.findById(role._id).lean().exec(); - await cache.set(role.name, updatedRole); + await cache.set(scopedCacheKey(role.name), updatedRole); } migratedCount++; @@ -418,7 +422,7 @@ export function createRoleMethods(mongoose: typeof import('mongoose'), deps: Rol try { const cache = deps.getCache?.(CacheKeys.ROLES); if (cache) { - await cache.set(role.name, role.toObject()); + await cache.set(scopedCacheKey(role.name), role.toObject()); } } catch (cacheError) { logger.error(`[createRoleByName] cache set failed for "${role.name}":`, cacheError); @@ -454,7 +458,7 @@ export function createRoleMethods(mongoose: typeof import('mongoose'), deps: Rol // Setting null evicts the stale document. getRoleByName treats falsy cached // values as a miss and falls through to the DB, so this does not provide // negative caching — it only prevents serving the pre-deletion document. - await cache.set(roleName, null); + await cache.set(scopedCacheKey(roleName), null); } } catch (cacheError) { logger.error(`[deleteRoleByName] cache invalidation failed for "${roleName}":`, cacheError); From 983a33fbad1866a12c72e4efb7d212238aa06652 Mon Sep 17 00:00:00 2001 From: Danny Avila Date: Mon, 1 Jun 2026 18:00:53 -0400 Subject: [PATCH 06/14] =?UTF-8?q?=F0=9F=8E=9B=EF=B8=8F=20refactor:=20Scope?= =?UTF-8?q?=20App-Config=20Override=20Cache=20by=20Isolation=20Context=20(?= =?UTF-8?q?#13455)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit getAppConfig caches per-principal merged config overrides under a key built by overrideCacheKey(role, userId, tenantId). The key used the tenantId *argument* only — but callers that go through the tenant middleware (the common path) pass no explicit tenantId and rely on the AsyncLocalStorage tenant context. Those calls were keyed under the shared '__default__' bucket, so the DB query (correctly scoped to the ALS tenant by the Mongoose plugin) produced a merged config that was then cached and served to the next tenant resolving the same role/user — leaking model specs, endpoints, and interface flags across tenants. Fall back to getTenantId() before '__default__' so the cache key reflects the actual tenant scope (param or ALS). Tighten the strict-mode warning to fire only when there is genuinely no tenant anywhere (param nor ALS), since the ALS case is now scoped rather than defaulted. No-op for single-tenant deployments, where getTenantId() is undefined and the key stays '__default__'. Adds tests (real Map-backed cache) proving the ALS tenant scopes the key and that two tenants resolving the same role each get their own config with no cache collision. --- packages/api/src/app/service.spec.ts | 45 ++++++++++++++++++++++++++++ packages/api/src/app/service.ts | 17 ++++++----- 2 files changed, 55 insertions(+), 7 deletions(-) diff --git a/packages/api/src/app/service.spec.ts b/packages/api/src/app/service.spec.ts index b692aa6eb289..248d42dacd0d 100644 --- a/packages/api/src/app/service.spec.ts +++ b/packages/api/src/app/service.spec.ts @@ -327,6 +327,51 @@ describe('createAppConfigService', () => { expect(deps.getApplicableConfigs).toHaveBeenCalledWith([]); }); + + it('scopes the override cache key to the ALS tenant when no tenantId param is given', async () => { + const { tenantStorage } = jest.requireActual('@librechat/data-schemas'); + const deps = createDeps({ + getApplicableConfigs: jest + .fn() + .mockResolvedValue([{ priority: 10, overrides: { x: 1 }, isActive: true }]), + }); + const { getAppConfig } = createAppConfigService(deps); + + await tenantStorage.run({ tenantId: 'tenant-a' }, async () => + getAppConfig({ role: 'USER' }), + ); + + const overrideKey = [...deps._cache._store.keys()].find((k: string) => + k.includes('_OVERRIDE_:'), + ); + expect(overrideKey).toBe('app_config:_OVERRIDE_:tenant-a:USER'); + expect(overrideKey).not.toContain('__default__'); + }); + + it('does not serve one tenant a cached config built for another tenant', async () => { + const { tenantStorage, getTenantId } = jest.requireActual('@librechat/data-schemas'); + // Each tenant's DB overrides carry a marker derived from the active ALS tenant. + const deps = createDeps({ + getApplicableConfigs: jest + .fn() + .mockImplementation(async () => [ + { priority: 10, overrides: { whoami: getTenantId() }, isActive: true }, + ]), + }); + const { getAppConfig } = createAppConfigService(deps); + + const configA = (await tenantStorage.run({ tenantId: 'tenant-a' }, async () => + getAppConfig({ role: 'USER' }), + )) as TestConfig & { whoami?: string }; + const configB = (await tenantStorage.run({ tenantId: 'tenant-b' }, async () => + getAppConfig({ role: 'USER' }), + )) as TestConfig & { whoami?: string }; + + expect(configA.whoami).toBe('tenant-a'); + expect(configB.whoami).toBe('tenant-b'); + // A cache collision would short-circuit the second tenant's DB read. + expect(deps.getApplicableConfigs).toHaveBeenCalledTimes(2); + }); }); it('does not cache on buildPrincipals error — retries on next request', async () => { diff --git a/packages/api/src/app/service.ts b/packages/api/src/app/service.ts index 613c428fca77..658056503fc5 100644 --- a/packages/api/src/app/service.ts +++ b/packages/api/src/app/service.ts @@ -73,7 +73,10 @@ export function _resetOverrideStrictCache(): void { } function overrideCacheKey(role?: string, userId?: string, tenantId?: string): string { - const tenant = tenantId || '__default__'; + // Fall back to the ALS tenant context before `__default__`: callers that rely on the + // tenant middleware (the common path) pass no explicit tenantId, so without this the + // entry is keyed under the shared `__default__` bucket and leaks across tenants. + const tenant = tenantId || getTenantId() || '__default__'; if (userId && role) { return `_OVERRIDE_:${tenant}:${role}:${userId}`; } @@ -174,16 +177,16 @@ export function createAppConfigService(deps: AppConfigServiceDeps) { return baseConfig; } - // Strict-isolation + no tenant (param or ALS) = pathological path (middleware bypass or - // unauthenticated startup). Pre-tenant calls use baseOnly:true; admin calls carry tenantId. - // If ALS has a tenant, Mongoose scopes queries to that tenant's overrides — must fall through. - // Not cached: the cache key doesn't include ALS context, so a cached __default__ entry would - // be served to later ALS-scoped calls that share the same param-derived key. + // Strict isolation + no tenant anywhere (neither param nor ALS) is pathological: a + // middleware bypass or an unauthenticated startup call. Pre-tenant calls should use + // baseOnly:true and admin calls carry an explicit tenantId. Return the base config + // without caching it under the shared `__default__` bucket. When ALS has a tenant, + // overrideCacheKey scopes the key to it, so we fall through and cache per-tenant. if (principals.length === 0 && !tenantId && !getTenantId() && isStrictOverrideMode()) { return baseConfig; } - if (!tenantId && isStrictOverrideMode() && !_warnedNoTenantInStrictMode) { + if (!tenantId && !getTenantId() && isStrictOverrideMode() && !_warnedNoTenantInStrictMode) { _warnedNoTenantInStrictMode = true; logger.warn( '[getAppConfig] No tenantId in strict mode — falling back to __default__. ' + From 8120fc69cdb1b48fa21aac86a3b5fbc04dc8dcae Mon Sep 17 00:00:00 2001 From: Danny Avila Date: Mon, 1 Jun 2026 18:01:16 -0400 Subject: [PATCH 07/14] =?UTF-8?q?=F0=9F=AA=9D=20fix:=20Apply=20Isolation?= =?UTF-8?q?=20Plugin=20to=20Distinct=20Queries=20(#13457)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mongoose's distinct query operation was not in the tenant-isolation plugin's hooked-operation list, so .distinct() (and .find(...).distinct(field), whose op switches to 'distinct') ran unscoped — reading across all tenants. This affects the ACL resource lookups (findAccessibleResources, findPublicResourceIds — including PUBLIC 'shared-to-all' entries), agent category values, and random prompt categories. distinct IS a registerable query-middleware hook in Mongoose 8 (it is in queryOperations), so the fix is to register the existing queryMiddleware for it — one line. This keeps every call site as .distinct(), which is the established FerretDB-compatible pattern (getRandomPromptGroups was deliberately built on .distinct() rather than an aggregation stage for FerretDB support), and scopes all distinct queries systemically with the same SYSTEM-context bypass and strict-mode fail-closed behavior as the other operations. Adds distinct cases to the plugin spec (including the find().distinct() op switch and SYSTEM/no-context paths) plus behavioral tenant-isolation specs for the ACL and category lookups; verified all fail without the hook. --- .../src/methods/aclEntry.tenant.spec.ts | 114 ++++++++++++++++++ .../src/methods/agentCategory.tenant.spec.ts | 60 +++++++++ .../models/plugins/tenantIsolation.spec.ts | 29 +++++ .../src/models/plugins/tenantIsolation.ts | 1 + 4 files changed, 204 insertions(+) create mode 100644 packages/data-schemas/src/methods/aclEntry.tenant.spec.ts create mode 100644 packages/data-schemas/src/methods/agentCategory.tenant.spec.ts diff --git a/packages/data-schemas/src/methods/aclEntry.tenant.spec.ts b/packages/data-schemas/src/methods/aclEntry.tenant.spec.ts new file mode 100644 index 000000000000..a216ce9e6352 --- /dev/null +++ b/packages/data-schemas/src/methods/aclEntry.tenant.spec.ts @@ -0,0 +1,114 @@ +import mongoose from 'mongoose'; +import { MongoMemoryServer } from 'mongodb-memory-server'; +import { PrincipalType, PrincipalModel, PermissionBits } from 'librechat-data-provider'; +import type { IAclEntry } from '..'; +import { createAclEntryMethods } from './aclEntry'; +import { createModels } from '../models'; +import { tenantStorage } from '../config/tenantContext'; + +jest.mock('~/config/winston', () => ({ + error: jest.fn(), + warn: jest.fn(), + info: jest.fn(), + debug: jest.fn(), +})); + +const TENANT_A = 'tenant-aaaaaaaaaaaaaaaaaaaa'; +const TENANT_B = 'tenant-bbbbbbbbbbbbbbbbbbbb'; +const RESOURCE_TYPE = 'agent'; + +let mongoServer: MongoMemoryServer; +let AclEntry: mongoose.Model; +let methods: ReturnType; + +function runAs(tenantId: string, fn: () => Promise): Promise { + return tenantStorage.run({ tenantId }, fn); +} + +async function seedAcl(tenantId: string, doc: Record): Promise { + await runAs(tenantId, async () => { + await new AclEntry(doc).save(); + }); +} + +beforeAll(async () => { + mongoServer = await MongoMemoryServer.create(); + await mongoose.connect(mongoServer.getUri()); + createModels(mongoose); + AclEntry = mongoose.models.AclEntry as mongoose.Model; + methods = createAclEntryMethods(mongoose); +}); + +afterAll(async () => { + await mongoose.disconnect(); + await mongoServer.stop(); +}); + +beforeEach(async () => { + await AclEntry.deleteMany({}); +}); + +describe('AclEntry resource lookups are scoped to the active tenant', () => { + it('findAccessibleResources returns only the current tenant resources', async () => { + const principalId = new mongoose.Types.ObjectId(); + const resourceA = new mongoose.Types.ObjectId(); + const resourceB = new mongoose.Types.ObjectId(); + + await seedAcl(TENANT_A, { + principalType: PrincipalType.USER, + principalModel: PrincipalModel.USER, + principalId, + resourceType: RESOURCE_TYPE, + resourceId: resourceA, + permBits: PermissionBits.VIEW, + }); + await seedAcl(TENANT_B, { + principalType: PrincipalType.USER, + principalModel: PrincipalModel.USER, + principalId, + resourceType: RESOURCE_TYPE, + resourceId: resourceB, + permBits: PermissionBits.VIEW, + }); + + const principals = [{ principalType: PrincipalType.USER, principalId }]; + + const aResources = await runAs(TENANT_A, () => + methods.findAccessibleResources(principals, RESOURCE_TYPE, PermissionBits.VIEW), + ); + expect(aResources.map(String)).toEqual([String(resourceA)]); + + const bResources = await runAs(TENANT_B, () => + methods.findAccessibleResources(principals, RESOURCE_TYPE, PermissionBits.VIEW), + ); + expect(bResources.map(String)).toEqual([String(resourceB)]); + }); + + it('findPublicResourceIds returns only the current tenant public resources', async () => { + const publicA = new mongoose.Types.ObjectId(); + const publicB = new mongoose.Types.ObjectId(); + + await seedAcl(TENANT_A, { + principalType: PrincipalType.PUBLIC, + resourceType: RESOURCE_TYPE, + resourceId: publicA, + permBits: PermissionBits.VIEW, + }); + await seedAcl(TENANT_B, { + principalType: PrincipalType.PUBLIC, + resourceType: RESOURCE_TYPE, + resourceId: publicB, + permBits: PermissionBits.VIEW, + }); + + const aPublic = await runAs(TENANT_A, () => + methods.findPublicResourceIds(RESOURCE_TYPE, PermissionBits.VIEW), + ); + expect(aPublic.map(String)).toEqual([String(publicA)]); + + const bPublic = await runAs(TENANT_B, () => + methods.findPublicResourceIds(RESOURCE_TYPE, PermissionBits.VIEW), + ); + expect(bPublic.map(String)).toEqual([String(publicB)]); + }); +}); diff --git a/packages/data-schemas/src/methods/agentCategory.tenant.spec.ts b/packages/data-schemas/src/methods/agentCategory.tenant.spec.ts new file mode 100644 index 000000000000..cccae345b91c --- /dev/null +++ b/packages/data-schemas/src/methods/agentCategory.tenant.spec.ts @@ -0,0 +1,60 @@ +import mongoose from 'mongoose'; +import { MongoMemoryServer } from 'mongodb-memory-server'; +import type { IAgentCategory } from '..'; +import { createAgentCategoryMethods } from './agentCategory'; +import { createModels } from '../models'; +import { tenantStorage } from '../config/tenantContext'; + +jest.mock('~/config/winston', () => ({ + error: jest.fn(), + warn: jest.fn(), + info: jest.fn(), + debug: jest.fn(), +})); + +const TENANT_A = 'tenant-aaaaaaaaaaaaaaaaaaaa'; +const TENANT_B = 'tenant-bbbbbbbbbbbbbbbbbbbb'; + +let mongoServer: MongoMemoryServer; +let AgentCategory: mongoose.Model; +let methods: ReturnType; + +function runAs(tenantId: string, fn: () => Promise): Promise { + return tenantStorage.run({ tenantId }, fn); +} + +async function seedCategory(tenantId: string, value: string): Promise { + await runAs(tenantId, async () => { + await new AgentCategory({ value, label: value, isActive: true }).save(); + }); +} + +beforeAll(async () => { + mongoServer = await MongoMemoryServer.create(); + await mongoose.connect(mongoServer.getUri()); + createModels(mongoose); + AgentCategory = mongoose.models.AgentCategory as mongoose.Model; + methods = createAgentCategoryMethods(mongoose); +}); + +afterAll(async () => { + await mongoose.disconnect(); + await mongoServer.stop(); +}); + +beforeEach(async () => { + await AgentCategory.deleteMany({}); +}); + +describe('getValidCategoryValues is scoped to the active tenant', () => { + it('returns only the current tenant category values', async () => { + await seedCategory(TENANT_A, 'alpha'); + await seedCategory(TENANT_B, 'beta'); + + const aValues = await runAs(TENANT_A, () => methods.getValidCategoryValues()); + expect(aValues).toEqual(['alpha']); + + const bValues = await runAs(TENANT_B, () => methods.getValidCategoryValues()); + expect(bValues).toEqual(['beta']); + }); +}); diff --git a/packages/data-schemas/src/models/plugins/tenantIsolation.spec.ts b/packages/data-schemas/src/models/plugins/tenantIsolation.spec.ts index 82e74d2ceacd..ba65e17be8e2 100644 --- a/packages/data-schemas/src/models/plugins/tenantIsolation.spec.ts +++ b/packages/data-schemas/src/models/plugins/tenantIsolation.spec.ts @@ -154,6 +154,35 @@ describe('applyTenantIsolation', () => { const tenantADoc = await TestModel.findOne({ tenantId: 'tenant-a' }).lean(); expect(tenantADoc!.name).toBe('updated'); }); + + it('injects tenantId filter into distinct', async () => { + const names = await tenantStorage.run({ tenantId: 'tenant-a' }, async () => + TestModel.distinct('name'), + ); + + expect(names).toEqual(['tenant-a-doc']); + }); + + it('injects tenantId filter into find().distinct() (op switches to distinct)', async () => { + const names = await tenantStorage.run({ tenantId: 'tenant-b' }, async () => + TestModel.find().distinct('name'), + ); + + expect(names).toEqual(['tenant-b-doc']); + }); + + it('does not scope distinct when context is absent (non-strict)', async () => { + const names = await TestModel.distinct('name'); + expect(names.sort()).toEqual(['no-tenant-doc', 'tenant-a-doc', 'tenant-b-doc']); + }); + + it('bypasses distinct filter for SYSTEM_TENANT_ID', async () => { + const names = await tenantStorage.run({ tenantId: SYSTEM_TENANT_ID }, async () => + TestModel.distinct('name'), + ); + + expect(names).toHaveLength(3); + }); }); describe('aggregate filtering', () => { diff --git a/packages/data-schemas/src/models/plugins/tenantIsolation.ts b/packages/data-schemas/src/models/plugins/tenantIsolation.ts index 06f8e035fb2c..14506103452a 100644 --- a/packages/data-schemas/src/models/plugins/tenantIsolation.ts +++ b/packages/data-schemas/src/models/plugins/tenantIsolation.ts @@ -137,6 +137,7 @@ export function applyTenantIsolation(schema: Schema): void { schema.pre('find', queryMiddleware); schema.pre('findOne', queryMiddleware); + schema.pre('distinct', queryMiddleware); schema.pre('findOneAndUpdate', queryMiddleware); schema.pre('findOneAndDelete', queryMiddleware); schema.pre('findOneAndReplace', queryMiddleware); From 547b28455abdee2611bccd7fb95559734dd6d860 Mon Sep 17 00:00:00 2001 From: Danny Avila Date: Mon, 1 Jun 2026 18:02:02 -0400 Subject: [PATCH 08/14] =?UTF-8?q?=F0=9F=97=BC=20ci:=20Guard=20Scoped=20Mod?= =?UTF-8?q?el=20Applies=20the=20Isolation=20Plugin=20(#13458)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a coverage test that enumerates all registered models and asserts every schema with a tenantId field has the tenant-isolation plugin applied (detected via the global Symbol.for('librechat:tenantIsolation') marker the plugin sets), with a single documented allowlist entry — SystemGrant, which scopes tenancy manually. A future model that ships a tenantId field without the plugin (the exact gap that lets data leak across tenants) now fails CI instead of shipping silently. --- .../plugins/tenantIsolation.coverage.spec.ts | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 packages/data-schemas/src/models/plugins/tenantIsolation.coverage.spec.ts diff --git a/packages/data-schemas/src/models/plugins/tenantIsolation.coverage.spec.ts b/packages/data-schemas/src/models/plugins/tenantIsolation.coverage.spec.ts new file mode 100644 index 000000000000..13b7af41c288 --- /dev/null +++ b/packages/data-schemas/src/models/plugins/tenantIsolation.coverage.spec.ts @@ -0,0 +1,52 @@ +import mongoose from 'mongoose'; +import { createModels } from '../index'; + +/** + * Global symbol set by applyTenantIsolation() on every schema it processes. + * Recreated here via Symbol.for (the global registry) so the guard can detect + * plugin application without the plugin exporting anything. + */ +const TENANT_ISOLATION_APPLIED = Symbol.for('librechat:tenantIsolation'); + +/** + * Models that carry a `tenantId` field but intentionally do NOT use the + * tenant-isolation plugin. SystemGrant scopes tenancy manually inside its + * methods (see models/systemGrant). Adding an entry here must be a deliberate, + * reviewed decision — that is the whole point of this guard. + */ +const MANUAL_TENANT_SCOPING = new Set(['SystemGrant']); + +function isPluginApplied(schema: mongoose.Schema): boolean { + return (schema as unknown as { [key: symbol]: boolean })[TENANT_ISOLATION_APPLIED] === true; +} + +describe('tenant-isolation plugin coverage', () => { + beforeAll(() => { + createModels(mongoose); + }); + + it('applies the tenant-isolation plugin to every model that has a tenantId field', () => { + const missing: string[] = []; + + for (const [name, model] of Object.entries(mongoose.models)) { + const hasTenantId = Boolean(model.schema.path('tenantId')); + if (!hasTenantId || MANUAL_TENANT_SCOPING.has(name)) { + continue; + } + if (!isPluginApplied(model.schema)) { + missing.push(name); + } + } + + expect(missing).toEqual([]); + }); + + it('keeps the manual-scoping allowlist accurate (tenantId field, no plugin)', () => { + for (const name of MANUAL_TENANT_SCOPING) { + const model = mongoose.models[name]; + expect(model).toBeDefined(); + expect(Boolean(model.schema.path('tenantId'))).toBe(true); + expect(isPluginApplied(model.schema)).toBe(false); + } + }); +}); From 730878bc5a1ef5f39e4e01b98aca864e2f334325 Mon Sep 17 00:00:00 2001 From: Marco Beretta <81851188+berry-13@users.noreply.github.com> Date: Tue, 2 Jun 2026 00:14:12 +0200 Subject: [PATCH 09/14] =?UTF-8?q?=F0=9F=94=90=20feat:=20Use=20`SecretInput?= =?UTF-8?q?`=20for=20Sensitive=20Fields=20(#12955)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: use SecretInput for sensitive fields * fix: align auth SecretInput styles * chore: remove unused password i18n keys * fix: align SecretInput controls * fix: use SecretInput for dynamic credentials * fix: reveal SecretInput controls on hover * fix: align SecretInput eye icon and modernize controls The wrapper was a flex container, so passing 'mb-2' on the input made it contribute its margin to the wrapper's cross-axis size — the controls overlay spanned the inflated height and centered the toggle 4px below the input's true center. Switching the wrapper to a plain relative block collapses height back to the input. Also tightens the toggle/copy buttons (size-7 rounded-md with hover:bg-surface-hover) and adds a focus ring on the input. Auth pages still override className/buttonClassName so login/register styling is unchanged. * fix: remove focus ring from SecretInput * fix: keep green focus border on auth secret inputs SecretInput's modernized default uses focus-visible:border-border-heavy and hover:border-border-medium, which Tailwind emits after the auth pages' focus: rules and overrides them. Auth pages now also declare focus-visible:border-green-500 and hover:border-border-light so cn()/twMerge resolves them as the winners when classes are concatenated. * feat: add optional sensitive flag to MCP customUserVars Dynamic MCP credential fields all rendered as masked SecretInputs, which also hid non-secret setup values like usernames, project keys, and URLs. Add an optional `sensitive` flag to customUserVars and the plugin auth config. It defaults to masked when omitted, so existing configs keep the safe-by-default behavior; set `sensitive: false` to render a field as plain text. The flag is display-only — values remain encrypted at rest. --- api/server/controllers/mcp.js | 1 + client/src/common/types.ts | 2 + client/src/components/Auth/LoginForm.tsx | 31 +++---- client/src/components/Auth/Registration.tsx | 88 ++++++++++++------- client/src/components/Auth/ResetPassword.tsx | 38 ++++---- .../components/Chat/Input/MCPConfigDialog.tsx | 39 +++++--- .../Input/SetKeyDialog/CustomEndpoint.tsx | 1 + .../Input/SetKeyDialog/GoogleConfig.tsx | 1 + .../Input/SetKeyDialog/InputWithLabel.tsx | 54 +++++++++--- .../Input/SetKeyDialog/OpenAIConfig.tsx | 2 + .../Input/SetKeyDialog/OtherConfig.tsx | 1 + .../components/MCP/CustomUserVarsSection.tsx | 56 ++++++------ .../__tests__/CustomUserVarsSection.test.tsx | 19 +++- .../Account/TwoFactorPhases/QRPhase.tsx | 36 +++----- .../Nav/SettingsTabs/Data/AgentApiKeys.tsx | 46 +++------- .../Plugins/Store/PluginAuthForm.tsx | 65 ++++++++------ .../Store/__tests__/PluginAuthForm.spec.tsx | 25 +++++- .../SidePanel/Agents/Search/InputSection.tsx | 73 +++++---------- .../SidePanel/Builder/ActionsAuth.tsx | 39 +++++--- .../MCPServerDialog/sections/AuthSection.tsx | 15 +++- client/src/hooks/MCP/useMCPServerManager.ts | 2 + client/src/locales/en/translation.json | 2 - .../client/src/components/SecretInput.tsx | 52 +++++++++-- packages/data-provider/src/mcp.ts | 6 ++ packages/data-provider/src/schemas.ts | 2 + 25 files changed, 415 insertions(+), 281 deletions(-) diff --git a/api/server/controllers/mcp.js b/api/server/controllers/mcp.js index a50680f3d16f..d58e1feacf77 100644 --- a/api/server/controllers/mcp.js +++ b/api/server/controllers/mcp.js @@ -146,6 +146,7 @@ const getMCPTools = async (req, res) => { authField: key, label: value.title || key, description: value.description || '', + sensitive: value.sensitive, })); server.authenticated = false; } diff --git a/client/src/common/types.ts b/client/src/common/types.ts index d8f86f23f43b..7be7bef749af 100644 --- a/client/src/common/types.ts +++ b/client/src/common/types.ts @@ -16,6 +16,8 @@ export function isEphemeralAgent(agentId: string | null | undefined): boolean { export interface ConfigFieldDetail { title: string; description: string; + /** Whether the field holds a secret and should be masked (defaults to masked when omitted). */ + sensitive?: boolean; } export type CodeBarProps = { diff --git a/client/src/components/Auth/LoginForm.tsx b/client/src/components/Auth/LoginForm.tsx index c51c2002e32e..3d0a2528d5fd 100644 --- a/client/src/components/Auth/LoginForm.tsx +++ b/client/src/components/Auth/LoginForm.tsx @@ -1,7 +1,7 @@ import React, { useState, useEffect, useContext } from 'react'; import { useForm } from 'react-hook-form'; import { Turnstile } from '@marsidev/react-turnstile'; -import { ThemeContext, Spinner, Button, isDark } from '@librechat/client'; +import { ThemeContext, SecretInput, Spinner, Button, isDark } from '@librechat/client'; import type { TLoginUser, TStartupConfig } from 'librechat-data-provider'; import type { TAuthContext } from '~/common'; import { useResendVerificationEmail, useGetStartupConfig } from '~/data-provider'; @@ -31,6 +31,13 @@ const LoginForm: React.FC = ({ onSubmit, startupConfig, error, const useUsernameLogin = config?.ldap?.username; const validTheme = isDark(theme) ? 'dark' : 'light'; const requireCaptcha = Boolean(startupConfig.turnstile?.siteKey); + const authInputClassName = + 'webkit-dark-styles transition-color peer w-full rounded-2xl border border-border-light bg-surface-primary px-3.5 pb-2.5 pt-3 text-text-primary duration-200 hover:border-border-light focus:border-green-500 focus:outline-none focus-visible:border-green-500'; + const authSecretInputClassName = `${authInputClassName} h-auto pr-12`; + const authLabelClassName = + 'absolute start-3 top-1.5 z-10 origin-[0] -translate-y-4 scale-75 transform bg-surface-primary px-2 text-sm text-text-secondary-alt duration-200 peer-placeholder-shown:top-1/2 peer-placeholder-shown:-translate-y-1/2 peer-placeholder-shown:scale-100 peer-focus:top-1.5 peer-focus:-translate-y-4 peer-focus:scale-75 peer-focus:px-2 peer-focus:text-green-600 dark:peer-focus:text-green-500 rtl:peer-focus:left-auto rtl:peer-focus:translate-x-1/4'; + const authSecretButtonClassName = + 'size-9 rounded-xl text-text-secondary-alt hover:bg-transparent hover:text-text-primary'; useEffect(() => { if (error && error.includes('422') && !showResendLink) { @@ -102,13 +109,10 @@ const LoginForm: React.FC = ({ onSubmit, startupConfig, error, : (value) => validateEmail(value, localize('com_auth_email_pattern')), })} aria-invalid={!!errors.email} - className="webkit-dark-styles transition-color peer w-full rounded-2xl border border-border-light bg-surface-primary px-3.5 pb-2.5 pt-3 text-text-primary duration-200 focus:border-green-500 focus:outline-none" + className={authInputClassName} placeholder=" " /> -