diff --git a/.github/.nvmrc b/.github/.nvmrc index 32f8c50de0..d845d9d88d 100644 --- a/.github/.nvmrc +++ b/.github/.nvmrc @@ -1 +1 @@ -24.13.1 +24.14.0 diff --git a/.github/workflows/auto-close.yml b/.github/workflows/auto-close.yml new file mode 100644 index 0000000000..60371d1abb --- /dev/null +++ b/.github/workflows/auto-close.yml @@ -0,0 +1,143 @@ +name: Auto-close PRs + +on: + pull_request_target: # zizmor: ignore[dangerous-triggers] + types: [opened, edited, labeled] + +permissions: {} + +jobs: + parse_template: + runs-on: ubuntu-latest + if: ${{ github.event.action != 'labeled' && github.event.pull_request.head.repo.fork == true }} + permissions: + contents: read + outputs: + uses_template: ${{ steps.check.outputs.uses_template }} + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + sparse-checkout: .github/pull_request_template.md + sparse-checkout-cone-mode: false + persist-credentials: false + + - name: Check required sections + id: check + env: + BODY: ${{ github.event.pull_request.body }} + run: | + OK=true + while IFS= read -r header; do + printf '%s\n' "$BODY" | grep -qF "$header" || OK=false + done < <(sed '//d' .github/pull_request_template.md | grep "^## ") + echo "uses_template=$OK" >> "$GITHUB_OUTPUT" + + close_template: + runs-on: ubuntu-latest + needs: parse_template + if: ${{ needs.parse_template.outputs.uses_template == 'false' && github.event.pull_request.state != 'closed' }} + permissions: + pull-requests: write + steps: + - name: Comment and close + env: + GH_TOKEN: ${{ github.token }} + NODE_ID: ${{ github.event.pull_request.node_id }} + run: | + gh api graphql \ + -f prId="$NODE_ID" \ + -f body="This PR has been automatically closed as the description doesn't follow our template. After you edit it to match the template, the PR will automatically be reopened." \ + -f query=' + mutation CommentAndClosePR($prId: ID!, $body: String!) { + addComment(input: { + subjectId: $prId, + body: $body + }) { + __typename + } + closePullRequest(input: { + pullRequestId: $prId + }) { + __typename + } + }' + + - name: Add label + env: + GH_TOKEN: ${{ github.token }} + PR_NUMBER: ${{ github.event.pull_request.number }} + run: gh pr edit "$PR_NUMBER" --repo "${{ github.repository }}" --add-label "auto-closed:template" + + close_llm: + runs-on: ubuntu-latest + if: ${{ github.event.action == 'labeled' && github.event.label.name == 'auto-closed:llm' }} + permissions: + pull-requests: write + steps: + - name: Comment and close + env: + GH_TOKEN: ${{ github.token }} + NODE_ID: ${{ github.event.pull_request.node_id }} + run: | + gh api graphql \ + -f prId="$NODE_ID" \ + -f body="Thank you for your interest in contributing to Immich! Unfortunately this PR looks like it was generated using an LLM. As noted in our [CONTRIBUTING.md](https://github.com/immich-app/immich/blob/main/CONTRIBUTING.md#use-of-generative-ai), we request that you don't use LLMs to generate PRs as those are not a good use of maintainer time." \ + -f query=' + mutation CommentAndClosePR($prId: ID!, $body: String!) { + addComment(input: { + subjectId: $prId, + body: $body + }) { + __typename + } + closePullRequest(input: { + pullRequestId: $prId + }) { + __typename + } + }' + + reopen: + runs-on: ubuntu-latest + needs: parse_template + if: >- + ${{ + needs.parse_template.outputs.uses_template == 'true' + && github.event.pull_request.state == 'closed' + && contains(github.event.pull_request.labels.*.name, 'auto-closed:template') + }} + permissions: + pull-requests: write + steps: + - name: Remove template label + env: + GH_TOKEN: ${{ github.token }} + PR_NUMBER: ${{ github.event.pull_request.number }} + run: gh pr edit "$PR_NUMBER" --repo "${{ github.repository }}" --remove-label "auto-closed:template" || true + + - name: Check for remaining auto-closed labels + id: check_labels + env: + GH_TOKEN: ${{ github.token }} + PR_NUMBER: ${{ github.event.pull_request.number }} + run: | + REMAINING=$(gh pr view "$PR_NUMBER" --repo "${{ github.repository }}" --json labels \ + --jq '[.labels[].name | select(startswith("auto-closed:"))] | length') + echo "remaining=$REMAINING" >> "$GITHUB_OUTPUT" + + - name: Reopen PR + if: ${{ steps.check_labels.outputs.remaining == '0' }} + env: + GH_TOKEN: ${{ github.token }} + NODE_ID: ${{ github.event.pull_request.node_id }} + run: | + gh api graphql \ + -f prId="$NODE_ID" \ + -f query=' + mutation ReopenPR($prId: ID!) { + reopenPullRequest(input: { + pullRequestId: $prId + }) { + __typename + } + }' diff --git a/.github/workflows/build-mobile.yml b/.github/workflows/build-mobile.yml index 44645c1e1b..deda195b84 100644 --- a/.github/workflows/build-mobile.yml +++ b/.github/workflows/build-mobile.yml @@ -51,14 +51,14 @@ jobs: should_run: ${{ steps.check.outputs.should_run }} steps: - id: token - uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1 + uses: immich-app/devtools/actions/create-workflow-token@57ff6ebfd507b045514442683ff06ff1b2f6efbd # create-workflow-token-action-v1.0.2 with: app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }} private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }} - name: Check what should run id: check - uses: immich-app/devtools/actions/pre-job@eed0f8b8165ffcb951f2ba854b2dd031935e1d73 # pre-job-action-v2.0.2 + uses: immich-app/devtools/actions/pre-job@f50e3b600b6ac1763ddb8f3dfc69093512b967a1 # pre-job-action-v2.0.3 with: github-token: ${{ steps.token.outputs.token }} filters: | @@ -79,7 +79,7 @@ jobs: steps: - id: token - uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1 + uses: immich-app/devtools/actions/create-workflow-token@57ff6ebfd507b045514442683ff06ff1b2f6efbd # create-workflow-token-action-v1.0.2 with: app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }} private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }} @@ -103,7 +103,7 @@ jobs: - name: Restore Gradle Cache id: cache-gradle-restore - uses: actions/cache/restore@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3 + uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 with: path: | ~/.gradle/caches @@ -114,7 +114,7 @@ jobs: key: build-mobile-gradle-${{ runner.os }}-main - name: Setup Flutter SDK - uses: subosito/flutter-action@fd55f4c5af5b953cc57a2be44cb082c8f6635e8e # v2.21.0 + uses: subosito/flutter-action@0ca7a949e71ae44c8e688a51c5e7e93b2c87e295 # v2.22.0 with: channel: 'stable' flutter-version-file: ./mobile/pubspec.yaml @@ -153,14 +153,14 @@ jobs: fi - name: Publish Android Artifact - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: release-apk-signed path: mobile/build/app/outputs/flutter-apk/*.apk - name: Save Gradle Cache id: cache-gradle-save - uses: actions/cache/save@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3 + uses: actions/cache/save@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 if: github.ref == 'refs/heads/main' with: path: | @@ -185,13 +185,13 @@ jobs: run: sudo xcode-select -s /Applications/Xcode_26.2.app/Contents/Developer - name: Checkout code - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: ref: ${{ inputs.ref || github.sha }} persist-credentials: false - name: Setup Flutter SDK - uses: subosito/flutter-action@fd55f4c5af5b953cc57a2be44cb082c8f6635e8e # v2 + uses: subosito/flutter-action@0ca7a949e71ae44c8e688a51c5e7e93b2c87e295 # v2.22.0 with: channel: 'stable' flutter-version-file: ./mobile/pubspec.yaml @@ -210,7 +210,7 @@ jobs: working-directory: ./mobile - name: Setup Ruby - uses: ruby/setup-ruby@v1 + uses: ruby/setup-ruby@319994f95fa847cf3fb3cd3dbe89f6dcde9f178f # v1.295.0 with: ruby-version: '3.3' bundler-cache: true @@ -291,7 +291,7 @@ jobs: security delete-keychain build.keychain || true - name: Upload IPA artifact - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: ios-release-ipa path: mobile/ios/Runner.ipa diff --git a/.github/workflows/cache-cleanup.yml b/.github/workflows/cache-cleanup.yml index 3de4676622..e093cf9bf0 100644 --- a/.github/workflows/cache-cleanup.yml +++ b/.github/workflows/cache-cleanup.yml @@ -19,7 +19,7 @@ jobs: actions: write steps: - id: token - uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1 + uses: immich-app/devtools/actions/create-workflow-token@57ff6ebfd507b045514442683ff06ff1b2f6efbd # create-workflow-token-action-v1.0.2 with: app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }} private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }} diff --git a/.github/workflows/check-openapi.yml b/.github/workflows/check-openapi.yml index b725b45f6c..dbf0036746 100644 --- a/.github/workflows/check-openapi.yml +++ b/.github/workflows/check-openapi.yml @@ -24,7 +24,7 @@ jobs: persist-credentials: false - name: Check for breaking API changes - uses: oasdiff/oasdiff-action/breaking@748daafaf3aac877a36307f842a48d55db938ac8 # v0.0.31 + uses: oasdiff/oasdiff-action/breaking@2a37bc82462349c03a533b8b608bebbaf57b3e60 # v0.0.33 with: base: https://raw.githubusercontent.com/${{ github.repository }}/main/open-api/immich-openapi-specs.json revision: open-api/immich-openapi-specs.json diff --git a/.github/workflows/check-pr-template.yml b/.github/workflows/check-pr-template.yml deleted file mode 100644 index 5419fb27f7..0000000000 --- a/.github/workflows/check-pr-template.yml +++ /dev/null @@ -1,97 +0,0 @@ -name: Check PR Template - -on: - pull_request_target: # zizmor: ignore[dangerous-triggers] - types: [opened, edited] - -permissions: {} - -env: - LABEL_ID: 'LA_kwDOGyI-8M8AAAACcAeOfg' # auto-closed:template - -jobs: - parse: - runs-on: ubuntu-latest - if: ${{ github.event.pull_request.head.repo.fork == true }} - permissions: - contents: read - outputs: - uses_template: ${{ steps.check.outputs.uses_template }} - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - with: - sparse-checkout: .github/pull_request_template.md - sparse-checkout-cone-mode: false - persist-credentials: false - - - name: Check required sections - id: check - env: - BODY: ${{ github.event.pull_request.body }} - run: | - OK=true - while IFS= read -r header; do - printf '%s\n' "$BODY" | grep -qF "$header" || OK=false - done < <(sed '//d' .github/pull_request_template.md | grep "^## ") - echo "uses_template=$OK" >> "$GITHUB_OUTPUT" - - act: - runs-on: ubuntu-latest - needs: parse - permissions: - pull-requests: write - steps: - - name: Close PR - if: ${{ needs.parse.outputs.uses_template == 'false' && github.event.pull_request.state != 'closed' }} - env: - GH_TOKEN: ${{ github.token }} - NODE_ID: ${{ github.event.pull_request.node_id }} - run: | - gh api graphql \ - -f prId="$NODE_ID" \ - -f labelId="$LABEL_ID" \ - -f body="This PR has been automatically closed as the description doesn't follow our template. After you edit it to match the template, the PR will automatically be reopened." \ - -f query=' - mutation CommentAndClosePR($prId: ID!, $body: String!, $labelId: ID!) { - addComment(input: { - subjectId: $prId, - body: $body - }) { - __typename - } - closePullRequest(input: { - pullRequestId: $prId - }) { - __typename - } - addLabelsToLabelable(input: { - labelableId: $prId, - labelIds: [$labelId] - }) { - __typename - } - }' - - - name: Reopen PR (sections now present, PR was auto-closed) - if: ${{ needs.parse.outputs.uses_template == 'true' && github.event.pull_request.state == 'closed' && contains(github.event.pull_request.labels.*.node_id, env.LABEL_ID) }} - env: - GH_TOKEN: ${{ github.token }} - NODE_ID: ${{ github.event.pull_request.node_id }} - run: | - gh api graphql \ - -f prId="$NODE_ID" \ - -f labelId="$LABEL_ID" \ - -f query=' - mutation ReopenPR($prId: ID!, $labelId: ID!) { - reopenPullRequest(input: { - pullRequestId: $prId - }) { - __typename - } - removeLabelsFromLabelable(input: { - labelableId: $prId, - labelIds: [$labelId] - }) { - __typename - } - }' diff --git a/.github/workflows/cli.yml b/.github/workflows/cli.yml index d3eb66810e..9d08d3f816 100644 --- a/.github/workflows/cli.yml +++ b/.github/workflows/cli.yml @@ -31,7 +31,7 @@ jobs: working-directory: ./cli steps: - id: token - uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1 + uses: immich-app/devtools/actions/create-workflow-token@57ff6ebfd507b045514442683ff06ff1b2f6efbd # create-workflow-token-action-v1.0.2 with: app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }} private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }} @@ -42,7 +42,7 @@ jobs: token: ${{ steps.token.outputs.token }} - name: Setup pnpm - uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4.3.0 + uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0 - name: Setup Node uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 @@ -71,7 +71,7 @@ jobs: steps: - id: token - uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1 + uses: immich-app/devtools/actions/create-workflow-token@57ff6ebfd507b045514442683ff06ff1b2f6efbd # create-workflow-token-action-v1.0.2 with: app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }} private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }} @@ -83,13 +83,13 @@ jobs: token: ${{ steps.token.outputs.token }} - name: Set up QEMU - uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0 + uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0 + uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0 - name: Login to GitHub Container Registry - uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0 + uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0 if: ${{ !github.event.pull_request.head.repo.fork }} with: registry: ghcr.io @@ -104,7 +104,7 @@ jobs: - name: Generate docker image tags id: metadata - uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5.10.0 + uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6.0.0 with: flavor: | latest=false @@ -115,7 +115,7 @@ jobs: type=raw,value=latest,enable=${{ github.event_name == 'release' }} - name: Build and push image - uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6.19.2 + uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7.0.0 with: file: cli/Dockerfile platforms: linux/amd64,linux/arm64 diff --git a/.github/workflows/close-duplicates.yml b/.github/workflows/close-duplicates.yml index 1b18c0c5e1..b73ba5e634 100644 --- a/.github/workflows/close-duplicates.yml +++ b/.github/workflows/close-duplicates.yml @@ -35,7 +35,7 @@ jobs: needs: [get_body, should_run] if: ${{ needs.should_run.outputs.should_run == 'true' }} container: - image: ghcr.io/immich-app/mdq:main@sha256:4f9860d04c88f7f87861f8ee84bfeedaec15ed7ca5ca87bc7db44b036f81645f + image: ghcr.io/immich-app/mdq:main@sha256:df7188ba88abb0800d73cc97d3633280f0c0c3d4c441d678225067bf154150fb outputs: checked: ${{ steps.get_checkbox.outputs.checked }} steps: diff --git a/.github/workflows/close-llm-pr.yml b/.github/workflows/close-llm-pr.yml deleted file mode 100644 index 511d5c7f55..0000000000 --- a/.github/workflows/close-llm-pr.yml +++ /dev/null @@ -1,38 +0,0 @@ -name: Close LLM-generated PRs - -on: - pull_request_target: - types: [labeled] - -permissions: {} - -jobs: - comment_and_close: - runs-on: ubuntu-latest - if: ${{ github.event.label.name == 'llm-generated' }} - permissions: - pull-requests: write - steps: - - name: Comment and close - env: - GH_TOKEN: ${{ github.token }} - NODE_ID: ${{ github.event.pull_request.node_id }} - run: | - gh api graphql \ - -f prId="$NODE_ID" \ - -f body="Thank you for your interest in contributing to Immich! Unfortunately this PR looks like it was generated using an LLM. As noted in our [CONTRIBUTING.md](https://github.com/immich-app/immich/blob/main/CONTRIBUTING.md#use-of-generative-ai), we request that you don't use LLMs to generate PRs as those are not a good use of maintainer time." \ - -f query=' - mutation CommentAndClosePR($prId: ID!, $body: String!) { - addComment(input: { - subjectId: $prId, - body: $body - }) { - __typename - } - - closePullRequest(input: { - pullRequestId: $prId - }) { - __typename - } - }' diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 3450fe96bb..83c6c65cac 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -44,7 +44,7 @@ jobs: steps: - id: token - uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1 + uses: immich-app/devtools/actions/create-workflow-token@57ff6ebfd507b045514442683ff06ff1b2f6efbd # create-workflow-token-action-v1.0.2 with: app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }} private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }} @@ -57,7 +57,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@0d579ffd059c29b07949a3cce3983f0780820c98 # v4.32.6 + uses: github/codeql-action/init@b1bff81932f5cdfc8695c7752dcee935dcd061c8 # v4.33.0 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -70,7 +70,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@0d579ffd059c29b07949a3cce3983f0780820c98 # v4.32.6 + uses: github/codeql-action/autobuild@b1bff81932f5cdfc8695c7752dcee935dcd061c8 # v4.33.0 # â„šī¸ Command-line programs to run using the OS shell. # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun @@ -83,6 +83,6 @@ jobs: # ./location_of_script_within_repo/buildscript.sh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@0d579ffd059c29b07949a3cce3983f0780820c98 # v4.32.6 + uses: github/codeql-action/analyze@b1bff81932f5cdfc8695c7752dcee935dcd061c8 # v4.33.0 with: category: '/language:${{matrix.language}}' diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 2573ba8123..d5c327b9e7 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -23,14 +23,14 @@ jobs: should_run: ${{ steps.check.outputs.should_run }} steps: - id: token - uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1 + uses: immich-app/devtools/actions/create-workflow-token@57ff6ebfd507b045514442683ff06ff1b2f6efbd # create-workflow-token-action-v1.0.2 with: app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }} private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }} - name: Check what should run id: check - uses: immich-app/devtools/actions/pre-job@eed0f8b8165ffcb951f2ba854b2dd031935e1d73 # pre-job-action-v2.0.2 + uses: immich-app/devtools/actions/pre-job@f50e3b600b6ac1763ddb8f3dfc69093512b967a1 # pre-job-action-v2.0.3 with: github-token: ${{ steps.token.outputs.token }} filters: | @@ -60,7 +60,7 @@ jobs: suffix: ['', '-cuda', '-rocm', '-openvino', '-armnn', '-rknn'] steps: - name: Login to GitHub Container Registry - uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0 + uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0 with: registry: ghcr.io username: ${{ github.repository_owner }} @@ -90,7 +90,7 @@ jobs: suffix: [''] steps: - name: Login to GitHub Container Registry - uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0 + uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0 with: registry: ghcr.io username: ${{ github.repository_owner }} @@ -132,7 +132,7 @@ jobs: suffixes: '-rocm' platforms: linux/amd64 runner-mapping: '{"linux/amd64": "pokedex-large"}' - uses: immich-app/devtools/.github/workflows/multi-runner-build.yml@bd49ed7a5a6022149f79b6564df48177476a822b # multi-runner-build-workflow-v2.2.1 + uses: immich-app/devtools/.github/workflows/multi-runner-build.yml@61a0fc2b41524edcc7c9fffb8bb178e6b0ccf21d # multi-runner-build-workflow-v2.3.0 permissions: contents: read actions: read @@ -155,7 +155,7 @@ jobs: name: Build and Push Server needs: pre-job if: ${{ fromJSON(needs.pre-job.outputs.should_run).server == true }} - uses: immich-app/devtools/.github/workflows/multi-runner-build.yml@bd49ed7a5a6022149f79b6564df48177476a822b # multi-runner-build-workflow-v2.2.1 + uses: immich-app/devtools/.github/workflows/multi-runner-build.yml@61a0fc2b41524edcc7c9fffb8bb178e6b0ccf21d # multi-runner-build-workflow-v2.3.0 permissions: contents: read actions: read @@ -178,7 +178,7 @@ jobs: runs-on: ubuntu-latest if: always() steps: - - uses: immich-app/devtools/actions/success-check@68f10eb389bb02a3cf9d1156111964c549eb421b # 0.0.4 + - uses: immich-app/devtools/actions/success-check@53bb77345ee9f953f93bd6fd9980f07a2f24965e # success-check-action-v0.0.5 with: needs: ${{ toJSON(needs) }} @@ -189,6 +189,6 @@ jobs: runs-on: ubuntu-latest if: always() steps: - - uses: immich-app/devtools/actions/success-check@68f10eb389bb02a3cf9d1156111964c549eb421b # 0.0.4 + - uses: immich-app/devtools/actions/success-check@53bb77345ee9f953f93bd6fd9980f07a2f24965e # success-check-action-v0.0.5 with: needs: ${{ toJSON(needs) }} diff --git a/.github/workflows/docs-build.yml b/.github/workflows/docs-build.yml index 02d7b3456a..2055bfce65 100644 --- a/.github/workflows/docs-build.yml +++ b/.github/workflows/docs-build.yml @@ -21,14 +21,14 @@ jobs: should_run: ${{ steps.check.outputs.should_run }} steps: - id: token - uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1 + uses: immich-app/devtools/actions/create-workflow-token@57ff6ebfd507b045514442683ff06ff1b2f6efbd # create-workflow-token-action-v1.0.2 with: app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }} private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }} - name: Check what should run id: check - uses: immich-app/devtools/actions/pre-job@eed0f8b8165ffcb951f2ba854b2dd031935e1d73 # pre-job-action-v2.0.2 + uses: immich-app/devtools/actions/pre-job@f50e3b600b6ac1763ddb8f3dfc69093512b967a1 # pre-job-action-v2.0.3 with: github-token: ${{ steps.token.outputs.token }} filters: | @@ -54,7 +54,7 @@ jobs: steps: - id: token - uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1 + uses: immich-app/devtools/actions/create-workflow-token@57ff6ebfd507b045514442683ff06ff1b2f6efbd # create-workflow-token-action-v1.0.2 with: app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }} private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }} @@ -67,7 +67,7 @@ jobs: fetch-depth: 0 - name: Setup pnpm - uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4.3.0 + uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0 - name: Setup Node uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 @@ -86,7 +86,7 @@ jobs: run: pnpm build - name: Upload build output - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: docs-build-output path: docs/build/ diff --git a/.github/workflows/docs-deploy.yml b/.github/workflows/docs-deploy.yml index babda72c33..05c845ccd1 100644 --- a/.github/workflows/docs-deploy.yml +++ b/.github/workflows/docs-deploy.yml @@ -20,7 +20,7 @@ jobs: artifact: ${{ steps.get-artifact.outputs.result }} steps: - id: token - uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1 + uses: immich-app/devtools/actions/create-workflow-token@57ff6ebfd507b045514442683ff06ff1b2f6efbd # create-workflow-token-action-v1.0.2 with: app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }} private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }} @@ -119,7 +119,7 @@ jobs: if: ${{ fromJson(needs.checks.outputs.artifact).found && fromJson(needs.checks.outputs.parameters).shouldDeploy }} steps: - id: token - uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1 + uses: immich-app/devtools/actions/create-workflow-token@57ff6ebfd507b045514442683ff06ff1b2f6efbd # create-workflow-token-action-v1.0.2 with: app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }} private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }} @@ -131,7 +131,7 @@ jobs: token: ${{ steps.token.outputs.token }} - name: Setup Mise - uses: immich-app/devtools/actions/use-mise@dab18118da6476e8237ac94080fd937983fecd42 # use-mise-action-v1.1.2 + uses: immich-app/devtools/actions/use-mise@035e80a7d4355d5f087ffb95db9e4a0944c04e56 # use-mise-action-v1.1.3 - name: Load parameters id: parameters diff --git a/.github/workflows/docs-destroy.yml b/.github/workflows/docs-destroy.yml index 05842889cc..bb24a017fe 100644 --- a/.github/workflows/docs-destroy.yml +++ b/.github/workflows/docs-destroy.yml @@ -17,7 +17,7 @@ jobs: pull-requests: write steps: - id: token - uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1 + uses: immich-app/devtools/actions/create-workflow-token@57ff6ebfd507b045514442683ff06ff1b2f6efbd # create-workflow-token-action-v1.0.2 with: app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }} private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }} @@ -29,7 +29,7 @@ jobs: token: ${{ steps.token.outputs.token }} - name: Setup Mise - uses: immich-app/devtools/actions/use-mise@dab18118da6476e8237ac94080fd937983fecd42 # use-mise-action-v1.1.2 + uses: immich-app/devtools/actions/use-mise@035e80a7d4355d5f087ffb95db9e4a0944c04e56 # use-mise-action-v1.1.3 - name: Destroy Docs Subdomain env: diff --git a/.github/workflows/fix-format.yml b/.github/workflows/fix-format.yml index 0091bcef89..ae8e0b29ca 100644 --- a/.github/workflows/fix-format.yml +++ b/.github/workflows/fix-format.yml @@ -16,7 +16,7 @@ jobs: steps: - name: Generate a token id: generate-token - uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1 + uses: actions/create-github-app-token@f8d387b68d61c58ab83c6c016672934102569859 # v3.0.0 with: app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }} private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }} @@ -29,7 +29,7 @@ jobs: persist-credentials: true - name: Setup pnpm - uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4.3.0 + uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0 - name: Setup Node uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 diff --git a/.github/workflows/merge-translations.yml b/.github/workflows/merge-translations.yml index 392dec5e37..fcda857eda 100644 --- a/.github/workflows/merge-translations.yml +++ b/.github/workflows/merge-translations.yml @@ -31,7 +31,7 @@ jobs: - name: Generate a token id: generate_token if: ${{ inputs.skip != true }} - uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1 + uses: actions/create-github-app-token@f8d387b68d61c58ab83c6c016672934102569859 # v3.0.0 with: app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }} private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }} diff --git a/.github/workflows/pr-label-validation.yml b/.github/workflows/pr-label-validation.yml index e04b32d74f..416e40df0d 100644 --- a/.github/workflows/pr-label-validation.yml +++ b/.github/workflows/pr-label-validation.yml @@ -14,13 +14,13 @@ jobs: pull-requests: write steps: - id: token - uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1 + uses: immich-app/devtools/actions/create-workflow-token@57ff6ebfd507b045514442683ff06ff1b2f6efbd # create-workflow-token-action-v1.0.2 with: app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }} private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }} - name: Require PR to have a changelog label - uses: mheap/github-action-required-labels@8afbe8ae6ab7647d0c9f0cfa7c2f939650d22509 # v5.5.1 + uses: mheap/github-action-required-labels@0ac283b4e65c1fb28ce6079dea5546ceca98ccbe # v5.5.2 with: token: ${{ steps.token.outputs.token }} mode: exactly diff --git a/.github/workflows/pr-labeler.yml b/.github/workflows/pr-labeler.yml index 24f3f8faf1..75ee750e9f 100644 --- a/.github/workflows/pr-labeler.yml +++ b/.github/workflows/pr-labeler.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest steps: - id: token - uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1 + uses: immich-app/devtools/actions/create-workflow-token@57ff6ebfd507b045514442683ff06ff1b2f6efbd # create-workflow-token-action-v1.0.2 with: app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }} private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }} diff --git a/.github/workflows/prepare-release.yml b/.github/workflows/prepare-release.yml index e3e6659140..dec9b06d67 100644 --- a/.github/workflows/prepare-release.yml +++ b/.github/workflows/prepare-release.yml @@ -50,7 +50,7 @@ jobs: steps: - name: Generate a token id: generate-token - uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1 + uses: actions/create-github-app-token@f8d387b68d61c58ab83c6c016672934102569859 # v3.0.0 with: app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }} private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }} @@ -63,10 +63,10 @@ jobs: ref: main - name: Install uv - uses: astral-sh/setup-uv@6ee6290f1cbc4156c0bdd66691b2c144ef8df19a # v7.4.0 + uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0 - name: Setup pnpm - uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4.3.0 + uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0 - name: Setup Node uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 @@ -124,7 +124,7 @@ jobs: steps: - name: Generate a token id: generate-token - uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1 + uses: actions/create-github-app-token@f8d387b68d61c58ab83c6c016672934102569859 # v3.0.0 with: app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }} private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }} @@ -136,13 +136,13 @@ jobs: persist-credentials: false - name: Download APK - uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: release-apk-signed github-token: ${{ steps.generate-token.outputs.token }} - name: Create draft release - uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2.5.0 + uses: softprops/action-gh-release@153bb8e04406b158c6c84fc1615b65b24149a1fe # v2.6.1 with: draft: true tag_name: ${{ needs.bump_version.outputs.version }} diff --git a/.github/workflows/preview-label.yaml b/.github/workflows/preview-label.yaml index dc6f0eff0a..43c971c31b 100644 --- a/.github/workflows/preview-label.yaml +++ b/.github/workflows/preview-label.yaml @@ -14,12 +14,12 @@ jobs: pull-requests: write steps: - id: token - uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1 + uses: immich-app/devtools/actions/create-workflow-token@57ff6ebfd507b045514442683ff06ff1b2f6efbd # create-workflow-token-action-v1.0.2 with: app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }} private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }} - - uses: mshick/add-pr-comment@b8f338c590a895d50bcbfa6c5859251edc8952fc # v2.8.2 + - uses: mshick/add-pr-comment@ffd016c7e151d97d69d21a843022fd4cd5b96fe5 # v3.9.0 with: github-token: ${{ steps.token.outputs.token }} message-id: 'preview-status' @@ -32,7 +32,7 @@ jobs: pull-requests: write steps: - id: token - uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1 + uses: immich-app/devtools/actions/create-workflow-token@57ff6ebfd507b045514442683ff06ff1b2f6efbd # create-workflow-token-action-v1.0.2 with: app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }} private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }} @@ -48,14 +48,14 @@ jobs: name: 'preview' }) - - uses: mshick/add-pr-comment@b8f338c590a895d50bcbfa6c5859251edc8952fc # v2.8.2 + - uses: mshick/add-pr-comment@ffd016c7e151d97d69d21a843022fd4cd5b96fe5 # v3.9.0 if: ${{ github.event.pull_request.head.repo.fork }} with: github-token: ${{ steps.token.outputs.token }} message-id: 'preview-status' message: 'PRs from forks cannot have preview environments.' - - uses: mshick/add-pr-comment@b8f338c590a895d50bcbfa6c5859251edc8952fc # v2.8.2 + - uses: mshick/add-pr-comment@ffd016c7e151d97d69d21a843022fd4cd5b96fe5 # v3.9.0 if: ${{ !github.event.pull_request.head.repo.fork }} with: github-token: ${{ steps.token.outputs.token }} diff --git a/.github/workflows/sdk.yml b/.github/workflows/sdk.yml index 2da7d79b26..d9b6ffb7f5 100644 --- a/.github/workflows/sdk.yml +++ b/.github/workflows/sdk.yml @@ -19,7 +19,7 @@ jobs: working-directory: ./open-api/typescript-sdk steps: - id: token - uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1 + uses: immich-app/devtools/actions/create-workflow-token@57ff6ebfd507b045514442683ff06ff1b2f6efbd # create-workflow-token-action-v1.0.2 with: app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }} private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }} @@ -30,7 +30,7 @@ jobs: token: ${{ steps.token.outputs.token }} - name: Setup pnpm - uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4.3.0 + uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0 # Setup .npmrc file to publish to npm - uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 diff --git a/.github/workflows/static_analysis.yml b/.github/workflows/static_analysis.yml index d100dd281f..4359212d01 100644 --- a/.github/workflows/static_analysis.yml +++ b/.github/workflows/static_analysis.yml @@ -20,14 +20,14 @@ jobs: should_run: ${{ steps.check.outputs.should_run }} steps: - id: token - uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1 + uses: immich-app/devtools/actions/create-workflow-token@57ff6ebfd507b045514442683ff06ff1b2f6efbd # create-workflow-token-action-v1.0.2 with: app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }} private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }} - name: Check what should run id: check - uses: immich-app/devtools/actions/pre-job@eed0f8b8165ffcb951f2ba854b2dd031935e1d73 # pre-job-action-v2.0.2 + uses: immich-app/devtools/actions/pre-job@f50e3b600b6ac1763ddb8f3dfc69093512b967a1 # pre-job-action-v2.0.3 with: github-token: ${{ steps.token.outputs.token }} filters: | @@ -49,7 +49,7 @@ jobs: working-directory: ./mobile steps: - id: token - uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1 + uses: immich-app/devtools/actions/create-workflow-token@57ff6ebfd507b045514442683ff06ff1b2f6efbd # create-workflow-token-action-v1.0.2 with: app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }} private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }} @@ -61,7 +61,7 @@ jobs: token: ${{ steps.token.outputs.token }} - name: Setup Flutter SDK - uses: subosito/flutter-action@fd55f4c5af5b953cc57a2be44cb082c8f6635e8e # v2.21.0 + uses: subosito/flutter-action@0ca7a949e71ae44c8e688a51c5e7e93b2c87e295 # v2.22.0 with: channel: 'stable' flutter-version-file: ./mobile/pubspec.yaml diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 2a2ebe2389..bb1e24be5c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -17,14 +17,14 @@ jobs: should_run: ${{ steps.check.outputs.should_run }} steps: - id: token - uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1 + uses: immich-app/devtools/actions/create-workflow-token@57ff6ebfd507b045514442683ff06ff1b2f6efbd # create-workflow-token-action-v1.0.2 with: app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }} private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }} - name: Check what should run id: check - uses: immich-app/devtools/actions/pre-job@eed0f8b8165ffcb951f2ba854b2dd031935e1d73 # pre-job-action-v2.0.2 + uses: immich-app/devtools/actions/pre-job@f50e3b600b6ac1763ddb8f3dfc69093512b967a1 # pre-job-action-v2.0.3 with: github-token: ${{ steps.token.outputs.token }} filters: | @@ -63,7 +63,7 @@ jobs: working-directory: ./server steps: - id: token - uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1 + uses: immich-app/devtools/actions/create-workflow-token@57ff6ebfd507b045514442683ff06ff1b2f6efbd # create-workflow-token-action-v1.0.2 with: app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }} private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }} @@ -75,7 +75,7 @@ jobs: token: ${{ steps.token.outputs.token }} - name: Setup pnpm - uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4.3.0 + uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0 - name: Setup Node uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 with: @@ -108,7 +108,7 @@ jobs: working-directory: ./cli steps: - id: token - uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1 + uses: immich-app/devtools/actions/create-workflow-token@57ff6ebfd507b045514442683ff06ff1b2f6efbd # create-workflow-token-action-v1.0.2 with: app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }} private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }} @@ -119,7 +119,7 @@ jobs: persist-credentials: false token: ${{ steps.token.outputs.token }} - name: Setup pnpm - uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4.3.0 + uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0 - name: Setup Node uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 with: @@ -155,7 +155,7 @@ jobs: working-directory: ./cli steps: - id: token - uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1 + uses: immich-app/devtools/actions/create-workflow-token@57ff6ebfd507b045514442683ff06ff1b2f6efbd # create-workflow-token-action-v1.0.2 with: app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }} private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }} @@ -166,7 +166,7 @@ jobs: persist-credentials: false token: ${{ steps.token.outputs.token }} - name: Setup pnpm - uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4.3.0 + uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0 - name: Setup Node uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 with: @@ -197,7 +197,7 @@ jobs: working-directory: ./web steps: - id: token - uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1 + uses: immich-app/devtools/actions/create-workflow-token@57ff6ebfd507b045514442683ff06ff1b2f6efbd # create-workflow-token-action-v1.0.2 with: app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }} private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }} @@ -208,7 +208,7 @@ jobs: persist-credentials: false token: ${{ steps.token.outputs.token }} - name: Setup pnpm - uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4.3.0 + uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0 - name: Setup Node uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 with: @@ -241,7 +241,7 @@ jobs: working-directory: ./web steps: - id: token - uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1 + uses: immich-app/devtools/actions/create-workflow-token@57ff6ebfd507b045514442683ff06ff1b2f6efbd # create-workflow-token-action-v1.0.2 with: app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }} private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }} @@ -252,7 +252,7 @@ jobs: persist-credentials: false token: ${{ steps.token.outputs.token }} - name: Setup pnpm - uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4.3.0 + uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0 - name: Setup Node uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 with: @@ -279,7 +279,7 @@ jobs: contents: read steps: - id: token - uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1 + uses: immich-app/devtools/actions/create-workflow-token@57ff6ebfd507b045514442683ff06ff1b2f6efbd # create-workflow-token-action-v1.0.2 with: app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }} private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }} @@ -290,7 +290,7 @@ jobs: persist-credentials: false token: ${{ steps.token.outputs.token }} - name: Setup pnpm - uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4.3.0 + uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0 - name: Setup Node uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 with: @@ -327,7 +327,7 @@ jobs: working-directory: ./e2e steps: - id: token - uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1 + uses: immich-app/devtools/actions/create-workflow-token@57ff6ebfd507b045514442683ff06ff1b2f6efbd # create-workflow-token-action-v1.0.2 with: app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }} private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }} @@ -338,7 +338,7 @@ jobs: persist-credentials: false token: ${{ steps.token.outputs.token }} - name: Setup pnpm - uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4.3.0 + uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0 - name: Setup Node uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 with: @@ -373,7 +373,7 @@ jobs: working-directory: ./server steps: - id: token - uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1 + uses: immich-app/devtools/actions/create-workflow-token@57ff6ebfd507b045514442683ff06ff1b2f6efbd # create-workflow-token-action-v1.0.2 with: app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }} private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }} @@ -385,7 +385,7 @@ jobs: submodules: 'recursive' token: ${{ steps.token.outputs.token }} - name: Setup pnpm - uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4.3.0 + uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0 - name: Setup Node uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 with: @@ -412,7 +412,7 @@ jobs: runner: [ubuntu-latest, ubuntu-24.04-arm] steps: - id: token - uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1 + uses: immich-app/devtools/actions/create-workflow-token@57ff6ebfd507b045514442683ff06ff1b2f6efbd # create-workflow-token-action-v1.0.2 with: app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }} private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }} @@ -424,7 +424,7 @@ jobs: submodules: 'recursive' token: ${{ steps.token.outputs.token }} - name: Setup pnpm - uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4.3.0 + uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0 - name: Setup Node uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 with: @@ -464,7 +464,7 @@ jobs: run: docker compose logs --no-color > docker-compose-logs.txt working-directory: ./e2e - name: Archive Docker logs - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 if: always() with: name: e2e-server-docker-logs-${{ matrix.runner }} @@ -484,7 +484,7 @@ jobs: runner: [ubuntu-latest, ubuntu-24.04-arm] steps: - id: token - uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1 + uses: immich-app/devtools/actions/create-workflow-token@57ff6ebfd507b045514442683ff06ff1b2f6efbd # create-workflow-token-action-v1.0.2 with: app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }} private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }} @@ -496,7 +496,7 @@ jobs: submodules: 'recursive' token: ${{ steps.token.outputs.token }} - name: Setup pnpm - uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4.3.0 + uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0 - name: Setup Node uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 with: @@ -522,7 +522,7 @@ jobs: run: pnpm test:web if: ${{ !cancelled() }} - name: Archive e2e test (web) results - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 if: success() || failure() with: name: e2e-web-test-results-${{ matrix.runner }} @@ -533,7 +533,7 @@ jobs: run: pnpm test:web:ui if: ${{ !cancelled() }} - name: Archive ui test (web) results - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 if: success() || failure() with: name: e2e-ui-test-results-${{ matrix.runner }} @@ -544,7 +544,7 @@ jobs: run: pnpm test:web:maintenance if: ${{ !cancelled() }} - name: Archive maintenance tests (web) results - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 if: success() || failure() with: name: e2e-maintenance-isolated-test-results-${{ matrix.runner }} @@ -554,7 +554,7 @@ jobs: run: docker compose logs --no-color > docker-compose-logs.txt working-directory: ./e2e - name: Archive Docker logs - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 if: always() with: name: e2e-web-docker-logs-${{ matrix.runner }} @@ -566,7 +566,7 @@ jobs: runs-on: ubuntu-latest if: always() steps: - - uses: immich-app/devtools/actions/success-check@68f10eb389bb02a3cf9d1156111964c549eb421b # 0.0.4 + - uses: immich-app/devtools/actions/success-check@53bb77345ee9f953f93bd6fd9980f07a2f24965e # success-check-action-v0.0.5 with: needs: ${{ toJSON(needs) }} mobile-unit-tests: @@ -578,7 +578,7 @@ jobs: contents: read steps: - id: token - uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1 + uses: immich-app/devtools/actions/create-workflow-token@57ff6ebfd507b045514442683ff06ff1b2f6efbd # create-workflow-token-action-v1.0.2 with: app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }} private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }} @@ -588,7 +588,7 @@ jobs: persist-credentials: false token: ${{ steps.token.outputs.token }} - name: Setup Flutter SDK - uses: subosito/flutter-action@fd55f4c5af5b953cc57a2be44cb082c8f6635e8e # v2.21.0 + uses: subosito/flutter-action@0ca7a949e71ae44c8e688a51c5e7e93b2c87e295 # v2.22.0 with: channel: 'stable' flutter-version-file: ./mobile/pubspec.yaml @@ -610,7 +610,7 @@ jobs: working-directory: ./machine-learning steps: - id: token - uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1 + uses: immich-app/devtools/actions/create-workflow-token@57ff6ebfd507b045514442683ff06ff1b2f6efbd # create-workflow-token-action-v1.0.2 with: app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }} private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }} @@ -620,7 +620,7 @@ jobs: persist-credentials: false token: ${{ steps.token.outputs.token }} - name: Install uv - uses: astral-sh/setup-uv@6ee6290f1cbc4156c0bdd66691b2c144ef8df19a # v7.4.0 + uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0 with: python-version: 3.11 - name: Install dependencies @@ -650,7 +650,7 @@ jobs: working-directory: ./.github steps: - id: token - uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1 + uses: immich-app/devtools/actions/create-workflow-token@57ff6ebfd507b045514442683ff06ff1b2f6efbd # create-workflow-token-action-v1.0.2 with: app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }} private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }} @@ -661,7 +661,7 @@ jobs: persist-credentials: false token: ${{ steps.token.outputs.token }} - name: Setup pnpm - uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4.3.0 + uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0 - name: Setup Node uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 with: @@ -680,7 +680,7 @@ jobs: contents: read steps: - id: token - uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1 + uses: immich-app/devtools/actions/create-workflow-token@57ff6ebfd507b045514442683ff06ff1b2f6efbd # create-workflow-token-action-v1.0.2 with: app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }} private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }} @@ -701,7 +701,7 @@ jobs: contents: read steps: - id: token - uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1 + uses: immich-app/devtools/actions/create-workflow-token@57ff6ebfd507b045514442683ff06ff1b2f6efbd # create-workflow-token-action-v1.0.2 with: app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }} private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }} @@ -712,7 +712,7 @@ jobs: persist-credentials: false token: ${{ steps.token.outputs.token }} - name: Setup pnpm - uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4.3.0 + uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0 - name: Setup Node uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 with: @@ -763,7 +763,7 @@ jobs: working-directory: ./server steps: - id: token - uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1 + uses: immich-app/devtools/actions/create-workflow-token@57ff6ebfd507b045514442683ff06ff1b2f6efbd # create-workflow-token-action-v1.0.2 with: app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }} private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }} @@ -774,7 +774,7 @@ jobs: persist-credentials: false token: ${{ steps.token.outputs.token }} - name: Setup pnpm - uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4.3.0 + uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0 - name: Setup Node uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 with: diff --git a/.github/workflows/weblate-lock.yml b/.github/workflows/weblate-lock.yml index 6e997ad76a..09024063c0 100644 --- a/.github/workflows/weblate-lock.yml +++ b/.github/workflows/weblate-lock.yml @@ -24,14 +24,14 @@ jobs: should_run: ${{ steps.check.outputs.should_run }} steps: - id: token - uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1 + uses: immich-app/devtools/actions/create-workflow-token@57ff6ebfd507b045514442683ff06ff1b2f6efbd # create-workflow-token-action-v1.0.2 with: app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }} private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }} - name: Check what should run id: check - uses: immich-app/devtools/actions/pre-job@eed0f8b8165ffcb951f2ba854b2dd031935e1d73 # pre-job-action-v2.0.2 + uses: immich-app/devtools/actions/pre-job@f50e3b600b6ac1763ddb8f3dfc69093512b967a1 # pre-job-action-v2.0.3 with: github-token: ${{ steps.token.outputs.token }} filters: | @@ -47,7 +47,7 @@ jobs: if: ${{ fromJSON(needs.pre-job.outputs.should_run).i18n == true }} steps: - id: token - uses: immich-app/devtools/actions/create-workflow-token@05e16407c0a5492138bb38139c9d9bf067b40886 # create-workflow-token-action-v1.0.1 + uses: immich-app/devtools/actions/create-workflow-token@57ff6ebfd507b045514442683ff06ff1b2f6efbd # create-workflow-token-action-v1.0.2 with: app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }} private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }} @@ -68,6 +68,6 @@ jobs: permissions: {} if: always() steps: - - uses: immich-app/devtools/actions/success-check@68f10eb389bb02a3cf9d1156111964c549eb421b # 0.0.4 + - uses: immich-app/devtools/actions/success-check@53bb77345ee9f953f93bd6fd9980f07a2f24965e # success-check-action-v0.0.5 with: needs: ${{ toJSON(needs) }} diff --git a/cli/.nvmrc b/cli/.nvmrc index 32f8c50de0..d845d9d88d 100644 --- a/cli/.nvmrc +++ b/cli/.nvmrc @@ -1 +1 @@ -24.13.1 +24.14.0 diff --git a/cli/package.json b/cli/package.json index 9faf2e4981..29df0822d9 100644 --- a/cli/package.json +++ b/cli/package.json @@ -1,6 +1,6 @@ { "name": "@immich/cli", - "version": "2.6.1", + "version": "2.6.3", "description": "Command Line Interface (CLI) for Immich", "type": "module", "exports": "./dist/index.js", @@ -20,7 +20,7 @@ "@types/lodash-es": "^4.17.12", "@types/micromatch": "^4.0.9", "@types/mock-fs": "^4.13.1", - "@types/node": "^24.11.0", + "@types/node": "^24.12.0", "@vitest/coverage-v8": "^4.0.0", "byte-size": "^9.0.0", "cli-progress": "^3.12.0", @@ -35,8 +35,7 @@ "prettier-plugin-organize-imports": "^4.0.0", "typescript": "^5.3.3", "typescript-eslint": "^8.28.0", - "vite": "^7.0.0", - "vite-tsconfig-paths": "^6.0.0", + "vite": "^8.0.0", "vitest": "^4.0.0", "vitest-fetch-mock": "^0.4.0", "yaml": "^2.3.1" @@ -69,6 +68,6 @@ "micromatch": "^4.0.8" }, "volta": { - "node": "24.13.1" + "node": "24.14.0" } } diff --git a/cli/vite.config.ts b/cli/vite.config.ts index c69b467011..fc57b9c796 100644 --- a/cli/vite.config.ts +++ b/cli/vite.config.ts @@ -1,10 +1,12 @@ import { defineConfig, UserConfig } from 'vite'; -import tsconfigPaths from 'vite-tsconfig-paths'; export default defineConfig({ - resolve: { alias: { src: '/src' } }, + resolve: { + alias: { src: '/src' }, + tsconfigPaths: true, + }, build: { - rollupOptions: { + rolldownOptions: { input: 'src/index.ts', output: { dir: 'dist', @@ -16,7 +18,6 @@ export default defineConfig({ // bundle everything except for Node built-ins noExternal: /^(?!node:).*$/, }, - plugins: [tsconfigPaths()], test: { name: 'cli:unit', globals: true, diff --git a/docker/docker-compose.dev.yml b/docker/docker-compose.dev.yml index 6e435b3c6b..1dac8f2c50 100644 --- a/docker/docker-compose.dev.yml +++ b/docker/docker-compose.dev.yml @@ -90,6 +90,7 @@ services: IMMICH_THIRD_PARTY_BUG_FEATURE_URL: https://github.com/immich-app/immich/issues IMMICH_THIRD_PARTY_DOCUMENTATION_URL: https://docs.immich.app IMMICH_THIRD_PARTY_SUPPORT_URL: https://docs.immich.app/community-guides + IMMICH_HELMET_FILE: 'true' ports: - 9230:9230 - 9231:9231 diff --git a/docker/docker-compose.prod.yml b/docker/docker-compose.prod.yml index 4d07794fea..10a78b12ba 100644 --- a/docker/docker-compose.prod.yml +++ b/docker/docker-compose.prod.yml @@ -97,7 +97,7 @@ services: command: ['./run.sh', '-disable-reporting'] ports: - 3000:3000 - image: grafana/grafana:12.3.2-ubuntu@sha256:6cca4b429a1dc0d37d401dee54825c12d40056c3c6f3f56e3f0d6318ce77749b + image: grafana/grafana:12.4.1-ubuntu@sha256:1a20dea76a2778773df17dbc365db86b1a4f2d57772b8590b6311038a3acb1db volumes: - grafana-data:/var/lib/grafana diff --git a/docs/.nvmrc b/docs/.nvmrc index 32f8c50de0..d845d9d88d 100644 --- a/docs/.nvmrc +++ b/docs/.nvmrc @@ -1 +1 @@ -24.13.1 +24.14.0 diff --git a/docs/docs/guides/custom-map-styles.md b/docs/docs/guides/custom-map-styles.md index 1a61afc324..ac693c16ba 100644 --- a/docs/docs/guides/custom-map-styles.md +++ b/docs/docs/guides/custom-map-styles.md @@ -3,8 +3,8 @@ You may decide that you'd like to modify the style document which is used to draw the maps in Immich. In addition to visual customization, this also allows you to pick your own map tile provider instead of the default one. The default -`style.json` for [light theme](https://github.com/immich-app/immich/tree/main/server/resources/style-light.json) -and [dark theme](https://github.com/immich-app/immich/blob/main/server/resources/style-dark.json) +`style.json` for [light theme](https://tiles.immich.cloud/v1/style/light.json) +and [dark theme](https://tiles.immich.cloud/v1/style/dark.json) can be used as a basis for creating your own style. There are several sources for already-made `style.json` map themes, as well as diff --git a/docs/docs/install/environment-variables.md b/docs/docs/install/environment-variables.md index e9e3bb032c..41068dee97 100644 --- a/docs/docs/install/environment-variables.md +++ b/docs/docs/install/environment-variables.md @@ -29,22 +29,23 @@ These environment variables are used by the `docker-compose.yml` file and do **N ## General -| Variable | Description | Default | Containers | Workers | -| :---------------------------------- | :---------------------------------------------------------------------------------------- | :--------------------------: | :----------------------- | :----------------- | -| `TZ` | Timezone | \*1 | server | microservices | -| `IMMICH_ENV` | Environment (production, development) | `production` | server, machine learning | api, microservices | -| `IMMICH_LOG_LEVEL` | Log level (verbose, debug, log, warn, error) | `log` | server, machine learning | api, microservices | -| `IMMICH_LOG_FORMAT` | Log output format (`console`, `json`) | `console` | server | api, microservices | -| `IMMICH_MEDIA_LOCATION` | Media location inside the container âš ī¸**You probably shouldn't set this**\*2âš ī¸ | `/data` | server | api, microservices | -| `IMMICH_CONFIG_FILE` | Path to config file | | server | api, microservices | -| `NO_COLOR` | Set to `true` to disable color-coded log output | `false` | server, machine learning | | -| `CPU_CORES` | Number of cores available to the Immich server | auto-detected CPU core count | server | | -| `IMMICH_API_METRICS_PORT` | Port for the OTEL metrics | `8081` | server | api | -| `IMMICH_MICROSERVICES_METRICS_PORT` | Port for the OTEL metrics | `8082` | server | microservices | -| `IMMICH_PROCESS_INVALID_IMAGES` | When `true`, generate thumbnails for invalid images | | server | microservices | -| `IMMICH_TRUSTED_PROXIES` | List of comma-separated IPs set as trusted proxies | | server | api | -| `IMMICH_IGNORE_MOUNT_CHECK_ERRORS` | See [System Integrity](/administration/system-integrity) | | server | api, microservices | -| `IMMICH_ALLOW_SETUP` | When `false` disables the `/auth/admin-sign-up` endpoint | `true` | server | api | +| Variable | Description | Default | Containers | Workers | +| :---------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------: | :----------------------- | :----------------- | +| `TZ` | Timezone | \*1 | server | microservices | +| `IMMICH_ENV` | Environment (production, development) | `production` | server, machine learning | api, microservices | +| `IMMICH_LOG_LEVEL` | Log level (verbose, debug, log, warn, error) | `log` | server, machine learning | api, microservices | +| `IMMICH_LOG_FORMAT` | Log output format (`console`, `json`) | `console` | server | api, microservices | +| `IMMICH_MEDIA_LOCATION` | Media location inside the container âš ī¸**You probably shouldn't set this**\*2âš ī¸ | `/data` | server | api, microservices | +| `IMMICH_CONFIG_FILE` | Path to config file | | server | api, microservices | +| `IMMICH_HELMET_FILE` | Path to a json file with [helmet](https://www.npmjs.com/package/helmet) options. Set to `false` to disable. Set to `true` to use `server/helmet.json`. | `false` | server | api, microservices | +| `NO_COLOR` | Set to `true` to disable color-coded log output | `false` | server, machine learning | | +| `CPU_CORES` | Number of cores available to the Immich server | auto-detected CPU core count | server | | +| `IMMICH_API_METRICS_PORT` | Port for the OTEL metrics | `8081` | server | api | +| `IMMICH_MICROSERVICES_METRICS_PORT` | Port for the OTEL metrics | `8082` | server | microservices | +| `IMMICH_PROCESS_INVALID_IMAGES` | When `true`, generate thumbnails for invalid images | | server | microservices | +| `IMMICH_TRUSTED_PROXIES` | List of comma-separated IPs set as trusted proxies | | server | api | +| `IMMICH_IGNORE_MOUNT_CHECK_ERRORS` | See [System Integrity](/administration/system-integrity) | | server | api, microservices | +| `IMMICH_ALLOW_SETUP` | When `false` disables the `/auth/admin-sign-up` endpoint | `true` | server | api | \*1: `TZ` should be set to a `TZ identifier` from [this list][tz-list]. For example, `TZ="Etc/UTC"`. `TZ` is used by `exiftool` as a fallback in case the timezone cannot be determined from the image metadata. It is also used for logfile timestamps and cron job execution. diff --git a/docs/docs/install/requirements.md b/docs/docs/install/requirements.md index ee5db45c9a..178cf45388 100644 --- a/docs/docs/install/requirements.md +++ b/docs/docs/install/requirements.md @@ -8,7 +8,7 @@ Hardware and software requirements for Immich: ## Hardware -- **OS**: Recommended Linux or \*nix operating system (Ubuntu, Debian, etc). +- **OS**: Recommended Linux or \*nix 64-bit operating system (Ubuntu, Debian, etc). - Non-Linux OSes tend to provide a poor Docker experience and are strongly discouraged. Our ability to assist with setup or troubleshooting on non-Linux OSes will be severely reduced. If you still want to try to use a non-Linux OS, you can set it up as follows: @@ -19,6 +19,10 @@ Hardware and software requirements for Immich: If you have issues, we recommend that you switch to a supported VM deployment. - **RAM**: Minimum 6GB, recommended 8GB. - **CPU**: Minimum 2 cores, recommended 4 cores. + - Immich runs on the `amd64` and `arm64` platforms. + Since `v2.6`, the machine learning container on `amd64` requires the `>= x86-64-v2` [microarchitecture level](https://en.wikipedia.org/wiki/X86-64#Microarchitecture_levels). + Most CPUs released since ~2012 support this microarchitecture. + If you are using a virtual machine, ensure you have selected a [supported microarchitecture](https://pve.proxmox.com/pve-docs/chapter-qm.html#_qemu_cpu_types). - **Storage**: Recommended Unix-compatible filesystem (EXT4, ZFS, APFS, etc.) with support for user/group ownership and permissions. - The generation of thumbnails and transcoded video can increase the size of the photo library by 10-20% on average. diff --git a/docs/package.json b/docs/package.json index 60a6dccf87..b5c9ca7421 100644 --- a/docs/package.json +++ b/docs/package.json @@ -58,6 +58,6 @@ "node": ">=20" }, "volta": { - "node": "24.13.1" + "node": "24.14.0" } } diff --git a/docs/static/archived-versions.json b/docs/static/archived-versions.json index b253234b39..afaa584882 100644 --- a/docs/static/archived-versions.json +++ b/docs/static/archived-versions.json @@ -1,7 +1,7 @@ [ { - "label": "v2.6.1", - "url": "https://docs.v2.6.1.archive.immich.app" + "label": "v2.6.3", + "url": "https://docs.v2.6.3.archive.immich.app" }, { "label": "v2.5.6", diff --git a/e2e/.nvmrc b/e2e/.nvmrc index 32f8c50de0..d845d9d88d 100644 --- a/e2e/.nvmrc +++ b/e2e/.nvmrc @@ -1 +1 @@ -24.13.1 +24.14.0 diff --git a/e2e/package.json b/e2e/package.json index 48bc8de65e..2be3ce04b6 100644 --- a/e2e/package.json +++ b/e2e/package.json @@ -1,6 +1,6 @@ { "name": "immich-e2e", - "version": "2.6.1", + "version": "2.6.3", "description": "", "main": "index.js", "type": "module", @@ -32,7 +32,7 @@ "@playwright/test": "^1.44.1", "@socket.io/component-emitter": "^3.1.2", "@types/luxon": "^3.4.2", - "@types/node": "^24.11.0", + "@types/node": "^24.12.0", "@types/pg": "^8.15.1", "@types/pngjs": "^6.0.4", "@types/supertest": "^6.0.2", @@ -58,6 +58,6 @@ "vitest": "^4.0.0" }, "volta": { - "node": "24.13.1" + "node": "24.14.0" } } diff --git a/e2e/src/specs/maintenance/server/database-backups.e2e-spec.ts b/e2e/src/specs/maintenance/server/database-backups.e2e-spec.ts index 2b0f6ae61a..b69bd099ed 100644 --- a/e2e/src/specs/maintenance/server/database-backups.e2e-spec.ts +++ b/e2e/src/specs/maintenance/server/database-backups.e2e-spec.ts @@ -10,7 +10,9 @@ describe('/admin/database-backups', () => { beforeAll(async () => { await utils.resetDatabase(); - admin = await utils.adminSetup(); + admin = await utils.adminSetup({ + onboarding: false, + }); await utils.resetBackups(admin.accessToken); }); @@ -94,7 +96,9 @@ describe('/admin/database-backups', () => { ({ status, body }) => status === 200 && !body.maintenanceMode, ); - admin = await utils.adminSetup(); + admin = await utils.adminSetup({ + onboarding: false, + }); }); it.sequential('should not work when the server is configured', async () => { diff --git a/e2e/src/specs/server/api/album.e2e-spec.ts b/e2e/src/specs/server/api/album.e2e-spec.ts index c4f06edd93..a9e90940ab 100644 --- a/e2e/src/specs/server/api/album.e2e-spec.ts +++ b/e2e/src/specs/server/api/album.e2e-spec.ts @@ -524,14 +524,19 @@ describe('/albums', () => { expect(body).toEqual(errorDto.badRequest('Not found or no album.update access')); }); - it('should not be able to update as an editor', async () => { + it('should be able to update as an editor', async () => { const { status, body } = await request(app) .patch(`/albums/${user1Albums[0].id}`) .set('Authorization', `Bearer ${user2.accessToken}`) .send({ albumName: 'New album name' }); - expect(status).toBe(400); - expect(body).toEqual(errorDto.badRequest('Not found or no album.update access')); + expect(status).toBe(200); + expect(body).toEqual( + expect.objectContaining({ + id: user1Albums[0].id, + albumName: 'New album name', + }), + ); }); }); diff --git a/e2e/src/specs/web/album.e2e-spec.ts b/e2e/src/specs/web/album.e2e-spec.ts index 953c7d00ae..cd8bb87582 100644 --- a/e2e/src/specs/web/album.e2e-spec.ts +++ b/e2e/src/specs/web/album.e2e-spec.ts @@ -1,6 +1,7 @@ import { LoginResponseDto } from '@immich/sdk'; -import { test } from '@playwright/test'; -import { utils } from 'src/utils'; +import { expect, test } from '@playwright/test'; +import { readFileSync } from 'node:fs'; +import { testAssetDir, utils } from 'src/utils'; test.describe('Album', () => { let admin: LoginResponseDto; @@ -22,4 +23,41 @@ test.describe('Album', () => { await page.reload(); await page.getByRole('button', { name: 'Select photos' }).waitFor(); }); + + test('should keep map view open after viewing an asset from the map and going back', async ({ context, page }) => { + await utils.setAuthCookies(context, admin.accessToken); + + const imagePath = `${testAssetDir}/metadata/gps-position/thompson-springs.jpg`; + const mapAsset = await utils.createAsset(admin.accessToken, { + assetData: { + bytes: readFileSync(imagePath), + filename: 'thompson-springs.jpg', + }, + }); + + await utils.waitForQueueFinish(admin.accessToken, 'metadataExtraction'); + + const mapAlbum = await utils.createAlbum(admin.accessToken, { + albumName: 'Map Test Album', + assetIds: [mapAsset.id], + }); + + await page.goto(`/albums/${mapAlbum.id}`); + const mapButton = page.getByRole('button', { name: 'Map' }); + await expect(mapButton).toBeVisible(); + await mapButton.click(); + + const mapModal = page.getByRole('dialog'); + await expect(mapModal).toBeVisible(); + + const mapMarker = mapModal.getByRole('img', { name: /Map marker/i }).first(); + await expect(mapMarker).toBeVisible(); + await mapMarker.click(); + + await page.waitForSelector('#immich-asset-viewer'); + await page.getByRole('button', { name: 'Go back' }).click(); + + await expect(page.locator('#immich-asset-viewer')).not.toBeVisible(); + await expect(mapModal).toBeVisible(); + }); }); diff --git a/e2e/src/specs/web/duplicates.e2e-spec.ts b/e2e/src/specs/web/duplicates.e2e-spec.ts new file mode 100644 index 0000000000..34f11cdf78 --- /dev/null +++ b/e2e/src/specs/web/duplicates.e2e-spec.ts @@ -0,0 +1,51 @@ +import { AssetMediaResponseDto, LoginResponseDto, updateAssets } from '@immich/sdk'; +import { expect, test } from '@playwright/test'; +import crypto from 'node:crypto'; +import { asBearerAuth, utils } from 'src/utils'; + +test.describe('Duplicates Utility', () => { + let admin: LoginResponseDto; + let firstAsset: AssetMediaResponseDto; + let secondAsset: AssetMediaResponseDto; + + test.beforeAll(async () => { + utils.initSdk(); + await utils.resetDatabase(); + admin = await utils.adminSetup(); + }); + + test.beforeEach(async ({ context }) => { + [firstAsset, secondAsset] = await Promise.all([ + utils.createAsset(admin.accessToken, { deviceAssetId: 'duplicate-a' }), + utils.createAsset(admin.accessToken, { deviceAssetId: 'duplicate-b' }), + ]); + + await updateAssets( + { + assetBulkUpdateDto: { + ids: [firstAsset.id, secondAsset.id], + duplicateId: crypto.randomUUID(), + }, + }, + { headers: asBearerAuth(admin.accessToken) }, + ); + + await utils.setAuthCookies(context, admin.accessToken); + }); + + test('navigates with arrow keys between duplicate preview assets', async ({ page }) => { + await page.goto('/utilities/duplicates'); + await page.getByRole('button', { name: 'View' }).first().click(); + await page.waitForSelector('#immich-asset-viewer'); + + const getViewedAssetId = () => new URL(page.url()).pathname.split('/').at(-1) ?? ''; + const initialAssetId = getViewedAssetId(); + expect([firstAsset.id, secondAsset.id]).toContain(initialAssetId); + + await page.keyboard.press('ArrowRight'); + await expect.poll(getViewedAssetId).not.toBe(initialAssetId); + + await page.keyboard.press('ArrowLeft'); + await expect.poll(getViewedAssetId).toBe(initialAssetId); + }); +}); diff --git a/i18n/en.json b/i18n/en.json index 956ed03989..252664653c 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -866,6 +866,7 @@ "crop_aspect_ratio_fixed": "Fixed", "crop_aspect_ratio_free": "Free", "crop_aspect_ratio_original": "Original", + "crop_aspect_ratio_square": "Square", "curated_object_page_title": "Things", "current_device": "Current device", "current_pin_code": "Current PIN code", @@ -880,7 +881,7 @@ "daily_title_text_date": "E, MMM dd", "daily_title_text_date_year": "E, MMM dd, yyyy", "dark": "Dark", - "dark_theme": "Toggle dark theme", + "dark_theme": "Switch to dark theme", "date": "Date", "date_after": "Date after", "date_and_time": "Date and Time", @@ -1387,6 +1388,7 @@ "library_page_sort_title": "Album title", "licenses": "Licenses", "light": "Light", + "light_theme": "Switch to light theme", "like": "Like", "like_deleted": "Like deleted", "link_motion_video": "Link motion video", diff --git a/i18n/package.json b/i18n/package.json index 1e4d885de1..a66505923d 100644 --- a/i18n/package.json +++ b/i18n/package.json @@ -1,6 +1,6 @@ { "name": "immich-i18n", - "version": "2.6.1", + "version": "2.6.3", "private": true, "scripts": { "format": "prettier --cache --check .", diff --git a/machine-learning/pyproject.toml b/machine-learning/pyproject.toml index 44911976a1..fd6b61d6c2 100644 --- a/machine-learning/pyproject.toml +++ b/machine-learning/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "immich-ml" -version = "2.6.1" +version = "2.6.3" description = "" authors = [{ name = "Hau Tran", email = "alex.tran1502@gmail.com" }] requires-python = ">=3.11,<4.0" diff --git a/machine-learning/uv.lock b/machine-learning/uv.lock index b24516cb79..e07f942312 100644 --- a/machine-learning/uv.lock +++ b/machine-learning/uv.lock @@ -898,7 +898,7 @@ wheels = [ [[package]] name = "immich-ml" -version = "2.6.1" +version = "2.6.3" source = { editable = "." } dependencies = [ { name = "aiocache" }, diff --git a/mise.toml b/mise.toml index 0ec32de20c..8991680528 100644 --- a/mise.toml +++ b/mise.toml @@ -14,9 +14,9 @@ config_roots = [ ] [tools] -node = "24.13.1" +node = "24.14.0" flutter = "3.35.7" -pnpm = "10.30.3" +pnpm = "10.32.1" terragrunt = "0.99.4" opentofu = "1.11.5" java = "21.0.2" diff --git a/mobile/android/app/src/main/kotlin/app/alextran/immich/core/HttpClientManager.kt b/mobile/android/app/src/main/kotlin/app/alextran/immich/core/HttpClientManager.kt index e7268396e8..cefdf4fbd2 100644 --- a/mobile/android/app/src/main/kotlin/app/alextran/immich/core/HttpClientManager.kt +++ b/mobile/android/app/src/main/kotlin/app/alextran/immich/core/HttpClientManager.kt @@ -23,10 +23,18 @@ import okhttp3.HttpUrl import okhttp3.HttpUrl.Companion.toHttpUrlOrNull import okhttp3.OkHttpClient import org.chromium.net.CronetEngine +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext import kotlinx.serialization.Serializable import kotlinx.serialization.json.Json import java.io.ByteArrayInputStream import java.io.File +import java.io.IOException +import java.nio.file.FileVisitResult +import java.nio.file.Files +import java.nio.file.Path +import java.nio.file.SimpleFileVisitor +import java.nio.file.attribute.BasicFileAttributes import java.net.Authenticator import java.net.CookieHandler import java.net.PasswordAuthentication @@ -277,10 +285,13 @@ object HttpClientManager { return result } - fun rebuildCronetEngine(): CronetEngine { - val old = cronetEngine!! - cronetEngine = buildCronetEngine() - return old + suspend fun rebuildCronetEngine(): Result { + return runCatching { + cronetEngine?.shutdown() + val deletionResult = deleteFolderAndGetSize(cronetStoragePath.toPath()) + cronetEngine = buildCronetEngine() + deletionResult + } } val cronetStoragePath: File get() = cronetStorageDir @@ -301,7 +312,7 @@ object HttpClientManager { } } - private fun buildCronetEngine(): CronetEngine { + fun buildCronetEngine(): CronetEngine { return CronetEngine.Builder(appContext) .enableHttp2(true) .enableQuic(true) @@ -312,6 +323,27 @@ object HttpClientManager { .build() } + private suspend fun deleteFolderAndGetSize(root: Path): Long = withContext(Dispatchers.IO) { + var totalSize = 0L + + Files.walkFileTree(root, object : SimpleFileVisitor() { + override fun visitFile(file: Path, attrs: BasicFileAttributes): FileVisitResult { + totalSize += attrs.size() + Files.delete(file) + return FileVisitResult.CONTINUE + } + + override fun postVisitDirectory(dir: Path, exc: IOException?): FileVisitResult { + if (dir != root) { + Files.delete(dir) + } + return FileVisitResult.CONTINUE + } + }) + + totalSize + } + private fun build(cacheDir: File): OkHttpClient { val connectionPool = ConnectionPool( maxIdleConnections = KEEP_ALIVE_CONNECTIONS, diff --git a/mobile/android/app/src/main/kotlin/app/alextran/immich/images/RemoteImagesImpl.kt b/mobile/android/app/src/main/kotlin/app/alextran/immich/images/RemoteImagesImpl.kt index 8e9fc3f6d5..9255eff44b 100644 --- a/mobile/android/app/src/main/kotlin/app/alextran/immich/images/RemoteImagesImpl.kt +++ b/mobile/android/app/src/main/kotlin/app/alextran/immich/images/RemoteImagesImpl.kt @@ -21,11 +21,6 @@ import java.io.EOFException import java.io.File import java.io.IOException import java.nio.ByteBuffer -import java.nio.file.FileVisitResult -import java.nio.file.Files -import java.nio.file.Path -import java.nio.file.SimpleFileVisitor -import java.nio.file.attribute.BasicFileAttributes import java.util.concurrent.ConcurrentHashMap private class RemoteRequest(val cancellationSignal: CancellationSignal) @@ -205,18 +200,15 @@ private class CronetImageFetcher : ImageFetcher { private fun onDrained() { val onCacheCleared = synchronized(stateLock) { - val onCacheCleared = onCacheCleared + val onCacheCleared = this.onCacheCleared this.onCacheCleared = null onCacheCleared - } - if (onCacheCleared != null) { - val oldEngine = HttpClientManager.rebuildCronetEngine() - oldEngine.shutdown() - CoroutineScope(Dispatchers.IO).launch { - val result = runCatching { deleteFolderAndGetSize(HttpClientManager.cronetStoragePath.toPath()) } - synchronized(stateLock) { draining = false } - onCacheCleared(result) - } + } ?: return + + CoroutineScope(Dispatchers.IO).launch { + val result = HttpClientManager.rebuildCronetEngine() + synchronized(stateLock) { draining = false } + onCacheCleared(result) } } @@ -306,26 +298,6 @@ private class CronetImageFetcher : ImageFetcher { } } - suspend fun deleteFolderAndGetSize(root: Path): Long = withContext(Dispatchers.IO) { - var totalSize = 0L - - Files.walkFileTree(root, object : SimpleFileVisitor() { - override fun visitFile(file: Path, attrs: BasicFileAttributes): FileVisitResult { - totalSize += attrs.size() - Files.delete(file) - return FileVisitResult.CONTINUE - } - - override fun postVisitDirectory(dir: Path, exc: IOException?): FileVisitResult { - if (dir != root) { - Files.delete(dir) - } - return FileVisitResult.CONTINUE - } - }) - - totalSize - } } private class OkHttpImageFetcher private constructor( diff --git a/mobile/android/fastlane/Fastfile b/mobile/android/fastlane/Fastfile index 3cabc0df0f..279b985cfe 100644 --- a/mobile/android/fastlane/Fastfile +++ b/mobile/android/fastlane/Fastfile @@ -35,8 +35,8 @@ platform :android do task: 'bundle', build_type: 'Release', properties: { - "android.injected.version.code" => 3039, - "android.injected.version.name" => "2.6.1", + "android.injected.version.code" => 3041, + "android.injected.version.name" => "2.6.3", } ) upload_to_play_store(skip_upload_apk: true, skip_upload_images: true, skip_upload_screenshots: true, aab: '../build/app/outputs/bundle/release/app-release.aab') diff --git a/mobile/ios/Runner/Core/URLSessionManager.swift b/mobile/ios/Runner/Core/URLSessionManager.swift index 0b73ed71a6..9eb93f9ff9 100644 --- a/mobile/ios/Runner/Core/URLSessionManager.swift +++ b/mobile/ios/Runner/Core/URLSessionManager.swift @@ -150,7 +150,6 @@ class URLSessionManager: NSObject { config.httpCookieStorage = cookieStorage config.httpMaximumConnectionsPerHost = 64 config.timeoutIntervalForRequest = 60 - config.timeoutIntervalForResource = 300 var headers = UserDefaults.group.dictionary(forKey: HEADERS_KEY) as? [String: String] ?? [:] headers["User-Agent"] = headers["User-Agent"] ?? userAgent diff --git a/mobile/ios/Runner/Info.plist b/mobile/ios/Runner/Info.plist index 366d68c313..1bf52807f9 100644 --- a/mobile/ios/Runner/Info.plist +++ b/mobile/ios/Runner/Info.plist @@ -80,7 +80,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 2.6.1 + 2.6.3 CFBundleSignature ???? CFBundleURLTypes diff --git a/mobile/lib/constants/locales.dart b/mobile/lib/constants/locales.dart index e20f037beb..f44aa5cc3e 100644 --- a/mobile/lib/constants/locales.dart +++ b/mobile/lib/constants/locales.dart @@ -7,7 +7,7 @@ const Map locales = { 'Arabic (ar)': Locale('ar'), 'Bulgarian (bg)': Locale('bg'), 'Catalan (ca)': Locale('ca'), - 'Chinese Simplified (zh_CN)': Locale.fromSubtags(languageCode: 'zh', scriptCode: 'SIMPLIFIED'), + 'Chinese Simplified (zh_CN)': Locale.fromSubtags(languageCode: 'zh', scriptCode: 'Hans'), 'Chinese Traditional (zh_TW)': Locale.fromSubtags(languageCode: 'zh', scriptCode: 'Hant'), 'Croatian (hr)': Locale('hr'), 'Czech (cs)': Locale('cs'), diff --git a/mobile/lib/presentation/pages/drift_people_collection.page.dart b/mobile/lib/presentation/pages/drift_people_collection.page.dart index f73dac3af2..d34ce3e776 100644 --- a/mobile/lib/presentation/pages/drift_people_collection.page.dart +++ b/mobile/lib/presentation/pages/drift_people_collection.page.dart @@ -79,6 +79,7 @@ class _DriftPeopleCollectionPageState extends ConsumerState(null); + final hasRequestedSearch = useState(false); final dateInputFilter = useState(null); final peopleCurrentFilterWidget = useState(null); @@ -91,9 +92,11 @@ class DriftSearchPage extends HookConsumerWidget { if (filter.isEmpty) { previousFilter.value = null; + hasRequestedSearch.value = false; return; } + hasRequestedSearch.value = true; unawaited(ref.read(paginatedSearchProvider.notifier).search(filter)); previousFilter.value = filter; } @@ -107,6 +110,8 @@ class DriftSearchPage extends HookConsumerWidget { searchPreFilter() { if (preFilter != null) { Future.delayed(Duration.zero, () { + filter.value = preFilter; + textSearchController.clear(); searchFilter(preFilter); if (preFilter.location.city != null) { @@ -719,7 +724,7 @@ class DriftSearchPage extends HookConsumerWidget { ), ), ), - if (filter.value.isEmpty) + if (!hasRequestedSearch.value) const _SearchSuggestions() else _SearchResultGrid(onScrollEnd: loadMoreSearchResults), diff --git a/mobile/lib/presentation/widgets/action_buttons/similar_photos_action_button.widget.dart b/mobile/lib/presentation/widgets/action_buttons/similar_photos_action_button.widget.dart index 530c3fd8d4..bb42140d0a 100644 --- a/mobile/lib/presentation/widgets/action_buttons/similar_photos_action_button.widget.dart +++ b/mobile/lib/presentation/widgets/action_buttons/similar_photos_action_button.widget.dart @@ -24,20 +24,22 @@ class SimilarPhotosActionButton extends ConsumerWidget { } ref.invalidate(assetViewerProvider); - ref - .read(searchPreFilterProvider.notifier) - .setFilter( - SearchFilter( - assetId: assetId, - people: {}, - location: SearchLocationFilter(), - camera: SearchCameraFilter(), - date: SearchDateFilter(), - display: SearchDisplayFilters(isNotInAlbum: false, isArchive: false, isFavorite: false), - rating: SearchRatingFilter(), - mediaType: AssetType.image, - ), - ); + ref.invalidate(paginatedSearchProvider); + + ref.read(searchPreFilterProvider.notifier) + ..clear() + ..setFilter( + SearchFilter( + assetId: assetId, + people: {}, + location: SearchLocationFilter(), + camera: SearchCameraFilter(), + date: SearchDateFilter(), + display: SearchDisplayFilters(isNotInAlbum: false, isArchive: false, isFavorite: false), + rating: SearchRatingFilter(), + mediaType: AssetType.image, + ), + ); unawaited(context.navigateTo(const DriftSearchRoute())); } diff --git a/mobile/lib/presentation/widgets/asset_viewer/rating_bar.widget.dart b/mobile/lib/presentation/widgets/asset_viewer/rating_bar.widget.dart index 64090dc5c2..62a439fe39 100644 --- a/mobile/lib/presentation/widgets/asset_viewer/rating_bar.widget.dart +++ b/mobile/lib/presentation/widgets/asset_viewer/rating_bar.widget.dart @@ -39,6 +39,16 @@ class _RatingBarState extends State { _currentRating = widget.initialRating; } + @override + void didUpdateWidget(covariant RatingBar oldWidget) { + super.didUpdateWidget(oldWidget); + if (oldWidget.initialRating != widget.initialRating && _currentRating != widget.initialRating) { + setState(() { + _currentRating = widget.initialRating; + }); + } + } + void _updateRating(Offset localPosition, bool isRTL, {bool isTap = false}) { final totalWidth = widget.itemCount * widget.itemSize + (widget.itemCount - 1) * widget.starPadding; double dx = localPosition.dx; diff --git a/mobile/lib/services/auth.service.dart b/mobile/lib/services/auth.service.dart index c5f3fa6a4a..667681e579 100644 --- a/mobile/lib/services/auth.service.dart +++ b/mobile/lib/services/auth.service.dart @@ -67,6 +67,9 @@ class AuthService { bool isValid = false; try { + final urls = ApiService.getServerUrls(); + urls.add(url); + await NetworkRepository.setHeaders(ApiService.getRequestHeaders(), urls); final uri = Uri.parse('$url/users/me'); final response = await NetworkRepository.client.get(uri); if (response.statusCode == 200) { diff --git a/mobile/lib/utils/action_button.utils.dart b/mobile/lib/utils/action_button.utils.dart index 071956392c..2aad2f264a 100644 --- a/mobile/lib/utils/action_button.utils.dart +++ b/mobile/lib/utils/action_button.utils.dart @@ -143,8 +143,7 @@ enum ActionButtonType { !context.isInLockedView && // context.currentAlbum != null, ActionButtonType.setAlbumCover => - context.isOwner && // - !context.isInLockedView && // + !context.isInLockedView && // context.currentAlbum != null && // context.selectedCount == 1, ActionButtonType.unstack => diff --git a/mobile/lib/utils/cache/custom_image_cache.dart b/mobile/lib/utils/cache/custom_image_cache.dart index 99ce0db57c..2c09030ffa 100644 --- a/mobile/lib/utils/cache/custom_image_cache.dart +++ b/mobile/lib/utils/cache/custom_image_cache.dart @@ -20,7 +20,7 @@ final class CustomImageCache implements ImageCache { set maximumSize(int value) => _small.maximumSize = value; @override - set maximumSizeBytes(int value) => _small.maximumSize = value; + set maximumSizeBytes(int value) => _small.maximumSizeBytes = value; @override void clear() { diff --git a/mobile/lib/widgets/search/search_filter/common/dropdown.dart b/mobile/lib/widgets/search/search_filter/common/dropdown.dart index 70cbfd2c15..9d02f4f3e8 100644 --- a/mobile/lib/widgets/search/search_filter/common/dropdown.dart +++ b/mobile/lib/widgets/search/search_filter/common/dropdown.dart @@ -16,9 +16,15 @@ class SearchDropdown extends StatelessWidget { final Widget? label; final Widget? leadingIcon; + static const WidgetStatePropertyAll _optionPadding = WidgetStatePropertyAll( + EdgeInsetsDirectional.fromSTEB(16, 0, 16, 0), + ); + @override Widget build(BuildContext context) { - final menuStyle = const MenuStyle( + final mediaQuery = MediaQuery.of(context); + final maxMenuHeight = mediaQuery.size.height * 0.5 - mediaQuery.viewPadding.bottom; + const menuStyle = MenuStyle( shape: WidgetStatePropertyAll( RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(15))), ), @@ -26,11 +32,26 @@ class SearchDropdown extends StatelessWidget { return LayoutBuilder( builder: (context, constraints) { + final styledEntries = dropdownMenuEntries + .map( + (entry) => DropdownMenuEntry( + value: entry.value, + label: entry.label, + labelWidget: entry.labelWidget, + enabled: entry.enabled, + leadingIcon: entry.leadingIcon, + trailingIcon: entry.trailingIcon, + style: (entry.style ?? const ButtonStyle()).copyWith(padding: _optionPadding), + ), + ) + .toList(growable: false); + return DropdownMenu( controller: controller, leadingIcon: leadingIcon, width: constraints.maxWidth, - dropdownMenuEntries: dropdownMenuEntries, + menuHeight: maxMenuHeight, + dropdownMenuEntries: styledEntries, label: label, menuStyle: menuStyle, trailingIcon: const Icon(Icons.arrow_drop_down_rounded), diff --git a/mobile/openapi/README.md b/mobile/openapi/README.md index ceb41ac7bb..500de51622 100644 --- a/mobile/openapi/README.md +++ b/mobile/openapi/README.md @@ -3,7 +3,7 @@ Immich API This Dart package is automatically generated by the [OpenAPI Generator](https://openapi-generator.tech) project: -- API version: 2.6.1 +- API version: 2.6.3 - Generator version: 7.8.0 - Build package: org.openapitools.codegen.languages.DartClientCodegen diff --git a/mobile/openapi/lib/model/metadata_search_dto.dart b/mobile/openapi/lib/model/metadata_search_dto.dart index 81f8d41527..4dbc90d407 100644 --- a/mobile/openapi/lib/model/metadata_search_dto.dart +++ b/mobile/openapi/lib/model/metadata_search_dto.dart @@ -379,7 +379,7 @@ class MetadataSearchDto { /// bool? withExif; - /// Include assets with people + /// Include people data in response /// /// Please note: This property should have been non-nullable! Since the specification file /// does not include a default value (using the "default:" property), however, the generated diff --git a/mobile/openapi/lib/model/random_search_dto.dart b/mobile/openapi/lib/model/random_search_dto.dart index 4166fc9f3c..d5803c9cc7 100644 --- a/mobile/openapi/lib/model/random_search_dto.dart +++ b/mobile/openapi/lib/model/random_search_dto.dart @@ -273,7 +273,7 @@ class RandomSearchDto { /// bool? withExif; - /// Include assets with people + /// Include people data in response /// /// Please note: This property should have been non-nullable! Since the specification file /// does not include a default value (using the "default:" property), however, the generated diff --git a/mobile/pubspec.yaml b/mobile/pubspec.yaml index 201f4395a3..c5839fb9be 100644 --- a/mobile/pubspec.yaml +++ b/mobile/pubspec.yaml @@ -2,7 +2,7 @@ name: immich_mobile description: Immich - selfhosted backup media file on mobile phone publish_to: 'none' -version: 2.6.1+3039 +version: 2.6.3+3041 environment: sdk: '>=3.8.0 <4.0.0' diff --git a/mobile/test/utils/action_button_utils_test.dart b/mobile/test/utils/action_button_utils_test.dart index b5540f9dc7..9956dfa2d0 100644 --- a/mobile/test/utils/action_button_utils_test.dart +++ b/mobile/test/utils/action_button_utils_test.dart @@ -727,7 +727,7 @@ void main() { expect(ActionButtonType.setAlbumCover.shouldShow(context), isTrue); }); - test('should not show when not owner', () { + test('should show when not owner', () { final album = createRemoteAlbum(); final context = ActionButtonContext( asset: mergedAsset, @@ -742,7 +742,7 @@ void main() { selectedCount: 1, ); - expect(ActionButtonType.setAlbumCover.shouldShow(context), isFalse); + expect(ActionButtonType.setAlbumCover.shouldShow(context), isTrue); }); test('should not show when in locked view', () { diff --git a/open-api/immich-openapi-specs.json b/open-api/immich-openapi-specs.json index dfca8737f8..f9bfc0639f 100644 --- a/open-api/immich-openapi-specs.json +++ b/open-api/immich-openapi-specs.json @@ -15166,7 +15166,7 @@ "info": { "title": "Immich", "description": "Immich API", - "version": "2.6.1", + "version": "2.6.3", "contact": {} }, "tags": [ @@ -19129,7 +19129,7 @@ "type": "boolean" }, "withPeople": { - "description": "Include assets with people", + "description": "Include people data in response", "type": "boolean" }, "withStacked": { @@ -20868,7 +20868,7 @@ "type": "boolean" }, "withPeople": { - "description": "Include assets with people", + "description": "Include people data in response", "type": "boolean" }, "withStacked": { diff --git a/open-api/typescript-sdk/.nvmrc b/open-api/typescript-sdk/.nvmrc index 32f8c50de0..d845d9d88d 100644 --- a/open-api/typescript-sdk/.nvmrc +++ b/open-api/typescript-sdk/.nvmrc @@ -1 +1 @@ -24.13.1 +24.14.0 diff --git a/open-api/typescript-sdk/package.json b/open-api/typescript-sdk/package.json index 42184f3841..1a2d6fe79d 100644 --- a/open-api/typescript-sdk/package.json +++ b/open-api/typescript-sdk/package.json @@ -1,6 +1,6 @@ { "name": "@immich/sdk", - "version": "2.6.1", + "version": "2.6.3", "description": "Auto-generated TypeScript SDK for the Immich API", "type": "module", "main": "./build/index.js", @@ -19,7 +19,7 @@ "@oazapfts/runtime": "^1.0.2" }, "devDependencies": { - "@types/node": "^24.11.0", + "@types/node": "^24.12.0", "typescript": "^5.3.3" }, "repository": { @@ -28,6 +28,6 @@ "directory": "open-api/typescript-sdk" }, "volta": { - "node": "24.13.1" + "node": "24.14.0" } } diff --git a/open-api/typescript-sdk/src/fetch-client.ts b/open-api/typescript-sdk/src/fetch-client.ts index 3f87aa82ef..257bf668d0 100644 --- a/open-api/typescript-sdk/src/fetch-client.ts +++ b/open-api/typescript-sdk/src/fetch-client.ts @@ -1,6 +1,6 @@ /** * Immich - * 2.6.1 + * 2.6.3 * DO NOT MODIFY - This file has been generated using oazapfts. * See https://www.npmjs.com/package/oazapfts */ @@ -1741,7 +1741,7 @@ export type MetadataSearchDto = { withDeleted?: boolean; /** Include EXIF data in response */ withExif?: boolean; - /** Include assets with people */ + /** Include people data in response */ withPeople?: boolean; /** Include stacked assets */ withStacked?: boolean; @@ -1855,7 +1855,7 @@ export type RandomSearchDto = { withDeleted?: boolean; /** Include EXIF data in response */ withExif?: boolean; - /** Include assets with people */ + /** Include people data in response */ withPeople?: boolean; /** Include stacked assets */ withStacked?: boolean; diff --git a/package.json b/package.json index 7e323425ea..e33d46df96 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,9 @@ { "name": "immich-monorepo", - "version": "2.6.1", + "version": "2.6.3", "description": "Monorepo for Immich", "private": true, - "packageManager": "pnpm@10.30.3+sha512.c961d1e0a2d8e354ecaa5166b822516668b7f44cb5bd95122d590dd81922f606f5473b6d23ec4a5be05e7fcd18e8488d47d978bbe981872f1145d06e9a740017", + "packageManager": "pnpm@10.32.1+sha512.a706938f0e89ac1456b6563eab4edf1d1faf3368d1191fc5c59790e96dc918e4456ab2e67d613de1043d2e8c81f87303e6b40d4ffeca9df15ef1ad567348f2be", "engines": { "pnpm": ">=10.0.0" } diff --git a/plugins/package-lock.json b/plugins/package-lock.json index 9ebaa59a02..3f004d7dba 100644 --- a/plugins/package-lock.json +++ b/plugins/package-lock.json @@ -15,9 +15,9 @@ } }, "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==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.4.tgz", + "integrity": "sha512-cQPwL2mp2nSmHHJlCyoXgHGhbEPMrEEU5xhkcy3Hs/O7nGZqEpZ2sUtLaL9MORLtDfRvVl2/3PAuEkYZH0Ty8Q==", "cpu": [ "ppc64" ], @@ -32,9 +32,9 @@ } }, "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==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.4.tgz", + "integrity": "sha512-X9bUgvxiC8CHAGKYufLIHGXPJWnr0OCdR0anD2e21vdvgCI8lIfqFbnoeOz7lBjdrAGUhqLZLcQo6MLhTO2DKQ==", "cpu": [ "arm" ], @@ -49,9 +49,9 @@ } }, "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==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.4.tgz", + "integrity": "sha512-gdLscB7v75wRfu7QSm/zg6Rx29VLdy9eTr2t44sfTW7CxwAtQghZ4ZnqHk3/ogz7xao0QAgrkradbBzcqFPasw==", "cpu": [ "arm64" ], @@ -66,9 +66,9 @@ } }, "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==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.4.tgz", + "integrity": "sha512-PzPFnBNVF292sfpfhiyiXCGSn9HZg5BcAz+ivBuSsl6Rk4ga1oEXAamhOXRFyMcjwr2DVtm40G65N3GLeH1Lvw==", "cpu": [ "x64" ], @@ -83,9 +83,9 @@ } }, "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==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.4.tgz", + "integrity": "sha512-b7xaGIwdJlht8ZFCvMkpDN6uiSmnxxK56N2GDTMYPr2/gzvfdQN8rTfBsvVKmIVY/X7EM+/hJKEIbbHs9oA4tQ==", "cpu": [ "arm64" ], @@ -100,9 +100,9 @@ } }, "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==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.4.tgz", + "integrity": "sha512-sR+OiKLwd15nmCdqpXMnuJ9W2kpy0KigzqScqHI3Hqwr7IXxBp3Yva+yJwoqh7rE8V77tdoheRYataNKL4QrPw==", "cpu": [ "x64" ], @@ -117,9 +117,9 @@ } }, "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==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.4.tgz", + "integrity": "sha512-jnfpKe+p79tCnm4GVav68A7tUFeKQwQyLgESwEAUzyxk/TJr4QdGog9sqWNcUbr/bZt/O/HXouspuQDd9JxFSw==", "cpu": [ "arm64" ], @@ -134,9 +134,9 @@ } }, "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==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.4.tgz", + "integrity": "sha512-2kb4ceA/CpfUrIcTUl1wrP/9ad9Atrp5J94Lq69w7UwOMolPIGrfLSvAKJp0RTvkPPyn6CIWrNy13kyLikZRZQ==", "cpu": [ "x64" ], @@ -151,9 +151,9 @@ } }, "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==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.4.tgz", + "integrity": "sha512-aBYgcIxX/wd5n2ys0yESGeYMGF+pv6g0DhZr3G1ZG4jMfruU9Tl1i2Z+Wnj9/KjGz1lTLCcorqE2viePZqj4Eg==", "cpu": [ "arm" ], @@ -168,9 +168,9 @@ } }, "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==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.4.tgz", + "integrity": "sha512-7nQOttdzVGth1iz57kxg9uCz57dxQLHWxopL6mYuYthohPKEK0vU0C3O21CcBK6KDlkYVcnDXY099HcCDXd9dA==", "cpu": [ "arm64" ], @@ -185,9 +185,9 @@ } }, "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==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.4.tgz", + "integrity": "sha512-oPtixtAIzgvzYcKBQM/qZ3R+9TEUd1aNJQu0HhGyqtx6oS7qTpvjheIWBbes4+qu1bNlo2V4cbkISr8q6gRBFA==", "cpu": [ "ia32" ], @@ -202,9 +202,9 @@ } }, "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==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.4.tgz", + "integrity": "sha512-8mL/vh8qeCoRcFH2nM8wm5uJP+ZcVYGGayMavi8GmRJjuI3g1v6Z7Ni0JJKAJW+m0EtUuARb6Lmp4hMjzCBWzA==", "cpu": [ "loong64" ], @@ -219,9 +219,9 @@ } }, "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==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.4.tgz", + "integrity": "sha512-1RdrWFFiiLIW7LQq9Q2NES+HiD4NyT8Itj9AUeCl0IVCA459WnPhREKgwrpaIfTOe+/2rdntisegiPWn/r/aAw==", "cpu": [ "mips64el" ], @@ -236,9 +236,9 @@ } }, "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==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.4.tgz", + "integrity": "sha512-tLCwNG47l3sd9lpfyx9LAGEGItCUeRCWeAx6x2Jmbav65nAwoPXfewtAdtbtit/pJFLUWOhpv0FpS6GQAmPrHA==", "cpu": [ "ppc64" ], @@ -253,9 +253,9 @@ } }, "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==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.4.tgz", + "integrity": "sha512-BnASypppbUWyqjd1KIpU4AUBiIhVr6YlHx/cnPgqEkNoVOhHg+YiSVxM1RLfiy4t9cAulbRGTNCKOcqHrEQLIw==", "cpu": [ "riscv64" ], @@ -270,9 +270,9 @@ } }, "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==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.4.tgz", + "integrity": "sha512-+eUqgb/Z7vxVLezG8bVB9SfBie89gMueS+I0xYh2tJdw3vqA/0ImZJ2ROeWwVJN59ihBeZ7Tu92dF/5dy5FttA==", "cpu": [ "s390x" ], @@ -287,9 +287,9 @@ } }, "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==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.4.tgz", + "integrity": "sha512-S5qOXrKV8BQEzJPVxAwnryi2+Iq5pB40gTEIT69BQONqR7JH1EPIcQ/Uiv9mCnn05jff9umq/5nqzxlqTOg9NA==", "cpu": [ "x64" ], @@ -304,9 +304,9 @@ } }, "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==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.4.tgz", + "integrity": "sha512-xHT8X4sb0GS8qTqiwzHqpY00C95DPAq7nAwX35Ie/s+LO9830hrMd3oX0ZMKLvy7vsonee73x0lmcdOVXFzd6Q==", "cpu": [ "arm64" ], @@ -321,9 +321,9 @@ } }, "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==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.4.tgz", + "integrity": "sha512-RugOvOdXfdyi5Tyv40kgQnI0byv66BFgAqjdgtAKqHoZTbTF2QqfQrFwa7cHEORJf6X2ht+l9ABLMP0dnKYsgg==", "cpu": [ "x64" ], @@ -338,9 +338,9 @@ } }, "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==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.4.tgz", + "integrity": "sha512-2MyL3IAaTX+1/qP0O1SwskwcwCoOI4kV2IBX1xYnDDqthmq5ArrW94qSIKCAuRraMgPOmG0RDTA74mzYNQA9ow==", "cpu": [ "arm64" ], @@ -355,9 +355,9 @@ } }, "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==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.4.tgz", + "integrity": "sha512-u8fg/jQ5aQDfsnIV6+KwLOf1CmJnfu1ShpwqdwC0uA7ZPwFws55Ngc12vBdeUdnuWoQYx/SOQLGDcdlfXhYmXQ==", "cpu": [ "x64" ], @@ -372,9 +372,9 @@ } }, "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==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.4.tgz", + "integrity": "sha512-JkTZrl6VbyO8lDQO3yv26nNr2RM2yZzNrNHEsj9bm6dOwwu9OYN28CjzZkH57bh4w0I2F7IodpQvUAEd1mbWXg==", "cpu": [ "arm64" ], @@ -389,9 +389,9 @@ } }, "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==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.4.tgz", + "integrity": "sha512-/gOzgaewZJfeJTlsWhvUEmUG4tWEY2Spp5M20INYRg2ZKl9QPO3QEEgPeRtLjEWSW8FilRNacPOg8R1uaYkA6g==", "cpu": [ "x64" ], @@ -406,9 +406,9 @@ } }, "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==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.4.tgz", + "integrity": "sha512-Z9SExBg2y32smoDQdf1HRwHRt6vAHLXcxD2uGgO/v2jK7Y718Ix4ndsbNMU/+1Qiem9OiOdaqitioZwxivhXYg==", "cpu": [ "arm64" ], @@ -423,9 +423,9 @@ } }, "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==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.4.tgz", + "integrity": "sha512-DAyGLS0Jz5G5iixEbMHi5KdiApqHBWMGzTtMiJ72ZOLhbu/bzxgAe8Ue8CTS3n3HbIUHQz/L51yMdGMeoxXNJw==", "cpu": [ "ia32" ], @@ -440,9 +440,9 @@ } }, "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==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.4.tgz", + "integrity": "sha512-+knoa0BDoeXgkNvvV1vvbZX4+hizelrkwmGJBdT17t8FNPwG2lKemmuMZlmaNQ3ws3DKKCxpb4zRZEIp3UxFCg==", "cpu": [ "x64" ], @@ -467,9 +467,9 @@ } }, "node_modules/esbuild": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", - "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.4.tgz", + "integrity": "sha512-Rq4vbHnYkK5fws5NF7MYTU68FPRE1ajX7heQ/8QXXWqNgqqJ/GkmmyxIzUnf2Sr/bakf8l54716CcMGHYhMrrQ==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -480,32 +480,32 @@ "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" + "@esbuild/aix-ppc64": "0.27.4", + "@esbuild/android-arm": "0.27.4", + "@esbuild/android-arm64": "0.27.4", + "@esbuild/android-x64": "0.27.4", + "@esbuild/darwin-arm64": "0.27.4", + "@esbuild/darwin-x64": "0.27.4", + "@esbuild/freebsd-arm64": "0.27.4", + "@esbuild/freebsd-x64": "0.27.4", + "@esbuild/linux-arm": "0.27.4", + "@esbuild/linux-arm64": "0.27.4", + "@esbuild/linux-ia32": "0.27.4", + "@esbuild/linux-loong64": "0.27.4", + "@esbuild/linux-mips64el": "0.27.4", + "@esbuild/linux-ppc64": "0.27.4", + "@esbuild/linux-riscv64": "0.27.4", + "@esbuild/linux-s390x": "0.27.4", + "@esbuild/linux-x64": "0.27.4", + "@esbuild/netbsd-arm64": "0.27.4", + "@esbuild/netbsd-x64": "0.27.4", + "@esbuild/openbsd-arm64": "0.27.4", + "@esbuild/openbsd-x64": "0.27.4", + "@esbuild/openharmony-arm64": "0.27.4", + "@esbuild/sunos-x64": "0.27.4", + "@esbuild/win32-arm64": "0.27.4", + "@esbuild/win32-ia32": "0.27.4", + "@esbuild/win32-x64": "0.27.4" } }, "node_modules/typescript": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4826666b24..75ccb8fe35 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -43,7 +43,7 @@ importers: devDependencies: '@eslint/js': specifier: ^10.0.0 - version: 10.0.1(eslint@10.0.2(jiti@2.6.1)) + version: 10.0.1(eslint@10.1.0(jiti@2.6.1)) '@immich/sdk': specifier: workspace:* version: link:../open-api/typescript-sdk @@ -63,11 +63,11 @@ importers: specifier: ^4.13.1 version: 4.13.4 '@types/node': - specifier: ^24.11.0 + specifier: ^24.12.0 version: 24.12.0 '@vitest/coverage-v8': specifier: ^4.0.0 - version: 4.0.18(vitest@4.0.18(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.3)(jiti@2.6.1)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + version: 4.1.0(vitest@4.1.0(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.4)(jsdom@26.1.0(canvas@2.11.2))(vite@8.0.1(@types/node@24.12.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))) byte-size: specifier: ^9.0.0 version: 9.0.1 @@ -79,16 +79,16 @@ importers: version: 12.1.0 eslint: specifier: ^10.0.0 - version: 10.0.2(jiti@2.6.1) + version: 10.1.0(jiti@2.6.1) eslint-config-prettier: specifier: ^10.1.8 - version: 10.1.8(eslint@10.0.2(jiti@2.6.1)) + version: 10.1.8(eslint@10.1.0(jiti@2.6.1)) eslint-plugin-prettier: specifier: ^5.1.3 - version: 5.5.5(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@10.0.2(jiti@2.6.1)))(eslint@10.0.2(jiti@2.6.1))(prettier@3.8.1) + version: 5.5.5(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@10.1.0(jiti@2.6.1)))(eslint@10.1.0(jiti@2.6.1))(prettier@3.8.1) eslint-plugin-unicorn: specifier: ^63.0.0 - version: 63.0.0(eslint@10.0.2(jiti@2.6.1)) + version: 63.0.0(eslint@10.1.0(jiti@2.6.1)) globals: specifier: ^17.0.0 version: 17.4.0 @@ -106,22 +106,19 @@ importers: version: 5.9.3 typescript-eslint: specifier: ^8.28.0 - version: 8.56.1(eslint@10.0.2(jiti@2.6.1))(typescript@5.9.3) + version: 8.57.1(eslint@10.1.0(jiti@2.6.1))(typescript@5.9.3) vite: - specifier: ^7.0.0 - version: 7.3.1(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) - vite-tsconfig-paths: - specifier: ^6.0.0 - version: 6.1.1(typescript@5.9.3)(vite@7.3.1(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + specifier: ^8.0.0 + version: 8.0.1(@types/node@24.12.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3) vitest: specifier: ^4.0.0 - version: 4.0.18(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.3)(jiti@2.6.1)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + version: 4.1.0(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.4)(jsdom@26.1.0(canvas@2.11.2))(vite@8.0.1(@types/node@24.12.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) vitest-fetch-mock: specifier: ^0.4.0 - version: 0.4.5(vitest@4.0.18(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.3)(jiti@2.6.1)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + version: 0.4.5(vitest@4.1.0(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.4)(jsdom@26.1.0(canvas@2.11.2))(vite@8.0.1(@types/node@24.12.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))) yaml: specifier: ^2.3.1 - version: 2.8.2 + version: 2.8.3 docs: dependencies: @@ -172,7 +169,7 @@ importers: version: 18.3.1(react@18.3.1) tailwindcss: specifier: ^3.2.4 - version: 3.4.19(tsx@4.21.0)(yaml@2.8.2) + version: 3.4.19(tsx@4.21.0)(yaml@2.8.3) url: specifier: ^0.11.0 version: 0.11.4 @@ -197,7 +194,7 @@ importers: devDependencies: '@eslint/js': specifier: ^10.0.0 - version: 10.0.1(eslint@10.0.2(jiti@2.6.1)) + version: 10.0.1(eslint@10.1.0(jiti@2.6.1)) '@faker-js/faker': specifier: ^10.1.0 version: 10.3.0 @@ -220,11 +217,11 @@ importers: specifier: ^3.4.2 version: 3.7.1 '@types/node': - specifier: ^24.11.0 + specifier: ^24.12.0 version: 24.12.0 '@types/pg': specifier: ^8.15.1 - version: 8.18.0 + version: 8.20.0 '@types/pngjs': specifier: ^6.0.4 version: 6.0.5 @@ -236,16 +233,16 @@ importers: version: 17.3.1 eslint: specifier: ^10.0.0 - version: 10.0.2(jiti@2.6.1) + version: 10.1.0(jiti@2.6.1) eslint-config-prettier: specifier: ^10.1.8 - version: 10.1.8(eslint@10.0.2(jiti@2.6.1)) + version: 10.1.8(eslint@10.1.0(jiti@2.6.1)) eslint-plugin-prettier: specifier: ^5.1.3 - version: 5.5.5(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@10.0.2(jiti@2.6.1)))(eslint@10.0.2(jiti@2.6.1))(prettier@3.8.1) + version: 5.5.5(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@10.1.0(jiti@2.6.1)))(eslint@10.1.0(jiti@2.6.1))(prettier@3.8.1) eslint-plugin-unicorn: specifier: ^63.0.0 - version: 63.0.0(eslint@10.0.2(jiti@2.6.1)) + version: 63.0.0(eslint@10.1.0(jiti@2.6.1)) exiftool-vendored: specifier: ^35.0.0 version: 35.13.1 @@ -281,16 +278,16 @@ importers: version: 5.9.3 typescript-eslint: specifier: ^8.28.0 - version: 8.56.1(eslint@10.0.2(jiti@2.6.1))(typescript@5.9.3) + version: 8.57.1(eslint@10.1.0(jiti@2.6.1))(typescript@5.9.3) utimes: specifier: ^5.2.1 version: 5.2.1(encoding@0.1.13) vite-tsconfig-paths: specifier: ^6.1.1 - version: 6.1.1(typescript@5.9.3)(vite@7.3.1(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + version: 6.1.1(typescript@5.9.3)(vite@8.0.1(@types/node@24.12.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) vitest: specifier: ^4.0.0 - version: 4.0.18(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.3)(jiti@2.6.1)(jsdom@26.1.0(canvas@2.11.2(encoding@0.1.13)))(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + version: 4.1.0(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.4)(jsdom@26.1.0(canvas@2.11.2(encoding@0.1.13)))(vite@8.0.1(@types/node@24.12.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) e2e-auth-server: devDependencies: @@ -302,7 +299,7 @@ importers: version: 5.10.0 oidc-provider: specifier: ^9.0.0 - version: 9.6.1 + version: 9.7.1 tsx: specifier: ^4.20.6 version: 4.21.0 @@ -323,7 +320,7 @@ importers: version: 1.2.0 devDependencies: '@types/node': - specifier: ^24.11.0 + specifier: ^24.12.0 version: 24.12.0 typescript: specifier: ^5.3.3 @@ -336,7 +333,7 @@ importers: version: 1.1.1 esbuild: specifier: ^0.27.0 - version: 0.27.3 + version: 0.27.4 typescript: specifier: ^5.3.2 version: 5.9.3 @@ -351,28 +348,28 @@ importers: version: 0.3.2 '@nestjs/bullmq': specifier: ^11.0.1 - version: 11.0.4(@nestjs/common@11.1.16(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.16)(bullmq@5.70.4) + version: 11.0.4(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17)(bullmq@5.71.0) '@nestjs/common': specifier: ^11.0.4 - version: 11.1.16(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) + version: 11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) '@nestjs/core': specifier: ^11.0.4 - version: 11.1.16(@nestjs/common@11.1.16(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.16)(@nestjs/websockets@11.1.16)(reflect-metadata@0.2.2)(rxjs@7.8.2) + version: 11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(@nestjs/websockets@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2) '@nestjs/platform-express': specifier: ^11.0.4 - version: 11.1.16(@nestjs/common@11.1.16(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.16) + version: 11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17) '@nestjs/platform-socket.io': specifier: ^11.0.4 - version: 11.1.16(@nestjs/common@11.1.16(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/websockets@11.1.16)(rxjs@7.8.2) + version: 11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/websockets@11.1.17)(rxjs@7.8.2) '@nestjs/schedule': specifier: ^6.0.0 - version: 6.1.1(@nestjs/common@11.1.16(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.16) + version: 6.1.1(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17) '@nestjs/swagger': specifier: ^11.0.2 - version: 11.2.6(@nestjs/common@11.1.16(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.16)(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2) + version: 11.2.6(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17)(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2) '@nestjs/websockets': specifier: ^11.0.4 - version: 11.1.16(@nestjs/common@11.1.16(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.16)(@nestjs/platform-socket.io@11.1.16)(reflect-metadata@0.2.2)(rxjs@7.8.2) + version: 11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17)(@nestjs/platform-socket.io@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2) '@opentelemetry/api': specifier: ^1.9.0 version: 1.9.0 @@ -432,7 +429,7 @@ importers: version: 2.2.2 bullmq: specifier: ^5.51.0 - version: 5.70.4 + version: 5.71.0 chokidar: specifier: ^4.0.3 version: 4.0.3 @@ -468,16 +465,19 @@ importers: version: 2.1.3 geo-tz: specifier: ^8.0.0 - version: 8.1.5 + version: 8.1.6 handlebars: specifier: ^4.7.8 version: 4.7.8 + helmet: + specifier: ^8.1.0 + version: 8.1.0 i18n-iso-countries: specifier: ^7.6.0 version: 7.14.0 ioredis: specifier: ^5.8.2 - version: 5.10.0 + version: 5.10.1 jose: specifier: ^5.10.0 version: 5.10.0 @@ -488,11 +488,11 @@ importers: specifier: ^9.0.2 version: 9.0.3 kysely: - specifier: 0.28.11 - version: 0.28.11 + specifier: 0.28.14 + version: 0.28.14 kysely-postgres-js: specifier: ^3.0.0 - version: 3.0.0(kysely@0.28.11)(postgres@3.4.8) + version: 3.0.0(kysely@0.28.14)(postgres@3.4.8) lodash: specifier: ^4.17.21 version: 4.17.23 @@ -507,16 +507,16 @@ importers: version: 2.1.1 nest-commander: specifier: ^3.16.0 - version: 3.20.1(@nestjs/common@11.1.16(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.16)(@types/inquirer@8.2.12)(@types/node@24.12.0)(typescript@5.9.3) + version: 3.20.1(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17)(@types/inquirer@8.2.12)(@types/node@24.12.0)(typescript@5.9.3) nestjs-cls: specifier: ^5.0.0 - version: 5.4.3(@nestjs/common@11.1.16(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.16)(reflect-metadata@0.2.2)(rxjs@7.8.2) + version: 5.4.3(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2) nestjs-kysely: specifier: 3.1.2 - version: 3.1.2(@nestjs/common@11.1.16(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.16)(kysely@0.28.11)(reflect-metadata@0.2.2) + version: 3.1.2(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17)(kysely@0.28.14)(reflect-metadata@0.2.2) nestjs-otel: specifier: ^7.0.0 - version: 7.0.1(@nestjs/common@11.1.16(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.16) + version: 7.0.1(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17) nodemailer: specifier: ^7.0.0 version: 7.0.13 @@ -531,7 +531,7 @@ importers: version: 2.12.0 picomatch: specifier: ^4.0.2 - version: 4.0.3 + version: 4.0.4 postgres: specifier: 3.4.8 version: 3.4.8 @@ -552,10 +552,10 @@ importers: version: 7.8.2 sanitize-filename: specifier: ^1.6.3 - version: 1.6.3 + version: 1.6.4 sanitize-html: specifier: ^2.14.0 - version: 2.17.1 + version: 2.17.2 semver: specifier: ^7.6.2 version: 7.7.4 @@ -570,7 +570,7 @@ importers: version: 4.8.3 tailwindcss-preset-email: specifier: ^1.4.0 - version: 1.4.1(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.2)) + version: 1.4.1(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.3)) thumbhash: specifier: ^0.1.1 version: 0.1.1 @@ -589,16 +589,16 @@ importers: devDependencies: '@eslint/js': specifier: ^10.0.0 - version: 10.0.1(eslint@10.0.2(jiti@2.6.1)) + version: 10.0.1(eslint@10.1.0(jiti@2.6.1)) '@nestjs/cli': specifier: ^11.0.2 - version: 11.0.16(@swc/core@1.15.18(@swc/helpers@0.5.17))(@types/node@24.12.0) + version: 11.0.16(@swc/core@1.15.18(@swc/helpers@0.5.17))(@types/node@24.12.0)(esbuild@0.27.4) '@nestjs/schematics': specifier: ^11.0.0 version: 11.0.9(chokidar@4.0.3)(typescript@5.9.3) '@nestjs/testing': specifier: ^11.0.4 - version: 11.1.16(@nestjs/common@11.1.16(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.16)(@nestjs/platform-express@11.1.16) + version: 11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17)(@nestjs/platform-express@11.1.17) '@swc/core': specifier: ^1.4.14 version: 1.15.18(@swc/helpers@0.5.17) @@ -645,7 +645,7 @@ importers: specifier: ^2.0.0 version: 2.1.0 '@types/node': - specifier: ^24.11.0 + specifier: ^24.12.0 version: 24.12.0 '@types/nodemailer': specifier: ^7.0.0 @@ -676,19 +676,19 @@ importers: version: 13.15.10 '@vitest/coverage-v8': specifier: ^3.0.0 - version: 3.2.4(vitest@3.2.4(@types/debug@4.1.12)(@types/node@24.12.0)(happy-dom@20.8.3)(jiti@2.6.1)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + version: 3.2.4(vitest@3.2.4(@types/debug@4.1.12)(@types/node@24.12.0)(happy-dom@20.8.4)(jiti@2.6.1)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.32.0)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) eslint: specifier: ^10.0.0 - version: 10.0.2(jiti@2.6.1) + version: 10.1.0(jiti@2.6.1) eslint-config-prettier: specifier: ^10.1.8 - version: 10.1.8(eslint@10.0.2(jiti@2.6.1)) + version: 10.1.8(eslint@10.1.0(jiti@2.6.1)) eslint-plugin-prettier: specifier: ^5.1.3 - version: 5.5.5(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@10.0.2(jiti@2.6.1)))(eslint@10.0.2(jiti@2.6.1))(prettier@3.8.1) + version: 5.5.5(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@10.1.0(jiti@2.6.1)))(eslint@10.1.0(jiti@2.6.1))(prettier@3.8.1) eslint-plugin-unicorn: specifier: ^63.0.0 - version: 63.0.0(eslint@10.0.2(jiti@2.6.1)) + version: 63.0.0(eslint@10.1.0(jiti@2.6.1)) globals: specifier: ^17.0.0 version: 17.4.0 @@ -715,31 +715,31 @@ importers: version: 7.2.2 tailwindcss: specifier: ^3.4.0 - version: 3.4.19(tsx@4.21.0)(yaml@2.8.2) + version: 3.4.19(tsx@4.21.0)(yaml@2.8.3) testcontainers: specifier: ^11.0.0 - version: 11.12.0 + version: 11.13.0 typescript: specifier: ^5.9.2 version: 5.9.3 typescript-eslint: specifier: ^8.28.0 - version: 8.56.1(eslint@10.0.2(jiti@2.6.1))(typescript@5.9.3) + version: 8.57.1(eslint@10.1.0(jiti@2.6.1))(typescript@5.9.3) unplugin-swc: specifier: ^1.4.5 version: 1.5.9(@swc/core@1.15.18(@swc/helpers@0.5.17))(rollup@4.55.1) vite-tsconfig-paths: specifier: ^6.0.0 - version: 6.1.1(typescript@5.9.3)(vite@7.3.1(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + version: 6.1.1(typescript@5.9.3)(vite@8.0.1(@types/node@24.12.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) vitest: specifier: ^3.0.0 - version: 3.2.4(@types/debug@4.1.12)(@types/node@24.12.0)(happy-dom@20.8.3)(jiti@2.6.1)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + version: 3.2.4(@types/debug@4.1.12)(@types/node@24.12.0)(happy-dom@20.8.4)(jiti@2.6.1)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.32.0)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3) web: dependencies: '@formatjs/icu-messageformat-parser': specifier: ^3.0.0 - version: 3.5.1 + version: 3.5.3 '@immich/justified-layout-wasm': specifier: ^0.4.3 version: 0.4.3 @@ -747,8 +747,8 @@ importers: specifier: workspace:* version: link:../open-api/typescript-sdk '@immich/ui': - specifier: ^0.65.3 - version: 0.65.3(@sveltejs/kit@2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.7)(vite@7.3.1(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(svelte@5.53.7)(typescript@5.9.3)(vite@7.3.1(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(svelte@5.53.7) + specifier: ^0.69.0 + version: 0.69.0(@sveltejs/kit@2.55.0(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.54.1)(vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)))(svelte@5.54.1)(typescript@5.9.3)(vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)))(svelte@5.54.1) '@mapbox/mapbox-gl-rtl-text': specifier: 0.3.0 version: 0.3.0 @@ -781,7 +781,7 @@ importers: version: 0.42.0 '@zoom-image/svelte': specifier: ^0.3.0 - version: 0.3.9(svelte@5.53.7) + version: 0.3.9(svelte@5.54.1) dom-to-image: specifier: ^2.6.0 version: 2.6.0 @@ -799,10 +799,10 @@ importers: version: 4.7.8 happy-dom: specifier: ^20.0.0 - version: 20.8.3 + version: 20.8.4 intl-messageformat: specifier: ^11.0.0 - version: 11.1.2 + version: 11.2.0 justified-layout: specifier: ^4.1.0 version: 4.1.0 @@ -814,7 +814,7 @@ importers: version: 3.7.2 maplibre-gl: specifier: ^5.6.2 - version: 5.19.0 + version: 5.21.0 pmtiles: specifier: ^4.3.0 version: 4.4.0 @@ -832,16 +832,16 @@ importers: version: 5.2.2 svelte-i18n: specifier: ^4.0.1 - version: 4.0.1(svelte@5.53.7) + version: 4.0.1(svelte@5.54.1) svelte-jsoneditor: specifier: ^3.10.0 - version: 3.11.0(svelte@5.53.7) + version: 3.11.0(svelte@5.54.1) svelte-maplibre: specifier: ^1.2.5 - version: 1.2.6(svelte@5.53.7) + version: 1.2.6(svelte@5.54.1) svelte-persisted-store: specifier: ^0.12.0 - version: 0.12.0(svelte@5.53.7) + version: 0.12.0(svelte@5.54.1) tabbable: specifier: ^6.2.0 version: 6.4.0 @@ -850,7 +850,7 @@ importers: version: 3.5.0 tailwind-variants: specifier: ^3.2.2 - version: 3.2.2(tailwind-merge@3.5.0)(tailwindcss@4.2.1) + version: 3.2.2(tailwind-merge@3.5.0)(tailwindcss@4.2.2) thumbhash: specifier: ^0.1.1 version: 0.1.1 @@ -863,37 +863,37 @@ importers: devDependencies: '@eslint/js': specifier: ^10.0.0 - version: 10.0.1(eslint@10.0.2(jiti@2.6.1)) + version: 10.0.1(eslint@10.1.0(jiti@2.6.1)) '@faker-js/faker': specifier: ^10.0.0 version: 10.3.0 '@koddsson/eslint-plugin-tscompat': specifier: ^0.2.0 - version: 0.2.0(eslint@10.0.2(jiti@2.6.1))(typescript@5.9.3) + version: 0.2.0(eslint@10.1.0(jiti@2.6.1))(typescript@5.9.3) '@socket.io/component-emitter': specifier: ^3.1.0 version: 3.1.2 '@sveltejs/adapter-static': specifier: ^3.0.8 - version: 3.0.10(@sveltejs/kit@2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.7)(vite@7.3.1(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(svelte@5.53.7)(typescript@5.9.3)(vite@7.3.1(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))) + version: 3.0.10(@sveltejs/kit@2.55.0(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.54.1)(vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)))(svelte@5.54.1)(typescript@5.9.3)(vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))) '@sveltejs/enhanced-img': - specifier: ^0.10.0 - version: 0.10.3(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.7)(vite@7.3.1(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(rollup@4.55.1)(svelte@5.53.7)(vite@7.3.1(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + specifier: ^0.10.4 + version: 0.10.4(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.54.1)(vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)))(rollup@4.55.1)(svelte@5.54.1)(vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) '@sveltejs/kit': specifier: ^2.27.1 - version: 2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.7)(vite@7.3.1(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(svelte@5.53.7)(typescript@5.9.3)(vite@7.3.1(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + version: 2.55.0(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.54.1)(vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)))(svelte@5.54.1)(typescript@5.9.3)(vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) '@sveltejs/vite-plugin-svelte': - specifier: 6.2.4 - version: 6.2.4(svelte@5.53.7)(vite@7.3.1(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + specifier: 7.0.0 + version: 7.0.0(svelte@5.54.1)(vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) '@tailwindcss/vite': - specifier: ^4.1.7 - version: 4.2.1(vite@7.3.1(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + specifier: ^4.2.2 + version: 4.2.2(vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) '@testing-library/jest-dom': specifier: ^6.4.2 version: 6.9.1 '@testing-library/svelte': specifier: ^5.2.8 - version: 5.3.1(svelte@5.53.7)(vite@7.3.1(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vitest@4.0.18(@opentelemetry/api@1.9.0)(@types/node@25.4.0)(happy-dom@20.8.3)(jiti@2.6.1)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + version: 5.3.1(svelte@5.54.1)(vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.0(@opentelemetry/api@1.9.0)(@types/node@25.5.0)(happy-dom@20.8.4)(jsdom@26.1.0(canvas@2.11.2))(vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))) '@testing-library/user-event': specifier: ^14.5.2 version: 14.6.1(@testing-library/dom@10.4.1) @@ -917,25 +917,25 @@ importers: version: 1.5.6 '@vitest/coverage-v8': specifier: ^4.0.0 - version: 4.0.18(vitest@4.0.18(@opentelemetry/api@1.9.0)(@types/node@25.4.0)(happy-dom@20.8.3)(jiti@2.6.1)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + version: 4.1.0(vitest@4.1.0(@opentelemetry/api@1.9.0)(@types/node@25.5.0)(happy-dom@20.8.4)(jsdom@26.1.0(canvas@2.11.2))(vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))) dotenv: specifier: ^17.0.0 version: 17.3.1 eslint: specifier: ^10.0.0 - version: 10.0.2(jiti@2.6.1) + version: 10.1.0(jiti@2.6.1) eslint-config-prettier: specifier: ^10.1.8 - version: 10.1.8(eslint@10.0.2(jiti@2.6.1)) + version: 10.1.8(eslint@10.1.0(jiti@2.6.1)) eslint-plugin-compat: specifier: ^6.0.2 - version: 6.2.1(eslint@10.0.2(jiti@2.6.1)) + version: 6.2.1(eslint@10.1.0(jiti@2.6.1)) eslint-plugin-svelte: specifier: ^3.12.4 - version: 3.15.0(eslint@10.0.2(jiti@2.6.1))(svelte@5.53.7) + version: 3.16.0(eslint@10.1.0(jiti@2.6.1))(svelte@5.54.1) eslint-plugin-unicorn: specifier: ^63.0.0 - version: 63.0.0(eslint@10.0.2(jiti@2.6.1)) + version: 63.0.0(eslint@10.1.0(jiti@2.6.1)) factory.ts: specifier: ^1.4.1 version: 1.4.2 @@ -953,34 +953,34 @@ importers: version: 4.2.0(prettier@3.8.1) prettier-plugin-svelte: specifier: ^3.3.3 - version: 3.5.1(prettier@3.8.1)(svelte@5.53.7) + version: 3.5.1(prettier@3.8.1)(svelte@5.54.1) rollup-plugin-visualizer: specifier: ^6.0.0 - version: 6.0.11(rollup@4.55.1) + version: 6.0.11(rolldown@1.0.0-rc.10)(rollup@4.55.1) svelte: - specifier: 5.53.7 - version: 5.53.7 + specifier: 5.54.1 + version: 5.54.1 svelte-check: specifier: ^4.1.5 - version: 4.4.4(picomatch@4.0.3)(svelte@5.53.7)(typescript@5.9.3) + version: 4.4.5(picomatch@4.0.4)(svelte@5.54.1)(typescript@5.9.3) svelte-eslint-parser: specifier: ^1.3.3 - version: 1.6.0(svelte@5.53.7) + version: 1.6.0(svelte@5.54.1) tailwindcss: - specifier: ^4.1.7 - version: 4.2.1 + specifier: ^4.2.2 + version: 4.2.2 typescript: specifier: ^5.8.3 version: 5.9.3 typescript-eslint: specifier: ^8.45.0 - version: 8.56.1(eslint@10.0.2(jiti@2.6.1))(typescript@5.9.3) + version: 8.57.1(eslint@10.1.0(jiti@2.6.1))(typescript@5.9.3) vite: - specifier: ^7.1.2 - version: 7.3.1(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + specifier: ^8.0.0 + version: 8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3) vitest: specifier: ^4.0.0 - version: 4.0.18(@opentelemetry/api@1.9.0)(@types/node@25.4.0)(happy-dom@20.8.3)(jiti@2.6.1)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + version: 4.1.0(@opentelemetry/api@1.9.0)(@types/node@25.5.0)(happy-dom@20.8.4)(jsdom@26.1.0(canvas@2.11.2))(vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) packages: @@ -1234,8 +1234,8 @@ packages: resolution: {integrity: sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==} engines: {node: '>=6.9.0'} - '@babel/parser@7.29.0': - resolution: {integrity: sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==} + '@babel/parser@7.29.2': + resolution: {integrity: sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==} engines: {node: '>=6.0.0'} hasBin: true @@ -1685,8 +1685,8 @@ packages: resolution: {integrity: sha512-h7iEYiW4HebClDEhtvFObtPmIvrd1SSfpI9EhOeKk4CtIK/ngBWFpuhCzhdmRKtg71ylcue+9I6dv54XYO1epQ==} engines: {node: '>=6.9.0'} - '@babel/runtime@7.28.6': - resolution: {integrity: sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==} + '@babel/runtime@7.29.2': + resolution: {integrity: sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==} engines: {node: '>=6.9.0'} '@babel/template@7.27.2': @@ -1708,8 +1708,8 @@ packages: resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==} engines: {node: '>=18'} - '@borewit/text-codec@0.2.1': - resolution: {integrity: sha512-k7vvKPbf7J2fZ5klGRD9AeKfUvojuZIQ3BT5u7Jfv+puwXkUBUT5PVyMDfJZpy30CBDXGMgw7fguK/lpOMBvgw==} + '@borewit/text-codec@0.2.2': + resolution: {integrity: sha512-DDaRehssg1aNrH4+2hnj1B7vnUGEjU6OIlyRdkMd0aUdIUvKXrJfXsy8LVtXAy7DRvYVluWbMspsRhz2lcW0mQ==} '@braintree/sanitize-url@7.1.1': resolution: {integrity: sha512-i1L7noDNxtFyL5DmZafWy1wRVhGehQmzZaz1HiN5e7iylJMSZR7ekOV7NsIqa5qBldlLrsKv4HbgFUVlQrz8Mw==} @@ -2264,8 +2264,14 @@ packages: resolution: {integrity: sha512-lBSBiRruFurFKXr5Hbsl2thmGweAPmddhF3jb99U4EMDA5L+e5Y1rAkOS07Nvrup7HUMBDrCV45meaxZnt28nQ==} engines: {node: '>=20.0'} - '@emnapi/runtime@1.7.1': - resolution: {integrity: sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==} + '@emnapi/core@1.9.1': + resolution: {integrity: sha512-mukuNALVsoix/w1BJwFzwXBN/dHeejQtuVzcDsfOEsdpCumXb/E9j8w11h5S54tT1xhifGfbbSm/ICrObRb3KA==} + + '@emnapi/runtime@1.9.1': + resolution: {integrity: sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA==} + + '@emnapi/wasi-threads@1.2.0': + resolution: {integrity: sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg==} '@esbuild/aix-ppc64@0.19.12': resolution: {integrity: sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==} @@ -2279,8 +2285,8 @@ packages: cpu: [ppc64] os: [aix] - '@esbuild/aix-ppc64@0.27.3': - resolution: {integrity: sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==} + '@esbuild/aix-ppc64@0.27.4': + resolution: {integrity: sha512-cQPwL2mp2nSmHHJlCyoXgHGhbEPMrEEU5xhkcy3Hs/O7nGZqEpZ2sUtLaL9MORLtDfRvVl2/3PAuEkYZH0Ty8Q==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] @@ -2297,8 +2303,8 @@ packages: cpu: [arm64] os: [android] - '@esbuild/android-arm64@0.27.3': - resolution: {integrity: sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==} + '@esbuild/android-arm64@0.27.4': + resolution: {integrity: sha512-gdLscB7v75wRfu7QSm/zg6Rx29VLdy9eTr2t44sfTW7CxwAtQghZ4ZnqHk3/ogz7xao0QAgrkradbBzcqFPasw==} engines: {node: '>=18'} cpu: [arm64] os: [android] @@ -2315,8 +2321,8 @@ packages: cpu: [arm] os: [android] - '@esbuild/android-arm@0.27.3': - resolution: {integrity: sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==} + '@esbuild/android-arm@0.27.4': + resolution: {integrity: sha512-X9bUgvxiC8CHAGKYufLIHGXPJWnr0OCdR0anD2e21vdvgCI8lIfqFbnoeOz7lBjdrAGUhqLZLcQo6MLhTO2DKQ==} engines: {node: '>=18'} cpu: [arm] os: [android] @@ -2333,8 +2339,8 @@ packages: cpu: [x64] os: [android] - '@esbuild/android-x64@0.27.3': - resolution: {integrity: sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==} + '@esbuild/android-x64@0.27.4': + resolution: {integrity: sha512-PzPFnBNVF292sfpfhiyiXCGSn9HZg5BcAz+ivBuSsl6Rk4ga1oEXAamhOXRFyMcjwr2DVtm40G65N3GLeH1Lvw==} engines: {node: '>=18'} cpu: [x64] os: [android] @@ -2351,8 +2357,8 @@ packages: cpu: [arm64] os: [darwin] - '@esbuild/darwin-arm64@0.27.3': - resolution: {integrity: sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==} + '@esbuild/darwin-arm64@0.27.4': + resolution: {integrity: sha512-b7xaGIwdJlht8ZFCvMkpDN6uiSmnxxK56N2GDTMYPr2/gzvfdQN8rTfBsvVKmIVY/X7EM+/hJKEIbbHs9oA4tQ==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] @@ -2369,8 +2375,8 @@ packages: cpu: [x64] os: [darwin] - '@esbuild/darwin-x64@0.27.3': - resolution: {integrity: sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==} + '@esbuild/darwin-x64@0.27.4': + resolution: {integrity: sha512-sR+OiKLwd15nmCdqpXMnuJ9W2kpy0KigzqScqHI3Hqwr7IXxBp3Yva+yJwoqh7rE8V77tdoheRYataNKL4QrPw==} engines: {node: '>=18'} cpu: [x64] os: [darwin] @@ -2387,8 +2393,8 @@ packages: cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-arm64@0.27.3': - resolution: {integrity: sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==} + '@esbuild/freebsd-arm64@0.27.4': + resolution: {integrity: sha512-jnfpKe+p79tCnm4GVav68A7tUFeKQwQyLgESwEAUzyxk/TJr4QdGog9sqWNcUbr/bZt/O/HXouspuQDd9JxFSw==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] @@ -2405,8 +2411,8 @@ packages: cpu: [x64] os: [freebsd] - '@esbuild/freebsd-x64@0.27.3': - resolution: {integrity: sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==} + '@esbuild/freebsd-x64@0.27.4': + resolution: {integrity: sha512-2kb4ceA/CpfUrIcTUl1wrP/9ad9Atrp5J94Lq69w7UwOMolPIGrfLSvAKJp0RTvkPPyn6CIWrNy13kyLikZRZQ==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] @@ -2423,8 +2429,8 @@ packages: cpu: [arm64] os: [linux] - '@esbuild/linux-arm64@0.27.3': - resolution: {integrity: sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==} + '@esbuild/linux-arm64@0.27.4': + resolution: {integrity: sha512-7nQOttdzVGth1iz57kxg9uCz57dxQLHWxopL6mYuYthohPKEK0vU0C3O21CcBK6KDlkYVcnDXY099HcCDXd9dA==} engines: {node: '>=18'} cpu: [arm64] os: [linux] @@ -2441,8 +2447,8 @@ packages: cpu: [arm] os: [linux] - '@esbuild/linux-arm@0.27.3': - resolution: {integrity: sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==} + '@esbuild/linux-arm@0.27.4': + resolution: {integrity: sha512-aBYgcIxX/wd5n2ys0yESGeYMGF+pv6g0DhZr3G1ZG4jMfruU9Tl1i2Z+Wnj9/KjGz1lTLCcorqE2viePZqj4Eg==} engines: {node: '>=18'} cpu: [arm] os: [linux] @@ -2459,8 +2465,8 @@ packages: cpu: [ia32] os: [linux] - '@esbuild/linux-ia32@0.27.3': - resolution: {integrity: sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==} + '@esbuild/linux-ia32@0.27.4': + resolution: {integrity: sha512-oPtixtAIzgvzYcKBQM/qZ3R+9TEUd1aNJQu0HhGyqtx6oS7qTpvjheIWBbes4+qu1bNlo2V4cbkISr8q6gRBFA==} engines: {node: '>=18'} cpu: [ia32] os: [linux] @@ -2477,8 +2483,8 @@ packages: cpu: [loong64] os: [linux] - '@esbuild/linux-loong64@0.27.3': - resolution: {integrity: sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==} + '@esbuild/linux-loong64@0.27.4': + resolution: {integrity: sha512-8mL/vh8qeCoRcFH2nM8wm5uJP+ZcVYGGayMavi8GmRJjuI3g1v6Z7Ni0JJKAJW+m0EtUuARb6Lmp4hMjzCBWzA==} engines: {node: '>=18'} cpu: [loong64] os: [linux] @@ -2495,8 +2501,8 @@ packages: cpu: [mips64el] os: [linux] - '@esbuild/linux-mips64el@0.27.3': - resolution: {integrity: sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==} + '@esbuild/linux-mips64el@0.27.4': + resolution: {integrity: sha512-1RdrWFFiiLIW7LQq9Q2NES+HiD4NyT8Itj9AUeCl0IVCA459WnPhREKgwrpaIfTOe+/2rdntisegiPWn/r/aAw==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] @@ -2513,8 +2519,8 @@ packages: cpu: [ppc64] os: [linux] - '@esbuild/linux-ppc64@0.27.3': - resolution: {integrity: sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==} + '@esbuild/linux-ppc64@0.27.4': + resolution: {integrity: sha512-tLCwNG47l3sd9lpfyx9LAGEGItCUeRCWeAx6x2Jmbav65nAwoPXfewtAdtbtit/pJFLUWOhpv0FpS6GQAmPrHA==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] @@ -2531,8 +2537,8 @@ packages: cpu: [riscv64] os: [linux] - '@esbuild/linux-riscv64@0.27.3': - resolution: {integrity: sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==} + '@esbuild/linux-riscv64@0.27.4': + resolution: {integrity: sha512-BnASypppbUWyqjd1KIpU4AUBiIhVr6YlHx/cnPgqEkNoVOhHg+YiSVxM1RLfiy4t9cAulbRGTNCKOcqHrEQLIw==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] @@ -2549,8 +2555,8 @@ packages: cpu: [s390x] os: [linux] - '@esbuild/linux-s390x@0.27.3': - resolution: {integrity: sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==} + '@esbuild/linux-s390x@0.27.4': + resolution: {integrity: sha512-+eUqgb/Z7vxVLezG8bVB9SfBie89gMueS+I0xYh2tJdw3vqA/0ImZJ2ROeWwVJN59ihBeZ7Tu92dF/5dy5FttA==} engines: {node: '>=18'} cpu: [s390x] os: [linux] @@ -2567,8 +2573,8 @@ packages: cpu: [x64] os: [linux] - '@esbuild/linux-x64@0.27.3': - resolution: {integrity: sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==} + '@esbuild/linux-x64@0.27.4': + resolution: {integrity: sha512-S5qOXrKV8BQEzJPVxAwnryi2+Iq5pB40gTEIT69BQONqR7JH1EPIcQ/Uiv9mCnn05jff9umq/5nqzxlqTOg9NA==} engines: {node: '>=18'} cpu: [x64] os: [linux] @@ -2579,8 +2585,8 @@ packages: cpu: [arm64] os: [netbsd] - '@esbuild/netbsd-arm64@0.27.3': - resolution: {integrity: sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==} + '@esbuild/netbsd-arm64@0.27.4': + resolution: {integrity: sha512-xHT8X4sb0GS8qTqiwzHqpY00C95DPAq7nAwX35Ie/s+LO9830hrMd3oX0ZMKLvy7vsonee73x0lmcdOVXFzd6Q==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] @@ -2597,8 +2603,8 @@ packages: cpu: [x64] os: [netbsd] - '@esbuild/netbsd-x64@0.27.3': - resolution: {integrity: sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==} + '@esbuild/netbsd-x64@0.27.4': + resolution: {integrity: sha512-RugOvOdXfdyi5Tyv40kgQnI0byv66BFgAqjdgtAKqHoZTbTF2QqfQrFwa7cHEORJf6X2ht+l9ABLMP0dnKYsgg==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] @@ -2609,8 +2615,8 @@ packages: cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-arm64@0.27.3': - resolution: {integrity: sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==} + '@esbuild/openbsd-arm64@0.27.4': + resolution: {integrity: sha512-2MyL3IAaTX+1/qP0O1SwskwcwCoOI4kV2IBX1xYnDDqthmq5ArrW94qSIKCAuRraMgPOmG0RDTA74mzYNQA9ow==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] @@ -2627,8 +2633,8 @@ packages: cpu: [x64] os: [openbsd] - '@esbuild/openbsd-x64@0.27.3': - resolution: {integrity: sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==} + '@esbuild/openbsd-x64@0.27.4': + resolution: {integrity: sha512-u8fg/jQ5aQDfsnIV6+KwLOf1CmJnfu1ShpwqdwC0uA7ZPwFws55Ngc12vBdeUdnuWoQYx/SOQLGDcdlfXhYmXQ==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] @@ -2639,8 +2645,8 @@ packages: cpu: [arm64] os: [openharmony] - '@esbuild/openharmony-arm64@0.27.3': - resolution: {integrity: sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==} + '@esbuild/openharmony-arm64@0.27.4': + resolution: {integrity: sha512-JkTZrl6VbyO8lDQO3yv26nNr2RM2yZzNrNHEsj9bm6dOwwu9OYN28CjzZkH57bh4w0I2F7IodpQvUAEd1mbWXg==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] @@ -2657,8 +2663,8 @@ packages: cpu: [x64] os: [sunos] - '@esbuild/sunos-x64@0.27.3': - resolution: {integrity: sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==} + '@esbuild/sunos-x64@0.27.4': + resolution: {integrity: sha512-/gOzgaewZJfeJTlsWhvUEmUG4tWEY2Spp5M20INYRg2ZKl9QPO3QEEgPeRtLjEWSW8FilRNacPOg8R1uaYkA6g==} engines: {node: '>=18'} cpu: [x64] os: [sunos] @@ -2675,8 +2681,8 @@ packages: cpu: [arm64] os: [win32] - '@esbuild/win32-arm64@0.27.3': - resolution: {integrity: sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==} + '@esbuild/win32-arm64@0.27.4': + resolution: {integrity: sha512-Z9SExBg2y32smoDQdf1HRwHRt6vAHLXcxD2uGgO/v2jK7Y718Ix4ndsbNMU/+1Qiem9OiOdaqitioZwxivhXYg==} engines: {node: '>=18'} cpu: [arm64] os: [win32] @@ -2693,8 +2699,8 @@ packages: cpu: [ia32] os: [win32] - '@esbuild/win32-ia32@0.27.3': - resolution: {integrity: sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==} + '@esbuild/win32-ia32@0.27.4': + resolution: {integrity: sha512-DAyGLS0Jz5G5iixEbMHi5KdiApqHBWMGzTtMiJ72ZOLhbu/bzxgAe8Ue8CTS3n3HbIUHQz/L51yMdGMeoxXNJw==} engines: {node: '>=18'} cpu: [ia32] os: [win32] @@ -2711,8 +2717,8 @@ packages: cpu: [x64] os: [win32] - '@esbuild/win32-x64@0.27.3': - resolution: {integrity: sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==} + '@esbuild/win32-x64@0.27.4': + resolution: {integrity: sha512-+knoa0BDoeXgkNvvV1vvbZX4+hizelrkwmGJBdT17t8FNPwG2lKemmuMZlmaNQ3ws3DKKCxpb4zRZEIp3UxFCg==} engines: {node: '>=18'} cpu: [x64] os: [win32] @@ -2727,16 +2733,16 @@ packages: resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - '@eslint/config-array@0.23.2': - resolution: {integrity: sha512-YF+fE6LV4v5MGWRGj7G404/OZzGNepVF8fxk7jqmqo3lrza7a0uUcDnROGRBG1WFC1omYUS/Wp1f42i0M+3Q3A==} + '@eslint/config-array@0.23.3': + resolution: {integrity: sha512-j+eEWmB6YYLwcNOdlwQ6L2OsptI/LO6lNBuLIqe5R7RetD658HLoF+Mn7LzYmAWWNNzdC6cqP+L6r8ujeYXWLw==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} - '@eslint/config-helpers@0.5.2': - resolution: {integrity: sha512-a5MxrdDXEvqnIq+LisyCX6tQMPF/dSJpCfBgBauY+pNZ28yCtSsTvyTYrMhaI+LK26bVyCJfJkT0u8KIj2i1dQ==} + '@eslint/config-helpers@0.5.3': + resolution: {integrity: sha512-lzGN0onllOZCGroKJmRwY6QcEHxbjBw1gwB8SgRSqK8YbbtEXMvKynsXc3553ckIEBxsbMBU7oOZXKIPGZNeZw==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} - '@eslint/core@1.1.0': - resolution: {integrity: sha512-/nr9K9wkr3P1EzFTdFdMoLuo1PmIxjmwvPozwoSodjNBdefGujXQUF93u1DDZpEaTuDvMsIQddsd35BwtrW9Xw==} + '@eslint/core@1.1.1': + resolution: {integrity: sha512-QUPblTtE51/7/Zhfv8BDwO0qkkzQL7P/aWWbqcf4xWLEYn1oKjdO0gglQBB4GAsu7u6wjijbCmzsUTy6mnk6oQ==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} '@eslint/js@10.0.1': @@ -2748,12 +2754,12 @@ packages: eslint: optional: true - '@eslint/object-schema@3.0.2': - resolution: {integrity: sha512-HOy56KJt48Bx8KmJ+XGQNSUMT/6dZee/M54XyUyuvTvPXJmsERRvBchsUVx1UMe1WwIH49XLAczNC7V2INsuUw==} + '@eslint/object-schema@3.0.3': + resolution: {integrity: sha512-iM869Pugn9Nsxbh/YHRqYiqd23AmIbxJOcpUMOuWCVNdoQJ5ZtwL6h3t0bcZzJUlC3Dq9jCFCESBZnX0GTv7iQ==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} - '@eslint/plugin-kit@0.6.0': - resolution: {integrity: sha512-bIZEUzOI1jkhviX2cp5vNyXQc6olzb2ohewQubuYlMXZ2Q/XjBO0x0XhGPvc9fjSIiUN0vw+0hq53BJ4eQSJKQ==} + '@eslint/plugin-kit@0.6.1': + resolution: {integrity: sha512-iH1B076HoAshH1mLpHMgwdGeTs0CYwL0SPMkGuSebZrwBp16v415e9NZXg2jtrqPVQjf6IANe2Vtlr5KswtcZQ==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} '@extism/extism@2.0.0-rc13': @@ -2780,35 +2786,38 @@ packages: '@floating-ui/utils@0.2.10': resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==} + '@formatjs/bigdecimal@0.2.0': + resolution: {integrity: sha512-GeaxHZbUoYvHL9tC5eltHLs+1zU70aPw0s7LwqgktIzF5oMhNY4o4deEtusJMsq7WFJF3Ye2zQEzdG8beVk73w==} + '@formatjs/ecma402-abstract@2.3.6': resolution: {integrity: sha512-HJnTFeRM2kVFVr5gr5kH1XP6K0JcJtE7Lzvtr3FS/so5f1kpsqqqxy5JF+FRaO6H2qmcMfAUIox7AJteieRtVw==} - '@formatjs/ecma402-abstract@3.1.1': - resolution: {integrity: sha512-jhZbTwda+2tcNrs4kKvxrPLPjx8QsBCLCUgrrJ/S+G9YrGHWLhAyFMMBHJBnBoOwuLHd7L14FgYudviKaxkO2Q==} + '@formatjs/ecma402-abstract@3.2.0': + resolution: {integrity: sha512-dHnqHgBo6GXYGRsepaE1wmsC2etaivOWd5VaJstZd+HI2zR3DCUjbDVZRtoPGkkXZmyHvBwrdEUuqfvzhF/DtQ==} '@formatjs/fast-memoize@2.2.7': resolution: {integrity: sha512-Yabmi9nSvyOMrlSeGGWDiH7rf3a7sIwplbvo/dlz9WCIjzIQAfy1RMf4S0X3yG724n5Ghu2GmEl5NJIV6O9sZQ==} - '@formatjs/fast-memoize@3.1.0': - resolution: {integrity: sha512-b5mvSWCI+XVKiz5WhnBCY3RJ4ZwfjAidU0yVlKa3d3MSgKmH1hC3tBGEAtYyN5mqL7N0G5x0BOUYyO8CEupWgg==} + '@formatjs/fast-memoize@3.1.1': + resolution: {integrity: sha512-CbNbf+tlJn1baRnPkNePnBqTLxGliG6DDgNa/UtV66abwIjwsliPMOt0172tzxABYzSuxZBZfcp//qI8AvBWPg==} '@formatjs/icu-messageformat-parser@2.11.4': resolution: {integrity: sha512-7kR78cRrPNB4fjGFZg3Rmj5aah8rQj9KPzuLsmcSn4ipLXQvC04keycTI1F7kJYDwIXtT2+7IDEto842CfZBtw==} - '@formatjs/icu-messageformat-parser@3.5.1': - resolution: {integrity: sha512-sSDmSvmmoVQ92XqWb499KrIhv/vLisJU8ITFrx7T7NZHUmMY7EL9xgRowAosaljhqnj/5iufG24QrdzB6X3ItA==} + '@formatjs/icu-messageformat-parser@3.5.3': + resolution: {integrity: sha512-HJWZ9S6JWey6iY5+YXE3Kd0ofWU1sC2KTTp56e1168g/xxWvVvr8k9G4fexIgwYV9wbtjY7kGYK5FjoWB3B2OQ==} '@formatjs/icu-skeleton-parser@1.8.16': resolution: {integrity: sha512-H13E9Xl+PxBd8D5/6TVUluSpxGNvFSlN/b3coUp0e0JpuWXXnQDiavIpY3NnvSp4xhEMoXyyBvVfdFX8jglOHQ==} - '@formatjs/icu-skeleton-parser@2.1.1': - resolution: {integrity: sha512-PSFABlcNefjI6yyk8f7nyX1DC7NHmq6WaCHZLySEXBrXuLOB2f935YsnzuPjlz+ibhb9yWTdPeVX1OVcj24w2Q==} + '@formatjs/icu-skeleton-parser@2.1.3': + resolution: {integrity: sha512-9mFp8TJ166ZM2pcjKwsBWXrDnOJGT7vMEScVgLygUODPOsE8S6f/FHoacvrlHK1B4dYZk8vSCNruyPU64AfgJQ==} '@formatjs/intl-localematcher@0.6.2': resolution: {integrity: sha512-XOMO2Hupl0wdd172Y06h6kLpBz6Dv+J4okPLl4LPtzbr8f66WbIoy4ev98EBuZ6ZK4h5ydTN6XneT4QVpD7cdA==} - '@formatjs/intl-localematcher@0.8.1': - resolution: {integrity: sha512-xwEuwQFdtSq1UKtQnyTZWC+eHdv7Uygoa+H2k/9uzBVQjDyp9r20LNDNKedWXll7FssT3GRHvqsdJGYSUWqYFA==} + '@formatjs/intl-localematcher@0.8.2': + resolution: {integrity: sha512-q05KMYGJLyqFNFtIb8NhWLF5X3aK/k0wYt7dnRFuy6aLQL+vUwQ1cg5cO4qawEiINybeCPXAWlprY2mSBjSXAQ==} '@fortawesome/fontawesome-common-types@7.1.0': resolution: {integrity: sha512-l/BQM7fYntsCI//du+6sEnHOP6a74UixFyOYUyz2DLMXKx+6DEhfR3F2NYGE45XH1JJuIamacb4IZs9S0ZOWLA==} @@ -3035,8 +3044,8 @@ packages: peerDependencies: svelte: ^5.0.0 - '@immich/ui@0.65.3': - resolution: {integrity: sha512-jMXzCzMNTcCdWXt9IUP7GkALE5oEvPQk/jCOuI2bfxsxCZFzMkUfUS+AV83Vg1vQ6l+g39PbKSPKBEzv125ATQ==} + '@immich/ui@0.69.0': + resolution: {integrity: sha512-YQ+27pGQhzdRBOo/7cHcbXnax5BUrrJeYjUc+VdRYp6KMS8SlGWAKQhvZPdcqiPB332fxJMmpHjV+VqXJJjrqg==} peerDependencies: svelte: ^5.0.0 @@ -3290,8 +3299,8 @@ packages: resolution: {integrity: sha512-x/iUDjcS90W69PryLDIMgFyV21YLTnG9zOpPXS7Bkt2b8AsY3zZsIpOLBkYr9fBcF3HbkKaER5hOBZLfpLgYNw==} engines: {node: '>= 14.0.0'} - '@koa/router@15.3.0': - resolution: {integrity: sha512-s87hWJjFYky2Z97u8jzah73sSHp4IZivD/2PZCuspHRvcKU69OPLoBIbKigVlBmS50yFTh9GHFfr1hDag4+wXw==} + '@koa/router@15.4.0': + resolution: {integrity: sha512-vKYlXtoCfcAN8z4dHiveYX55rTYOgHEYJNumK1WM9ZAwaArhreGVkyC1LTMGfUQUJyIO/SbwRFBOHeOCY8/MaQ==} engines: {node: '>= 20'} peerDependencies: koa: ^2.0.0 || ^3.0.0 @@ -3321,10 +3330,6 @@ packages: resolution: {integrity: sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA==} engines: {node: '>=8'} - '@mapbox/geojson-rewind@0.5.2': - resolution: {integrity: sha512-tJaT+RbYGJYStt7wI3cq4Nl4SXxG8W7JDG5DMJu97V25RnbNg3QtQtf+KD+VLjNpWKYsRvXDNmNrBgEETr1ifA==} - hasBin: true - '@mapbox/jsonlint-lines-primitives@2.0.2': resolution: {integrity: sha512-rY0o9A5ECsTQRVhv7tL/OyDpGAoUB4tTvLiW1DSzQGq4bvTPhNw1VpSNjDJc5GFZ2XuyOtSWSVN05qOtcD71qQ==} engines: {node: '>= 0.6'} @@ -3355,12 +3360,15 @@ packages: '@maplibre/geojson-vt@5.0.4': resolution: {integrity: sha512-KGg9sma45S+stfH9vPCJk1J0lSDLWZgCT9Y8u8qWZJyjFlP8MNP1WGTxIMYJZjDvVT3PDn05kN1C95Sut1HpgQ==} - '@maplibre/maplibre-gl-style-spec@24.6.0': - resolution: {integrity: sha512-+lxMYE+DvInshwVrqSQ3CkW9YRwVlRXeDzfthVOa1c9pwK5d7YgCwhgFwlSmjJLvTXn4gL8EvPUGT620sk2Pzg==} + '@maplibre/geojson-vt@6.0.4': + resolution: {integrity: sha512-HYv3POhMRCdhP3UPPATM/hfcy6/WuVIf5FKboH8u/ZuFMTnAIcSVlq5nfOqroLokd925w2QtE7YwquFOIacwVQ==} + + '@maplibre/maplibre-gl-style-spec@24.7.0': + resolution: {integrity: sha512-Ed7rcKYU5iELfablg9Mj+TVCsXsPBgdMyXPRAxb2v7oWg9YJnpQdZ5msDs1LESu/mtXy3Z48Vdppv2t/x5kAhw==} hasBin: true - '@maplibre/mlt@1.1.6': - resolution: {integrity: sha512-rgtY3x65lrrfXycLf6/T22ZnjTg5WgIOsptOIoCaMZy4O4UAKTyZlYY0h6v8le721pTptF94U65yMDQkug+URw==} + '@maplibre/mlt@1.1.8': + resolution: {integrity: sha512-8vtfYGidr1rNkv5IwIoU2lfe3Oy+Wa8HluzQYcQi9cveU9K3pweAal/poQj4GJ0K/EW4bTQp2wVAs09g2yDRZg==} '@maplibre/vt-pbf@4.3.0': resolution: {integrity: sha512-jIvp8F5hQCcreqOOpEt42TJMUlsrEcpf/kI1T2v85YrQRV6PPXUcEXUg5karKtH6oh47XJZ4kHu56pUkOuqA7w==} @@ -3428,6 +3436,9 @@ packages: '@namnode/store@0.1.0': resolution: {integrity: sha512-4NGTldxKcmY0UuZ7OEkvCjs8ZEoeYB6M2UwMu74pdLiFMKxXbj9HdNk1Qn213bxX1O7bY5h+PLh5DZsTURZkYA==} + '@napi-rs/wasm-runtime@1.1.1': + resolution: {integrity: sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A==} + '@nestjs/bull-shared@11.0.4': resolution: {integrity: sha512-VBJcDHSAzxQnpcDfA0kt9MTGUD1XZzfByV70su0W0eDCQ9aqIEBlzWRW21tv9FG9dIut22ysgDidshdjlnczLw==} peerDependencies: @@ -3454,8 +3465,8 @@ packages: '@swc/core': optional: true - '@nestjs/common@11.1.16': - resolution: {integrity: sha512-JSIeW+USuMJkkcNbiOdcPkVCeI3TSnXstIVEPpp3HiaKnPRuSbUUKm9TY9o/XpIcPHWUOQItAtC5BiAwFdVITQ==} + '@nestjs/common@11.1.17': + resolution: {integrity: sha512-hLODw5Abp8OQgA+mUO4tHou4krKgDtUcM9j5Ihxncst9XeyxYBTt2bwZm4e4EQr5E352S4Fyy6V3iFx9ggxKAg==} peerDependencies: class-transformer: '>=0.4.1' class-validator: '>=0.13.2' @@ -3467,8 +3478,8 @@ packages: class-validator: optional: true - '@nestjs/core@11.1.16': - resolution: {integrity: sha512-tXWXyCiqWthelJjrE0KLFjf0O98VEt+WPVx5CrqCf+059kIxJ8y1Vw7Cy7N4fwQafWNrmFL2AfN87DDMbVAY0w==} + '@nestjs/core@11.1.17': + resolution: {integrity: sha512-lD5mAYekTTurF3vDaa8C2OKPnjiz4tsfxIc5XlcSUzOhkwWf6Ay3HKvt6FmvuWQam6uIIHX52Clg+e6tAvf/cg==} engines: {node: '>= 20'} peerDependencies: '@nestjs/common': ^11.0.0 @@ -3498,14 +3509,14 @@ packages: class-validator: optional: true - '@nestjs/platform-express@11.1.16': - resolution: {integrity: sha512-IOegr5+ZfUiMKgk+garsSU4MOkPRhm46e6w8Bp1GcO4vCdl9Piz6FlWAzKVfa/U3Hn/DdzSVJOW3TWcQQFdBDw==} + '@nestjs/platform-express@11.1.17': + resolution: {integrity: sha512-mAf4eOsSBsTOn/VbrUO1gsjW6dVh91qqXPMXun4dN8SnNjf7PTQagM9o8d6ab8ZBpNe6UdZftdrZoDetU+n4Qg==} peerDependencies: '@nestjs/common': ^11.0.0 '@nestjs/core': ^11.0.0 - '@nestjs/platform-socket.io@11.1.16': - resolution: {integrity: sha512-3fYQTi8F2hb7HDkes/ArGhY8lkjB/Df29F5CN4cjbk4cmfpRVy89p6N1BC7PjVOHMAzdwqeX8FabqspdSAnywA==} + '@nestjs/platform-socket.io@11.1.17': + resolution: {integrity: sha512-BSOAsENdmTtsnDL0hb4takbWzPy9WoPybjlM57ab3/rQgm0biMFYUupH2uzmCjmmIXJL/EFbAWznVl8xw2Sa6Q==} peerDependencies: '@nestjs/common': ^11.0.0 '@nestjs/websockets': ^11.0.0 @@ -3539,8 +3550,8 @@ packages: class-validator: optional: true - '@nestjs/testing@11.1.16': - resolution: {integrity: sha512-E7/aUCxzeMSJV80L5GWGIuiMyR/1ncS7uOIetAImfbS4ATE1/h2GBafk0qpk+vjFtPIbtoh9BWDGICzUEU5jDA==} + '@nestjs/testing@11.1.17': + resolution: {integrity: sha512-lNffw+z+2USewmw4W0tsK+Rq94A2N4PiHbcqoRUu5y8fnqxQeIWGHhjo5BFCqj7eivqJBhT7WdRydxVq4rAHzg==} peerDependencies: '@nestjs/common': ^11.0.0 '@nestjs/core': ^11.0.0 @@ -3552,8 +3563,8 @@ packages: '@nestjs/platform-express': optional: true - '@nestjs/websockets@11.1.16': - resolution: {integrity: sha512-kfLhCFsq6139JVFCQpbFB6LOEjZzdpE7JzXsZtRbVjqmsgTKVSIh8gKRgzpcq27rbLNqHhhZavboOltOfSxZow==} + '@nestjs/websockets@11.1.17': + resolution: {integrity: sha512-YbwQ0QfVj0lxkKQhdIIgk14ZSVWDqGk1J8nNSN6SLjf36sVv58Ma5ro+dtQua8wj3l2Ub7JJCVFixEhKtYc/rQ==} peerDependencies: '@nestjs/common': ^11.0.0 '@nestjs/core': ^11.0.0 @@ -3804,6 +3815,9 @@ packages: peerDependencies: '@opentelemetry/api': ^1.1.0 + '@oxc-project/types@0.120.0': + resolution: {integrity: sha512-k1YNu55DuvAip/MGE1FTsIuU3FUCn6v/ujG9V7Nq5Df/kX2CWb13hhwD0lmJGMGqE+bE1MXvv9SZVnMzEXlWcg==} + '@paralleldrive/cuid2@2.3.1': resolution: {integrity: sha512-XO7cAxhnTZl0Yggq6jOgjiOHhbgcO4NqFqwSmQpjK3b6TEE6Uj/jfSk6wzYyemh3+I0sHirKSetjQwn5cZktFw==} @@ -4118,6 +4132,104 @@ packages: '@codemirror/state': ^6.0.0 '@codemirror/view': ^6.0.0 + '@rolldown/binding-android-arm64@1.0.0-rc.10': + resolution: {integrity: sha512-jOHxwXhxmFKuXztiu1ORieJeTbx5vrTkcOkkkn2d35726+iwhrY1w/+nYY/AGgF12thg33qC3R1LMBF5tHTZHg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + + '@rolldown/binding-darwin-arm64@1.0.0-rc.10': + resolution: {integrity: sha512-gED05Teg/vtTZbIJBc4VNMAxAFDUPkuO/rAIyyxZjTj1a1/s6z5TII/5yMGZ0uLRCifEtwUQn8OlYzuYc0m70w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@rolldown/binding-darwin-x64@1.0.0-rc.10': + resolution: {integrity: sha512-rI15NcM1mA48lqrIxVkHfAqcyFLcQwyXWThy+BQ5+mkKKPvSO26ir+ZDp36AgYoYVkqvMcdS8zOE6SeBsR9e8A==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + + '@rolldown/binding-freebsd-x64@1.0.0-rc.10': + resolution: {integrity: sha512-XZRXHdTa+4ME1MuDVp021+doQ+z6Ei4CCFmNc5/sKbqb8YmkiJdj8QKlV3rCI0AJtAeSB5n0WGPuJWNL9p/L2w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.10': + resolution: {integrity: sha512-R0SQMRluISSLzFE20sPWYHVmJdDQnRyc/FzSCN72BqQmh2SOZUFG+N3/vBZpR4C6WpEUVYJLrYUXaj43sJsNLA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.10': + resolution: {integrity: sha512-Y1reMrV/o+cwpduYhJuOE3OMKx32RMYCidf14y+HssARRmhDuWXJ4yVguDg2R/8SyyGNo+auzz64LnPK9Hq6jg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.10': + resolution: {integrity: sha512-vELN+HNb2IzuzSBUOD4NHmP9yrGwl1DVM29wlQvx1OLSclL0NgVWnVDKl/8tEks79EFek/kebQKnNJkIAA4W2g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.10': + resolution: {integrity: sha512-ZqrufYTgzxbHwpqOjzSsb0UV/aV2TFIY5rP8HdsiPTv/CuAgCRjM6s9cYFwQ4CNH+hf9Y4erHW1GjZuZ7WoI7w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.10': + resolution: {integrity: sha512-gSlmVS1FZJSRicA6IyjoRoKAFK7IIHBs7xJuHRSmjImqk3mPPWbR7RhbnfH2G6bcmMEllCt2vQ/7u9e6bBnByg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-x64-gnu@1.0.0-rc.10': + resolution: {integrity: sha512-eOCKUpluKgfObT2pHjztnaWEIbUabWzk3qPZ5PuacuPmr4+JtQG4k2vGTY0H15edaTnicgU428XW/IH6AimcQw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-x64-musl@1.0.0-rc.10': + resolution: {integrity: sha512-Xdf2jQbfQowJnLcgYfD/m0Uu0Qj5OdxKallD78/IPPfzaiaI4KRAwZzHcKQ4ig1gtg1SuzC7jovNiM2TzQsBXA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [musl] + + '@rolldown/binding-openharmony-arm64@1.0.0-rc.10': + resolution: {integrity: sha512-o1hYe8hLi1EY6jgPFyxQgQ1wcycX+qz8eEbVmot2hFkgUzPxy9+kF0u0NIQBeDq+Mko47AkaFFaChcvZa9UX9Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + + '@rolldown/binding-wasm32-wasi@1.0.0-rc.10': + resolution: {integrity: sha512-Ugv9o7qYJudqQO5Y5y2N2SOo6S4WiqiNOpuQyoPInnhVzCY+wi/GHltcLHypG9DEUYMB0iTB/huJrpadiAcNcA==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + + '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.10': + resolution: {integrity: sha512-7UODQb4fQUNT/vmgDZBl3XOBAIOutP5R3O/rkxg0aLfEGQ4opbCgU5vOw/scPe4xOqBwL9fw7/RP1vAMZ6QlAQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.10': + resolution: {integrity: sha512-PYxKHMVHOb5NJuDL53vBUl1VwUjymDcYI6rzpIni0C9+9mTiJedvUxSk7/RPp7OOAm3v+EjgMu9bIy3N6b408w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + + '@rolldown/pluginutils@1.0.0-rc.10': + resolution: {integrity: sha512-UkVDEFk1w3mveXeKgaTuYfKWtPbvgck1dT8TUG3bnccrH0XtLTuAyfCoks4Q/M5ZGToSVJTIQYCzy2g/atAOeg==} + '@rollup/pluginutils@5.3.0': resolution: {integrity: sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==} engines: {node: '>=14.0.0'} @@ -4325,15 +4437,15 @@ packages: peerDependencies: '@sveltejs/kit': ^2.0.0 - '@sveltejs/enhanced-img@0.10.3': - resolution: {integrity: sha512-/6tYiqVmVgWcntSD/TChENE74yN8Gde9JEN8gyGKtm2ytlsUzGiS8loPPiO7Lh4V/rSsOFbvLdXPdiNVztMArA==} + '@sveltejs/enhanced-img@0.10.4': + resolution: {integrity: sha512-Am5nmAKUo7Nboqq7Dhtfn7dcXA087d7gIz6Vecn1opB41aJ680+0q9U9KvEcMgduOyeiwckTIOQOx4Mmq9GcvA==} peerDependencies: - '@sveltejs/vite-plugin-svelte': ^6.0.0 + '@sveltejs/vite-plugin-svelte': ^6.0.0 || ^7.0.0 svelte: ^5.0.0 vite: ^6.3.0 || >=7.0.0 - '@sveltejs/kit@2.53.4': - resolution: {integrity: sha512-iAIPEahFgDJJyvz8g0jP08KvqnM6JvdW8YfsygZ+pMeMvyM2zssWMltcsotETvjSZ82G3VlitgDtBIvpQSZrTA==} + '@sveltejs/kit@2.55.0': + resolution: {integrity: sha512-MdFRjevVxmAknf2NbaUkDF16jSIzXMWd4Nfah0Qp8TtQVoSp3bV4jKt8mX7z7qTUTWvgSaxtR0EG5WJf53gcuA==} engines: {node: '>=18.13'} hasBin: true peerDependencies: @@ -4348,20 +4460,12 @@ packages: typescript: optional: true - '@sveltejs/vite-plugin-svelte-inspector@5.0.1': - resolution: {integrity: sha512-ubWshlMk4bc8mkwWbg6vNvCeT7lGQojE3ijDh3QTR6Zr/R+GXxsGbyH4PExEPpiFmqPhYiVSVmHBjUcVc1JIrA==} + '@sveltejs/vite-plugin-svelte@7.0.0': + resolution: {integrity: sha512-ILXmxC7HAsnkK2eslgPetrqqW1BKSL7LktsFgqzNj83MaivMGZzluWq32m25j2mDOjmSKX7GGWahePhuEs7P/g==} engines: {node: ^20.19 || ^22.12 || >=24} peerDependencies: - '@sveltejs/vite-plugin-svelte': ^6.0.0-next.0 - svelte: ^5.0.0 - vite: ^6.3.0 || ^7.0.0 - - '@sveltejs/vite-plugin-svelte@6.2.4': - resolution: {integrity: sha512-ou/d51QSdTyN26D7h6dSpusAKaZkAiGM55/AKYi+9AGZw7q85hElbjK3kEyzXHhLSnRISHOYzVge6x0jRZ7DXA==} - engines: {node: ^20.19 || ^22.12 || >=24} - peerDependencies: - svelte: ^5.0.0 - vite: ^6.3.0 || ^7.0.0 + svelte: ^5.46.4 + vite: ^8.0.0-beta.7 || ^8.0.0 '@svgr/babel-plugin-add-jsx-attribute@8.0.0': resolution: {integrity: sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g==} @@ -4527,69 +4631,69 @@ packages: resolution: {integrity: sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==} engines: {node: '>=14.16'} - '@tailwindcss/node@4.2.1': - resolution: {integrity: sha512-jlx6sLk4EOwO6hHe1oCGm1Q4AN/s0rSrTTPBGPM0/RQ6Uylwq17FuU8IeJJKEjtc6K6O07zsvP+gDO6MMWo7pg==} + '@tailwindcss/node@4.2.2': + resolution: {integrity: sha512-pXS+wJ2gZpVXqFaUEjojq7jzMpTGf8rU6ipJz5ovJV6PUGmlJ+jvIwGrzdHdQ80Sg+wmQxUFuoW1UAAwHNEdFA==} - '@tailwindcss/oxide-android-arm64@4.2.1': - resolution: {integrity: sha512-eZ7G1Zm5EC8OOKaesIKuw77jw++QJ2lL9N+dDpdQiAB/c/B2wDh0QPFHbkBVrXnwNugvrbJFk1gK2SsVjwWReg==} + '@tailwindcss/oxide-android-arm64@4.2.2': + resolution: {integrity: sha512-dXGR1n+P3B6748jZO/SvHZq7qBOqqzQ+yFrXpoOWWALWndF9MoSKAT3Q0fYgAzYzGhxNYOoysRvYlpixRBBoDg==} engines: {node: '>= 20'} cpu: [arm64] os: [android] - '@tailwindcss/oxide-darwin-arm64@4.2.1': - resolution: {integrity: sha512-q/LHkOstoJ7pI1J0q6djesLzRvQSIfEto148ppAd+BVQK0JYjQIFSK3JgYZJa+Yzi0DDa52ZsQx2rqytBnf8Hw==} + '@tailwindcss/oxide-darwin-arm64@4.2.2': + resolution: {integrity: sha512-iq9Qjr6knfMpZHj55/37ouZeykwbDqF21gPFtfnhCCKGDcPI/21FKC9XdMO/XyBM7qKORx6UIhGgg6jLl7BZlg==} engines: {node: '>= 20'} cpu: [arm64] os: [darwin] - '@tailwindcss/oxide-darwin-x64@4.2.1': - resolution: {integrity: sha512-/f/ozlaXGY6QLbpvd/kFTro2l18f7dHKpB+ieXz+Cijl4Mt9AI2rTrpq7V+t04nK+j9XBQHnSMdeQRhbGyt6fw==} + '@tailwindcss/oxide-darwin-x64@4.2.2': + resolution: {integrity: sha512-BlR+2c3nzc8f2G639LpL89YY4bdcIdUmiOOkv2GQv4/4M0vJlpXEa0JXNHhCHU7VWOKWT/CjqHdTP8aUuDJkuw==} engines: {node: '>= 20'} cpu: [x64] os: [darwin] - '@tailwindcss/oxide-freebsd-x64@4.2.1': - resolution: {integrity: sha512-5e/AkgYJT/cpbkys/OU2Ei2jdETCLlifwm7ogMC7/hksI2fC3iiq6OcXwjibcIjPung0kRtR3TxEITkqgn0TcA==} + '@tailwindcss/oxide-freebsd-x64@4.2.2': + resolution: {integrity: sha512-YUqUgrGMSu2CDO82hzlQ5qSb5xmx3RUrke/QgnoEx7KvmRJHQuZHZmZTLSuuHwFf0DJPybFMXMYf+WJdxHy/nQ==} engines: {node: '>= 20'} cpu: [x64] os: [freebsd] - '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.1': - resolution: {integrity: sha512-Uny1EcVTTmerCKt/1ZuKTkb0x8ZaiuYucg2/kImO5A5Y/kBz41/+j0gxUZl+hTF3xkWpDmHX+TaWhOtba2Fyuw==} + '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.2': + resolution: {integrity: sha512-FPdhvsW6g06T9BWT0qTwiVZYE2WIFo2dY5aCSpjG/S/u1tby+wXoslXS0kl3/KXnULlLr1E3NPRRw0g7t2kgaQ==} engines: {node: '>= 20'} cpu: [arm] os: [linux] - '@tailwindcss/oxide-linux-arm64-gnu@4.2.1': - resolution: {integrity: sha512-CTrwomI+c7n6aSSQlsPL0roRiNMDQ/YzMD9EjcR+H4f0I1SQ8QqIuPnsVp7QgMkC1Qi8rtkekLkOFjo7OlEFRQ==} + '@tailwindcss/oxide-linux-arm64-gnu@4.2.2': + resolution: {integrity: sha512-4og1V+ftEPXGttOO7eCmW7VICmzzJWgMx+QXAJRAhjrSjumCwWqMfkDrNu1LXEQzNAwz28NCUpucgQPrR4S2yw==} engines: {node: '>= 20'} cpu: [arm64] os: [linux] libc: [glibc] - '@tailwindcss/oxide-linux-arm64-musl@4.2.1': - resolution: {integrity: sha512-WZA0CHRL/SP1TRbA5mp9htsppSEkWuQ4KsSUumYQnyl8ZdT39ntwqmz4IUHGN6p4XdSlYfJwM4rRzZLShHsGAQ==} + '@tailwindcss/oxide-linux-arm64-musl@4.2.2': + resolution: {integrity: sha512-oCfG/mS+/+XRlwNjnsNLVwnMWYH7tn/kYPsNPh+JSOMlnt93mYNCKHYzylRhI51X+TbR+ufNhhKKzm6QkqX8ag==} engines: {node: '>= 20'} cpu: [arm64] os: [linux] libc: [musl] - '@tailwindcss/oxide-linux-x64-gnu@4.2.1': - resolution: {integrity: sha512-qMFzxI2YlBOLW5PhblzuSWlWfwLHaneBE0xHzLrBgNtqN6mWfs+qYbhryGSXQjFYB1Dzf5w+LN5qbUTPhW7Y5g==} + '@tailwindcss/oxide-linux-x64-gnu@4.2.2': + resolution: {integrity: sha512-rTAGAkDgqbXHNp/xW0iugLVmX62wOp2PoE39BTCGKjv3Iocf6AFbRP/wZT/kuCxC9QBh9Pu8XPkv/zCZB2mcMg==} engines: {node: '>= 20'} cpu: [x64] os: [linux] libc: [glibc] - '@tailwindcss/oxide-linux-x64-musl@4.2.1': - resolution: {integrity: sha512-5r1X2FKnCMUPlXTWRYpHdPYUY6a1Ar/t7P24OuiEdEOmms5lyqjDRvVY1yy9Rmioh+AunQ0rWiOTPE8F9A3v5g==} + '@tailwindcss/oxide-linux-x64-musl@4.2.2': + resolution: {integrity: sha512-XW3t3qwbIwiSyRCggeO2zxe3KWaEbM0/kW9e8+0XpBgyKU4ATYzcVSMKteZJ1iukJ3HgHBjbg9P5YPRCVUxlnQ==} engines: {node: '>= 20'} cpu: [x64] os: [linux] libc: [musl] - '@tailwindcss/oxide-wasm32-wasi@4.2.1': - resolution: {integrity: sha512-MGFB5cVPvshR85MTJkEvqDUnuNoysrsRxd6vnk1Lf2tbiqNlXpHYZqkqOQalydienEWOHHFyyuTSYRsLfxFJ2Q==} + '@tailwindcss/oxide-wasm32-wasi@4.2.2': + resolution: {integrity: sha512-eKSztKsmEsn1O5lJ4ZAfyn41NfG7vzCg496YiGtMDV86jz1q/irhms5O0VrY6ZwTUkFy/EKG3RfWgxSI3VbZ8Q==} engines: {node: '>=14.0.0'} cpu: [wasm32] bundledDependencies: @@ -4600,26 +4704,26 @@ packages: - '@emnapi/wasi-threads' - tslib - '@tailwindcss/oxide-win32-arm64-msvc@4.2.1': - resolution: {integrity: sha512-YlUEHRHBGnCMh4Nj4GnqQyBtsshUPdiNroZj8VPkvTZSoHsilRCwXcVKnG9kyi0ZFAS/3u+qKHBdDc81SADTRA==} + '@tailwindcss/oxide-win32-arm64-msvc@4.2.2': + resolution: {integrity: sha512-qPmaQM4iKu5mxpsrWZMOZRgZv1tOZpUm+zdhhQP0VhJfyGGO3aUKdbh3gDZc/dPLQwW4eSqWGrrcWNBZWUWaXQ==} engines: {node: '>= 20'} cpu: [arm64] os: [win32] - '@tailwindcss/oxide-win32-x64-msvc@4.2.1': - resolution: {integrity: sha512-rbO34G5sMWWyrN/idLeVxAZgAKWrn5LiR3/I90Q9MkA67s6T1oB0xtTe+0heoBvHSpbU9Mk7i6uwJnpo4u21XQ==} + '@tailwindcss/oxide-win32-x64-msvc@4.2.2': + resolution: {integrity: sha512-1T/37VvI7WyH66b+vqHj/cLwnCxt7Qt3WFu5Q8hk65aOvlwAhs7rAp1VkulBJw/N4tMirXjVnylTR72uI0HGcA==} engines: {node: '>= 20'} cpu: [x64] os: [win32] - '@tailwindcss/oxide@4.2.1': - resolution: {integrity: sha512-yv9jeEFWnjKCI6/T3Oq50yQEOqmpmpfzG1hcZsAOaXFQPfzWprWrlHSdGPEF3WQTi8zu8ohC9Mh9J470nT5pUw==} + '@tailwindcss/oxide@4.2.2': + resolution: {integrity: sha512-qEUA07+E5kehxYp9BVMpq9E8vnJuBHfJEC0vPC5e7iL/hw7HR61aDKoVoKzrG+QKp56vhNZe4qwkRmMC0zDLvg==} engines: {node: '>= 20'} - '@tailwindcss/vite@4.2.1': - resolution: {integrity: sha512-TBf2sJjYeb28jD2U/OhwdW0bbOsxkWPwQ7SrqGf9sVcoYwZj7rkXljroBO9wKBut9XnmQLXanuDUeqQK0lGg/w==} + '@tailwindcss/vite@4.2.2': + resolution: {integrity: sha512-mEiF5HO1QqCLXoNEfXVA1Tzo+cYsrqV7w9Juj2wdUFyW07JRenqMG225MvPwr3ZD9N1bFQj46X7r33iHxLUW0w==} peerDependencies: - vite: ^5.2.0 || ^6 || ^7 + vite: ^5.2.0 || ^6 || ^7 || ^8 '@testing-library/dom@10.4.1': resolution: {integrity: sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==} @@ -4665,14 +4769,17 @@ packages: resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==} engines: {node: '>=10.13.0'} - '@turf/boolean-point-in-polygon@7.3.2': - resolution: {integrity: sha512-PAfPDQ0TW1+VLgZ7tReTSyZ/X41AW7/nMRQxVpY+h/aG7JomZJ779lojnODT4dWCn3IMTA3xD2dDDfVYBAQMYg==} + '@turf/boolean-point-in-polygon@7.3.4': + resolution: {integrity: sha512-v/4hfyY90Vz9cDgs2GwjQf+Lft8o7mNCLJOTz/iv8SHAIgMMX0czEoIaNVOJr7tBqPqwin1CGwsncrkf5C9n8Q==} - '@turf/helpers@7.3.2': - resolution: {integrity: sha512-5HFN42rgWjSobdTMxbuq+ZdXPcqp1IbMgFYULTLCplEQM3dXhsyRFe7DCss4Eiw12iW3q6Z5UeTNVfITsE5lgA==} + '@turf/helpers@7.3.4': + resolution: {integrity: sha512-U/S5qyqgx3WTvg4twaH0WxF3EixoTCfDsmk98g1E3/5e2YKp7JKYZdz0vivsS5/UZLJeZDEElOSFH4pUgp+l7g==} - '@turf/invariant@7.3.2': - resolution: {integrity: sha512-brGmL1EFhZH/YNXhq6S+8sPWBEnmvEyxMWJO8bUNOFZyWHYiRTwxQHZM+An1blkbQ77PiEzsdNAspZqE1j7YKA==} + '@turf/invariant@7.3.4': + resolution: {integrity: sha512-88Eo4va4rce9sNZs6XiMJowWkikM3cS2TBhaCKlU+GFHdNf8PFEpiU42VDU8q5tOF6/fu21Rvlke5odgOGW4AQ==} + + '@tybys/wasm-util@0.10.1': + resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} '@types/accepts@1.3.7': resolution: {integrity: sha512-Pay9fq2lM2wXPWbteBsRAGiWH2hig4ZE2asK+mm7kUzlxRTfL961rj89I6zV/E3PcIkDqyuBEcMxFT7rccugeQ==} @@ -5000,8 +5107,8 @@ packages: '@types/node@24.12.0': resolution: {integrity: sha512-GYDxsZi3ChgmckRT9HPU0WEhKLP08ev/Yfcq2AstjrDASOYCSXeyjDsHg4v5t4jOj7cyDX3vmprafKlWIG9MXQ==} - '@types/node@25.4.0': - resolution: {integrity: sha512-9wLpoeWuBlcbBpOY3XmzSTG3oscB6xjBEEtn+pYXTfhyXhIxC5FsBer2KTopBlvKEiW9l13po9fq+SJY/5lkhw==} + '@types/node@25.5.0': + resolution: {integrity: sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw==} '@types/nodemailer@7.0.11': resolution: {integrity: sha512-E+U4RzR2dKrx+u3N4DlsmLaDC6mMZOM/TPROxA0UAPiTgI0y4CEFBmZE+coGWTjakDriRsXG368lNk1u9Q0a2g==} @@ -5018,8 +5125,8 @@ packages: '@types/pg@8.15.6': resolution: {integrity: sha512-NoaMtzhxOrubeL/7UZuNTrejB4MPAJ0RpxZqXQf2qXuVlTPuG6Y8p4u9dKRaue4yjmC7ZhzVO2/Yyyn25znrPQ==} - '@types/pg@8.18.0': - resolution: {integrity: sha512-gT+oueVQkqnj6ajGJXblFR4iavIXWsGAFCk3dP4Kki5+a9R4NMt0JARdk6s8cUKcfUoqP5dAtDSLU8xYUTFV+Q==} + '@types/pg@8.20.0': + resolution: {integrity: sha512-bEPFOaMAHTEP1EzpvHTbmwR8UsFyHSKsRisLIHVMXnpNefSbGA1bD6CVy+qKjGSqmZqNqBDV2azOBo8TgkcVow==} '@types/picomatch@4.0.2': resolution: {integrity: sha512-qHHxQ+P9PysNEGbALT8f8YOSHW0KJu6l2xU8DYY0fu/EmGxXdVnuTLvFUvBgPJMSqXq29SYHveejeAha+4AYgA==} @@ -5132,63 +5239,63 @@ packages: '@types/yargs@17.0.35': resolution: {integrity: sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==} - '@typescript-eslint/eslint-plugin@8.56.1': - resolution: {integrity: sha512-Jz9ZztpB37dNC+HU2HI28Bs9QXpzCz+y/twHOwhyrIRdbuVDxSytJNDl6z/aAKlaRIwC7y8wJdkBv7FxYGgi0A==} + '@typescript-eslint/eslint-plugin@8.57.1': + resolution: {integrity: sha512-Gn3aqnvNl4NGc6x3/Bqk1AOn0thyTU9bqDRhiRnUWezgvr2OnhYCWCgC8zXXRVqBsIL1pSDt7T9nJUe0oM0kDQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.56.1 + '@typescript-eslint/parser': ^8.57.1 eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/parser@8.56.1': - resolution: {integrity: sha512-klQbnPAAiGYFyI02+znpBRLyjL4/BrBd0nyWkdC0s/6xFLkXYQ8OoRrSkqacS1ddVxf/LDyODIKbQ5TgKAf/Fg==} + '@typescript-eslint/parser@8.57.1': + resolution: {integrity: sha512-k4eNDan0EIMTT/dUKc/g+rsJ6wcHYhNPdY19VoX/EOtaAG8DLtKCykhrUnuHPYvinn5jhAPgD2Qw9hXBwrahsw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/project-service@8.56.1': - resolution: {integrity: sha512-TAdqQTzHNNvlVFfR+hu2PDJrURiwKsUvxFn1M0h95BB8ah5jejas08jUWG4dBA68jDMI988IvtfdAI53JzEHOQ==} + '@typescript-eslint/project-service@8.57.1': + resolution: {integrity: sha512-vx1F37BRO1OftsYlmG9xay1TqnjNVlqALymwWVuYTdo18XuKxtBpCj1QlzNIEHlvlB27osvXFWptYiEWsVdYsg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/scope-manager@8.56.1': - resolution: {integrity: sha512-YAi4VDKcIZp0O4tz/haYKhmIDZFEUPOreKbfdAN3SzUDMcPhJ8QI99xQXqX+HoUVq8cs85eRKnD+rne2UAnj2w==} + '@typescript-eslint/scope-manager@8.57.1': + resolution: {integrity: sha512-hs/QcpCwlwT2L5S+3fT6gp0PabyGk4Q0Rv2doJXA0435/OpnSR3VRgvrp8Xdoc3UAYSg9cyUjTeFXZEPg/3OKg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/tsconfig-utils@8.56.1': - resolution: {integrity: sha512-qOtCYzKEeyr3aR9f28mPJqBty7+DBqsdd63eO0yyDwc6vgThj2UjWfJIcsFeSucYydqcuudMOprZ+x1SpF3ZuQ==} + '@typescript-eslint/tsconfig-utils@8.57.1': + resolution: {integrity: sha512-0lgOZB8cl19fHO4eI46YUx2EceQqhgkPSuCGLlGi79L2jwYY1cxeYc1Nae8Aw1xjgW3PKVDLlr3YJ6Bxx8HkWg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/type-utils@8.56.1': - resolution: {integrity: sha512-yB/7dxi7MgTtGhZdaHCemf7PuwrHMenHjmzgUW1aJpO+bBU43OycnM3Wn+DdvDO/8zzA9HlhaJ0AUGuvri4oGg==} + '@typescript-eslint/type-utils@8.57.1': + resolution: {integrity: sha512-+Bwwm0ScukFdyoJsh2u6pp4S9ktegF98pYUU0hkphOOqdMB+1sNQhIz8y5E9+4pOioZijrkfNO/HUJVAFFfPKA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/types@8.56.1': - resolution: {integrity: sha512-dbMkdIUkIkchgGDIv7KLUpa0Mda4IYjo4IAMJUZ+3xNoUXxMsk9YtKpTHSChRS85o+H9ftm51gsK1dZReY9CVw==} + '@typescript-eslint/types@8.57.1': + resolution: {integrity: sha512-S29BOBPJSFUiblEl6RzPPjJt6w25A6XsBqRVDt53tA/tlL8q7ceQNZHTjPeONt/3S7KRI4quk+yP9jK2WjBiPQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@8.56.1': - resolution: {integrity: sha512-qzUL1qgalIvKWAf9C1HpvBjif+Vm6rcT5wZd4VoMb9+Km3iS3Cv9DY6dMRMDtPnwRAFyAi7YXJpTIEXLvdfPxg==} + '@typescript-eslint/typescript-estree@8.57.1': + resolution: {integrity: sha512-ybe2hS9G6pXpqGtPli9Gx9quNV0TWLOmh58ADlmZe9DguLq0tiAKVjirSbtM1szG6+QH6rVXyU6GTLQbWnMY+g==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/utils@8.56.1': - resolution: {integrity: sha512-HPAVNIME3tABJ61siYlHzSWCGtOoeP2RTIaHXFMPqjrQKCGB9OgUVdiNgH7TJS2JNIQ5qQ4RsAUDuGaGme/KOA==} + '@typescript-eslint/utils@8.57.1': + resolution: {integrity: sha512-XUNSJ/lEVFttPMMoDVA2r2bwrl8/oPx8cURtczkSEswY5T3AeLmCy+EKWQNdL4u0MmAHOjcWrqJp2cdvgjn8dQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/visitor-keys@8.56.1': - resolution: {integrity: sha512-KiROIzYdEV85YygXw6BI/Dx4fnBlFQu6Mq4QE4MOH9fFnhohw6wX/OAvDY2/C+ut0I3RSPKenvZJIVYqJNkhEw==} + '@typescript-eslint/visitor-keys@8.57.1': + resolution: {integrity: sha512-YWnmJkXbofiz9KbnbbwuA2rpGkFPLbAIetcCNO6mJ8gdhdZ/v7WDXsoGFAJuM6ikUFKTlSQnjWnVO4ux+UzS6A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@ungap/structured-clone@1.3.0': @@ -5207,11 +5314,11 @@ packages: '@vitest/browser': optional: true - '@vitest/coverage-v8@4.0.18': - resolution: {integrity: sha512-7i+N2i0+ME+2JFZhfuz7Tg/FqKtilHjGyGvoHYQ6iLV0zahbsJ9sljC9OcFcPDbhYKCet+sG8SsVqlyGvPflZg==} + '@vitest/coverage-v8@4.1.0': + resolution: {integrity: sha512-nDWulKeik2bL2Va/Wl4x7DLuTKAXa906iRFooIRPR+huHkcvp9QDkPQ2RJdmjOFrqOqvNfoSQLF68deE3xC3CQ==} peerDependencies: - '@vitest/browser': 4.0.18 - vitest: 4.0.18 + '@vitest/browser': 4.1.0 + vitest: 4.1.0 peerDependenciesMeta: '@vitest/browser': optional: true @@ -5219,8 +5326,8 @@ packages: '@vitest/expect@3.2.4': resolution: {integrity: sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==} - '@vitest/expect@4.0.18': - resolution: {integrity: sha512-8sCWUyckXXYvx4opfzVY03EOiYVxyNrHS5QxX3DAIi5dpJAAkyJezHCP77VMX4HKA2LDT/Jpfo8i2r5BE3GnQQ==} + '@vitest/expect@4.1.0': + resolution: {integrity: sha512-EIxG7k4wlWweuCLG9Y5InKFwpMEOyrMb6ZJ1ihYu02LVj/bzUwn2VMU+13PinsjRW75XnITeFrQBMH5+dLvCDA==} '@vitest/mocker@3.2.4': resolution: {integrity: sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==} @@ -5233,11 +5340,11 @@ packages: vite: optional: true - '@vitest/mocker@4.0.18': - resolution: {integrity: sha512-HhVd0MDnzzsgevnOWCBj5Otnzobjy5wLBe4EdeeFGv8luMsGcYqDuFRMcttKWZA5vVO8RFjexVovXvAM4JoJDQ==} + '@vitest/mocker@4.1.0': + resolution: {integrity: sha512-evxREh+Hork43+Y4IOhTo+h5lGmVRyjqI739Rz4RlUPqwrkFFDF6EMvOOYjTx4E8Tl6gyCLRL8Mu7Ry12a13Tw==} peerDependencies: msw: ^2.4.9 - vite: ^6.0.0 || ^7.0.0-0 + vite: ^6.0.0 || ^7.0.0 || ^8.0.0-0 peerDependenciesMeta: msw: optional: true @@ -5247,32 +5354,32 @@ packages: '@vitest/pretty-format@3.2.4': resolution: {integrity: sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==} - '@vitest/pretty-format@4.0.18': - resolution: {integrity: sha512-P24GK3GulZWC5tz87ux0m8OADrQIUVDPIjjj65vBXYG17ZeU3qD7r+MNZ1RNv4l8CGU2vtTRqixrOi9fYk/yKw==} + '@vitest/pretty-format@4.1.0': + resolution: {integrity: sha512-3RZLZlh88Ib0J7NQTRATfc/3ZPOnSUn2uDBUoGNn5T36+bALixmzphN26OUD3LRXWkJu4H0s5vvUeqBiw+kS0A==} '@vitest/runner@3.2.4': resolution: {integrity: sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==} - '@vitest/runner@4.0.18': - resolution: {integrity: sha512-rpk9y12PGa22Jg6g5M3UVVnTS7+zycIGk9ZNGN+m6tZHKQb7jrP7/77WfZy13Y/EUDd52NDsLRQhYKtv7XfPQw==} + '@vitest/runner@4.1.0': + resolution: {integrity: sha512-Duvx2OzQ7d6OjchL+trw+aSrb9idh7pnNfxrklo14p3zmNL4qPCDeIJAK+eBKYjkIwG96Bc6vYuxhqDXQOWpoQ==} '@vitest/snapshot@3.2.4': resolution: {integrity: sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==} - '@vitest/snapshot@4.0.18': - resolution: {integrity: sha512-PCiV0rcl7jKQjbgYqjtakly6T1uwv/5BQ9SwBLekVg/EaYeQFPiXcgrC2Y7vDMA8dM1SUEAEV82kgSQIlXNMvA==} + '@vitest/snapshot@4.1.0': + resolution: {integrity: sha512-0Vy9euT1kgsnj1CHttwi9i9o+4rRLEaPRSOJ5gyv579GJkNpgJK+B4HSv/rAWixx2wdAFci1X4CEPjiu2bXIMg==} '@vitest/spy@3.2.4': resolution: {integrity: sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==} - '@vitest/spy@4.0.18': - resolution: {integrity: sha512-cbQt3PTSD7P2OARdVW3qWER5EGq7PHlvE+QfzSC0lbwO+xnt7+XH06ZzFjFRgzUX//JmpxrCu92VdwvEPlWSNw==} + '@vitest/spy@4.1.0': + resolution: {integrity: sha512-pz77k+PgNpyMDv2FV6qmk5ZVau6c3R8HC8v342T2xlFxQKTrSeYw9waIJG8KgV9fFwAtTu4ceRzMivPTH6wSxw==} '@vitest/utils@3.2.4': resolution: {integrity: sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==} - '@vitest/utils@4.0.18': - resolution: {integrity: sha512-msMRKLMVLWygpK3u2Hybgi4MNjcYJvwTb0Ru09+fOyCXIgT5raYP041DRRdiJiI3k/2U6SEbAETB3YtBrUkCFA==} + '@vitest/utils@4.1.0': + resolution: {integrity: sha512-XfPXT6a8TZY3dcGY8EdwsBulFCIw+BeeX0RZn2x/BtiY/75YGh8FeWGG8QISN/WhaqSrE2OrlDgtF8q5uhOTmw==} '@webassemblyjs/ast@1.14.1': resolution: {integrity: sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==} @@ -5558,6 +5665,9 @@ packages: ast-v8-to-istanbul@0.3.12: resolution: {integrity: sha512-BRRC8VRZY2R4Z4lFIL35MwNXmwVqBityvOIwETtsCSwvjl0IdgFsy9NhdaA6j74nUdtJJlIypeRhpDam19Wq3g==} + ast-v8-to-istanbul@1.0.0: + resolution: {integrity: sha512-1fSfIwuDICFA4LKkCzRPO7F0hzFf0B7+Xqrl27ynQaa+Rh0e1Es0v6kWHPott3lU10AyAr7oKHa65OppjLn3Rg==} + astring@1.9.0: resolution: {integrity: sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==} hasBin: true @@ -5588,8 +5698,8 @@ packages: resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} engines: {node: '>= 0.4'} - b4a@1.7.3: - resolution: {integrity: sha512-5Q2mfq2WfGuFp3uS//0s6baOJLMoVduPYVeNmDYxu5OUA1/cBfvr2RIS7vi62LdNj/urk1hfmj867I3qt6uZ7Q==} + b4a@1.8.0: + resolution: {integrity: sha512-qRuSmNSkGQaHwNbM7J78Wwy+ghLEYF1zNrSeMxj4Kgw6y33O3mXcQ6Ie9fRvfU/YnxWkOchPXbaLb73TkIsfdg==} peerDependencies: react-native-b4a: '*' peerDependenciesMeta: @@ -5642,8 +5752,8 @@ packages: bare-abort-controller: optional: true - bare-fs@4.5.4: - resolution: {integrity: sha512-POK4oplfA7P7gqvetNmCs4CNtm9fNsx+IAh7jH7GgU0OJdge2rso0R20TNWVq6VoWcCvsTdlNDaleLHGaKx8CA==} + bare-fs@4.5.6: + resolution: {integrity: sha512-1QovqDrR80Pmt5HPAsMsXTCFcDYr+NSUKW6nd6WO5v0JBmnItc/irNRzm2KOQ5oZ69P37y+AMujNyNtG+1Rggw==} engines: {bare: '>=1.16.0'} peerDependencies: bare-buffer: '*' @@ -5651,26 +5761,29 @@ packages: bare-buffer: optional: true - bare-os@3.6.2: - resolution: {integrity: sha512-T+V1+1srU2qYNBmJCXZkUY5vQ0B4FSlL3QDROnKQYOqeiQR8UbjNHlPa+TIbM4cuidiN9GaTaOZgSEgsvPbh5A==} + bare-os@3.8.0: + resolution: {integrity: sha512-Dc9/SlwfxkXIGYhvMQNUtKaXCaGkZYGcd1vuNUUADVqzu4/vQfvnMkYYOUnt2VwQ2AqKr/8qAVFRtwETljgeFg==} engines: {bare: '>=1.14.0'} bare-path@3.0.0: resolution: {integrity: sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw==} - bare-stream@2.8.0: - resolution: {integrity: sha512-reUN0M2sHRqCdG4lUK3Fw8w98eeUIZHL5c3H7Mbhk2yVBL+oofgaIp0ieLfD5QXwPCypBpmEEKU2WZKzbAk8GA==} + bare-stream@2.11.0: + resolution: {integrity: sha512-Y/+iQ49fL3rIn6w/AVxI/2+BRrpmzJvdWt5Jv8Za6Ngqc6V227c+pYjYYgLdpR3MwQ9ObVXD0ZrqoBztakM0rw==} peerDependencies: + bare-abort-controller: '*' bare-buffer: '*' bare-events: '*' peerDependenciesMeta: + bare-abort-controller: + optional: true bare-buffer: optional: true bare-events: optional: true - bare-url@2.3.2: - resolution: {integrity: sha512-ZMq4gd9ngV5aTMa5p9+UfY0b3skwhHELaDkhEHetMdX0LRkW9kzaym4oo/Eh+Ghm0CCDuMTsRIGM/ytUc1ZYmw==} + bare-url@2.4.0: + resolution: {integrity: sha512-NSTU5WN+fy/L0DDenfE8SXQna4voXuW0FHM7wH8i3/q9khUSchfPbPezO4zSFMnDGIf9YE+mt/RWhZgNRKRIXA==} base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} @@ -5746,8 +5859,8 @@ packages: brace-expansion@2.0.2: resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} - brace-expansion@5.0.4: - resolution: {integrity: sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==} + brace-expansion@5.0.5: + resolution: {integrity: sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==} engines: {node: 18 || 20 || >=22} braces@3.0.3: @@ -5783,8 +5896,8 @@ packages: resolution: {integrity: sha512-bkXY9WsVpY7CvMhKSR6pZilZu9Ln5WDrKVBUXf2S443etkmEO4V58heTecXcUIsNsi4Rx8JUO4NfX1IcQl4deg==} engines: {node: '>=18.20'} - bullmq@5.70.4: - resolution: {integrity: sha512-S58YT/tGdhc4pEPcIahtZRBR1TcTLpss1UKiXimF+Vy4yZwF38pW2IvhHqs4j4dEbZqDt8oi0jGGN/WYQHbPDg==} + bullmq@5.71.0: + resolution: {integrity: sha512-aeNWh4drsafSKnAJeiNH/nZP/5O8ZdtdMbnOPZmpjXj7NZUP5YC901U3bIH41iZValm7d1i3c34ojv7q31m30w==} bundle-name@4.1.0: resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==} @@ -6749,8 +6862,8 @@ packages: engines: {node: '>= 4.0.0'} hasBin: true - devalue@5.6.3: - resolution: {integrity: sha512-nc7XjUU/2Lb+SvEFVGcWLiKkzfw8+qHI7zn8WYXKkLMgfGSHbgCEaR6bJpev8Cm6Rmrb19Gfd/tZvGqx9is3wg==} + devalue@5.6.4: + resolution: {integrity: sha512-Gp6rDldRsFh/7XuouDbxMH3Mx8GMCcgzIb1pDTvNyn8pZGQ22u+Wa+lGV9dQCltFQ7uVw0MhRyb8XDskNFOReA==} devlop@1.1.0: resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} @@ -6789,16 +6902,16 @@ packages: resolution: {integrity: sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==} engines: {node: '>=6'} - docker-compose@1.3.1: - resolution: {integrity: sha512-rF0wH69G3CCcmkN9J1RVMQBaKe8o77LT/3XmqcLIltWWVxcWAzp2TnO7wS3n/umZHN3/EVrlT3exSBMal+Ou1w==} + docker-compose@1.3.3: + resolution: {integrity: sha512-LzcZ6Dk+Ps5SbLZ4iqAcagzYFZ+bBWQ52uzUNfORNkXyash2EjHZI4REf1ccG19emroS0iWElfQN8RQJ8HOIIg==} engines: {node: '>= 6.0.0'} - docker-modem@5.0.6: - resolution: {integrity: sha512-ens7BiayssQz/uAxGzH8zGXCtiV24rRWXdjNha5V4zSOcxmAZsfGVm/PPFbwQdqEkDnhG+SyR9E3zSHUbOKXBQ==} + docker-modem@5.0.7: + resolution: {integrity: sha512-XJgGhoR/CLpqshm4d3L7rzH6t8NgDFUIIpztYlLHIApeJjMZKYJMz2zxPsYxnejq5h3ELYSw/RBsi3t5h7gNTA==} engines: {node: '>= 8.0'} - dockerode@4.0.9: - resolution: {integrity: sha512-iND4mcOWhPaCNh54WmK/KoSb35AFqPAUWFMffTQcp52uQt36b5uNwEJTSXntJZBbeGad72Crbi/hvDIv6us/6Q==} + dockerode@4.0.10: + resolution: {integrity: sha512-8L/P9JynLBiG7/coiA4FlQXegHltRqS0a+KqI44P1zgQh8QLHTg7FKOwhkBgSJwZTeHsq30WRoVFLuwkfK0YFg==} engines: {node: '>= 8.0'} docusaurus-lunr-search@3.6.0: @@ -7001,8 +7114,8 @@ packages: engines: {node: '>=18'} hasBin: true - esbuild@0.27.3: - resolution: {integrity: sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==} + esbuild@0.27.4: + resolution: {integrity: sha512-Rq4vbHnYkK5fws5NF7MYTU68FPRE1ajX7heQ/8QXXWqNgqqJ/GkmmyxIzUnf2Sr/bakf8l54716CcMGHYhMrrQ==} engines: {node: '>=18'} hasBin: true @@ -7055,8 +7168,8 @@ packages: eslint-config-prettier: optional: true - eslint-plugin-svelte@3.15.0: - resolution: {integrity: sha512-QKB7zqfuB8aChOfBTComgDptMf2yxiJx7FE04nneCmtQzgTHvY8UJkuh8J2Rz7KB9FFV9aTHX6r7rdYGvG8T9Q==} + eslint-plugin-svelte@3.16.0: + resolution: {integrity: sha512-DJXxqpYZUxcE0SfYo8EJzV2ZC+zAD7fJp1n1HwcEMRR1cOEUYvjT9GuzJeNghMjgb7uxuK3IJAzI+x6zzUxO5A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.1 || ^9.0.0 || ^10.0.0 @@ -7079,8 +7192,8 @@ packages: resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - eslint-scope@9.1.1: - resolution: {integrity: sha512-GaUN0sWim5qc8KVErfPBWmc31LEsOkrUJbvJZV+xuL3u2phMUK4HIvXlWAakfC8W4nzlK+chPEAkYOYb5ZScIw==} + eslint-scope@9.1.2: + resolution: {integrity: sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} eslint-visitor-keys@3.4.3: @@ -7095,8 +7208,8 @@ packages: resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} - eslint@10.0.2: - resolution: {integrity: sha512-uYixubwmqJZH+KLVYIVKY1JQt7tysXhtj21WSvjcSmU5SVNzMus1bgLe+pAt816yQ8opKfheVVoPLqvVMGejYw==} + eslint@10.1.0: + resolution: {integrity: sha512-S9jlY/ELKEUwwQnqWDO+f+m6sercqOPSqXM5Go94l7DOmxHVDgmSFGWEzeE/gwgTAr0W103BWt0QLe/7mabIvA==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} hasBin: true peerDependencies: @@ -7116,8 +7229,8 @@ packages: resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - espree@11.1.1: - resolution: {integrity: sha512-AVHPqQoZYc+RUM4/3Ly5udlZY/U4LS8pIG05jEjWM2lQMU/oaZ7qshzAl2YP1tfNmXfftH3ohurfwNAug+MnsQ==} + espree@11.2.0: + resolution: {integrity: sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} esprima@4.0.1: @@ -7336,8 +7449,8 @@ packages: file-source@0.6.1: resolution: {integrity: sha512-1R1KneL7eTXmXfKxC10V/9NeGOdbsAXJ+lQ//fvvcHUgtaZcZDWNJNblxAoVOyV1cj45pOtUrR3vZTBwqcW8XA==} - file-type@21.3.0: - resolution: {integrity: sha512-8kPJMIGz1Yt/aPEwOsrR97ZyZaD1Iqm8PClb1nYFclUCkBi0Ma5IsYNQzvSFS9ib51lWyIw5mIT9rWzI/xjpzA==} + file-type@21.3.2: + resolution: {integrity: sha512-DLkUvGwep3poOV2wpzbHCOnSKGk1LzyXTv+aHFgN2VFl96wnp8YA9YjO2qPzg5PuL8q/SW9Pdi6WTkYOIh995w==} engines: {node: '>=20'} fill-range@7.1.1: @@ -7380,8 +7493,8 @@ packages: resolution: {integrity: sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==} hasBin: true - flatted@3.3.3: - resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} + flatted@3.4.2: + resolution: {integrity: sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==} fluent-ffmpeg@2.1.3: resolution: {integrity: sha512-Be3narBNt2s6bsaqP6Jzq91heDgOEaDCJAXcE3qcma/EJBSy5FB4cvO31XBInuAuKBx8Kptf8dkhjK0IOru39Q==} @@ -7495,8 +7608,8 @@ packages: geo-coordinates-parser@1.7.4: resolution: {integrity: sha512-gVGxBW+s1csexXVMf5bIwz3TH9n4sCEglOOOqmrPk8YazUI5f79jCowKjTw05m/0h1//3+Z2m/nv8IIozgZyUw==} - geo-tz@8.1.5: - resolution: {integrity: sha512-C0g6Zyo/4/wtaONcprVq6gHq4LnbheC7HXXi0nZMG8lbxqvOj8IZcTolCd0MeOmBekXnyXKKeDlh6g2o4Yy3qw==} + geo-tz@8.1.6: + resolution: {integrity: sha512-6YEper1rtHi1l3ZS99oy9ZBvrBO4qsLzvQwZoxYtV3fyxPuxh7yqiOUWRVs1bzSj693EXEO4k60jKXQmkY/JnQ==} engines: {node: '>=16'} geobuf@3.0.2: @@ -7522,8 +7635,8 @@ packages: get-own-enumerable-property-symbols@3.0.2: resolution: {integrity: sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==} - get-port@7.1.0: - resolution: {integrity: sha512-QB9NKEeDg3xxVwCCwJQ9+xycaz6pBB6iQ76wiWMl1927n0Kir6alPiP+yuiICLLU4jpMe08dXfpebuQppFA2zw==} + get-port@7.2.0: + resolution: {integrity: sha512-afP4W205ONCuMoPBqcR6PSXnzX35KTcJygfJfcp+QY+uwm3p20p1YczWXhlICIzGMCxYBQcySEcOgsJcrkyobg==} engines: {node: '>=16'} get-proto@1.0.1: @@ -7646,8 +7759,8 @@ packages: engines: {node: '>=0.4.7'} hasBin: true - happy-dom@20.8.3: - resolution: {integrity: sha512-lMHQRRwIPyJ70HV0kkFT7jH/gXzSI7yDkQFe07E2flwmNDFoWUTRMKpW2sglsnpeA7b6S2TJPp98EbQxai8eaQ==} + happy-dom@20.8.4: + resolution: {integrity: sha512-GKhjq4OQCYB4VLFBzv8mmccUadwlAusOZOI7hC1D9xDIT5HhzkJK17c4el2f6R6C715P9xB4uiMxeKUa2nHMwQ==} engines: {node: '>=20.0.0'} has-flag@4.0.0: @@ -7731,6 +7844,10 @@ packages: resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} hasBin: true + helmet@8.1.0: + resolution: {integrity: sha512-jOiHyAZsmnr8LqoPGmCjYAaiuWwjAPLgY8ZX2XrmHawt99/u1y6RgrZMTeoPfpUbV96HOalYgz1qzkRbw54Pmg==} + engines: {node: '>=18.0.0'} + highlight.js@11.11.1: resolution: {integrity: sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==} engines: {node: '>=12.0.0'} @@ -7972,14 +8089,14 @@ packages: intl-messageformat@10.7.18: resolution: {integrity: sha512-m3Ofv/X/tV8Y3tHXLohcuVuhWKo7BBq62cqY15etqmLxg2DZ34AGGgQDeR+SCta2+zICb1NX83af0GJmbQ1++g==} - intl-messageformat@11.1.2: - resolution: {integrity: sha512-ucSrQmZGAxfiBHfBRXW/k7UC8MaGFlEj4Ry1tKiDcmgwQm1y3EDl40u+4VNHYomxJQMJi9NEI3riDRlth96jKg==} + intl-messageformat@11.2.0: + resolution: {integrity: sha512-IhghAA8n4KSlXuWKzYsWyWb82JoYTzShfyvdSF85oJPnNOjvv4kAo7S7Jtkm3/vJ53C7dQNRO+Gpnj3iWgTjBQ==} invariant@2.2.4: resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==} - ioredis@5.10.0: - resolution: {integrity: sha512-HVBe9OFuqs+Z6n64q09PQvP1/R4Bm+30PAyyD4wIEqssh3v9L21QjCVk4kRLucMBcDokJTcLjsGeVRlq/nH6DA==} + ioredis@5.10.1: + resolution: {integrity: sha512-HuEDBTI70aYdx1v6U97SbNx9F1+svQKBDo30o0b9fw055LMepzpOOd0Ccg9Q6tbqmBSJaMuY0fB7yw9/vjBYCA==} engines: {node: '>=12.22.0'} ioredis@5.9.3: @@ -8248,8 +8365,8 @@ packages: jose@5.10.0: resolution: {integrity: sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg==} - jose@6.1.3: - resolution: {integrity: sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ==} + jose@6.2.2: + resolution: {integrity: sha512-d7kPDd34KO/YnzaDOlikGpOurfF0ByC2sEV4cANCtdqLlTfBlw2p14O/5d/zv40gJPbIQxfES3nSx1/oYNyuZQ==} js-tokens@10.0.0: resolution: {integrity: sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==} @@ -8381,8 +8498,8 @@ packages: koa-compose@4.1.0: resolution: {integrity: sha512-8ODW8TrDuMYvXRwra/Kh7/rJo9BtOfPc6qO8eAfC80CnCvSjSl0bkRM24X6/XBBEyj0v1nRUQ1LyOy3dbqOWXw==} - koa@3.1.1: - resolution: {integrity: sha512-KDDuvpfqSK0ZKEO2gCPedNjl5wYpfj+HNiuVRlbhd1A88S3M0ySkdf2V/EJ4NWt5dwh5PXCdcenrKK2IQJAxsg==} + koa@3.1.2: + resolution: {integrity: sha512-2LOQnFKu3m0VxpE+5sb5+BRTSKrXmNxGgxVRiKwD9s5KQB1zID/FRXhtzeV7RT1L2GVpdEEAfVuclFOMGl1ikA==} engines: {node: '>= 18'} kysely-postgres-js@3.0.0: @@ -8395,8 +8512,8 @@ packages: postgres: optional: true - kysely@0.28.11: - resolution: {integrity: sha512-zpGIFg0HuoC893rIjYX1BETkVWdDnzTzF5e0kWXJFg5lE0k1/LfNWBejrcnOFu8Q2Rfq/hTDTU7XLUM8QOrpzg==} + kysely@0.28.14: + resolution: {integrity: sha512-SU3lgh0rPvq7upc6vvdVrCsSMUG1h3ChvHVOY7wJ2fw4C9QEB7X3d5eyYEyULUX7UQtxZJtZXGuT6U2US72UYA==} engines: {node: '>=20.0.0'} langium@3.3.1: @@ -8434,78 +8551,78 @@ packages: libphonenumber-js@1.12.38: resolution: {integrity: sha512-vwzxmasAy9hZigxtqTbFEwp8ZdZ975TiqVDwj5bKx5sR+zi5ucUQy9mbVTkKM9GzqdLdxux/hTw2nmN5J7POMA==} - lightningcss-android-arm64@1.31.1: - resolution: {integrity: sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg==} + lightningcss-android-arm64@1.32.0: + resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [android] - lightningcss-darwin-arm64@1.31.1: - resolution: {integrity: sha512-02uTEqf3vIfNMq3h/z2cJfcOXnQ0GRwQrkmPafhueLb2h7mqEidiCzkE4gBMEH65abHRiQvhdcQ+aP0D0g67sg==} + lightningcss-darwin-arm64@1.32.0: + resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [darwin] - lightningcss-darwin-x64@1.31.1: - resolution: {integrity: sha512-1ObhyoCY+tGxtsz1lSx5NXCj3nirk0Y0kB/g8B8DT+sSx4G9djitg9ejFnjb3gJNWo7qXH4DIy2SUHvpoFwfTA==} + lightningcss-darwin-x64@1.32.0: + resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [darwin] - lightningcss-freebsd-x64@1.31.1: - resolution: {integrity: sha512-1RINmQKAItO6ISxYgPwszQE1BrsVU5aB45ho6O42mu96UiZBxEXsuQ7cJW4zs4CEodPUioj/QrXW1r9pLUM74A==} + lightningcss-freebsd-x64@1.32.0: + resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [freebsd] - lightningcss-linux-arm-gnueabihf@1.31.1: - resolution: {integrity: sha512-OOCm2//MZJ87CdDK62rZIu+aw9gBv4azMJuA8/KB74wmfS3lnC4yoPHm0uXZ/dvNNHmnZnB8XLAZzObeG0nS1g==} + lightningcss-linux-arm-gnueabihf@1.32.0: + resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} engines: {node: '>= 12.0.0'} cpu: [arm] os: [linux] - lightningcss-linux-arm64-gnu@1.31.1: - resolution: {integrity: sha512-WKyLWztD71rTnou4xAD5kQT+982wvca7E6QoLpoawZ1gP9JM0GJj4Tp5jMUh9B3AitHbRZ2/H3W5xQmdEOUlLg==} + lightningcss-linux-arm64-gnu@1.32.0: + resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] libc: [glibc] - lightningcss-linux-arm64-musl@1.31.1: - resolution: {integrity: sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg==} + lightningcss-linux-arm64-musl@1.32.0: + resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] libc: [musl] - lightningcss-linux-x64-gnu@1.31.1: - resolution: {integrity: sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA==} + lightningcss-linux-x64-gnu@1.32.0: + resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] libc: [glibc] - lightningcss-linux-x64-musl@1.31.1: - resolution: {integrity: sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA==} + lightningcss-linux-x64-musl@1.32.0: + resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] libc: [musl] - lightningcss-win32-arm64-msvc@1.31.1: - resolution: {integrity: sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w==} + lightningcss-win32-arm64-msvc@1.32.0: + resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [win32] - lightningcss-win32-x64-msvc@1.31.1: - resolution: {integrity: sha512-I9aiFrbd7oYHwlnQDqr1Roz+fTz61oDDJX7n9tYF9FJymH1cIN1DtKw3iYt6b8WZgEjoNwVSncwF4wx/ZedMhw==} + lightningcss-win32-x64-msvc@1.32.0: + resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [win32] - lightningcss@1.31.1: - resolution: {integrity: sha512-l51N2r93WmGUye3WuFoN5k10zyvrVs0qfKBhyC5ogUQ6Ew6JUSswh78mbSO+IU3nTWsyOArqPCcShdQSadghBQ==} + lightningcss@1.32.0: + resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} engines: {node: '>= 12.0.0'} lilconfig@2.1.0: @@ -8681,8 +8798,8 @@ packages: resolution: {integrity: sha512-iyyEpDty1mwW3dGlYXAJqC/azFn5PPvgKVwXayOGBSmKLxhKZ9fg4qIan2ePpp1vJIwfFiO34LAPZgq9SZW9Aw==} engines: {node: ^20.17.0 || >=22.9.0} - maplibre-gl@5.19.0: - resolution: {integrity: sha512-REhYUN8gNP3HlcIZS6QU2uy8iovl31cXsrNDkCcqWSQbCkcpdYLczqDz5PVIwNH42UQNyvukjes/RoHPDrOUmQ==} + maplibre-gl@5.21.0: + resolution: {integrity: sha512-n0v4J/Ge0EG8ix/z3TY3ragtJYMqzbtSnj1riOC0OwQbzwp0lUF2maS1ve1z8HhitQCKtZZiZJhb8to36aMMfQ==} engines: {node: '>=16.14.0', npm: '>=8.1.0'} mark.js@8.11.1: @@ -9021,12 +9138,15 @@ packages: minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} - minimatch@5.1.6: - resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} + minimatch@3.1.5: + resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==} + + minimatch@5.1.9: + resolution: {integrity: sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==} engines: {node: '>=10'} - minimatch@9.0.6: - resolution: {integrity: sha512-kQAVowdR33euIqeA0+VZTDqU+qo1IeVY+hrKYtZMio3Pg0P0vuh/kwRylLUddJhB6pf3q/botcOvRtx4IN1wqQ==} + minimatch@9.0.9: + resolution: {integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==} engines: {node: '>=16 || 14 >=14.17'} minimist@1.2.8: @@ -9147,16 +9267,16 @@ packages: mz@2.7.0: resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} - nan@2.25.0: - resolution: {integrity: sha512-0M90Ag7Xn5KMLLZ7zliPWP3rT90P6PN+IzVFS0VqmnPktBk3700xUVv8Ikm9EUaUE5SDWdp/BIxdENzVznpm1g==} + nan@2.26.2: + resolution: {integrity: sha512-0tTvBTYkt3tdGw22nrAy50x7gpbGCCFH3AFcyS5WiUu7Eu4vWlri1woE6qHBSfy11vksDqkiwjOnlR7WV8G1Hw==} nanoid@3.3.11: resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true - nanoid@5.1.6: - resolution: {integrity: sha512-c7+7RQ+dMB5dPwwCp4ee1/iV/q2P6aK1mTZcfr1BTuVlyW9hJYiMPybJCcnBlQtuSmTIWNeazm/zqNoZSSElBg==} + nanoid@5.1.7: + resolution: {integrity: sha512-ua3NDgISf6jdwezAheMOk4mbE1LXjm1DfMUDMuJf4AqxLFK3ccGpgWizwa5YV7Yz9EpXwEaWoRXSb/BnV0t5dQ==} engines: {node: ^18 || >=20} hasBin: true @@ -9363,8 +9483,8 @@ packages: obug@2.1.1: resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} - oidc-provider@9.6.1: - resolution: {integrity: sha512-8AtFXE4gEV6MLd8Re78VhqGNjBm/SUw0fUxrP2XwQc+5DZKw6GyuTuy2M4jkidpH3jRrhtkkqQpXlxD1Awi6tg==} + oidc-provider@9.7.1: + resolution: {integrity: sha512-yzOdAYxQEisPspCy6xVPrK++bYz71011uylwhR3XLDfb3r0NfVuJStApQvXoeMXj928nkZoxRTBC4ECYM94KOw==} on-finished@2.4.1: resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} @@ -9553,8 +9673,8 @@ packages: path-source@0.1.3: resolution: {integrity: sha512-dWRHm5mIw5kw0cs3QZLNmpUWty48f5+5v9nWD2dw3Y0Hf+s01Ag8iJEWV0Sm0kocE8kK27DrIowha03e1YR+Qw==} - path-to-regexp@0.1.12: - resolution: {integrity: sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==} + path-to-regexp@0.1.13: + resolution: {integrity: sha512-A/AGNMFN3c8bOlvV9RreMdrv7jsmF9XIfDeCd87+I8RNg6s78BhJxMu69NEMHBSJFxKidViTEdruRwEk/WIKqA==} path-to-regexp@1.9.0: resolution: {integrity: sha512-xIp7/apCFJuUHdDLWe8O1HIkb0kQrOMb/0u6FXQjemHn/ii5LrIzU6bdECnsiTF/GjZkMEKg1xdiZwNqDYlZ6g==} @@ -9624,16 +9744,16 @@ packages: picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} - picomatch@2.3.1: - resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + picomatch@2.3.2: + resolution: {integrity: sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==} engines: {node: '>=8.6'} picomatch@4.0.2: resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} engines: {node: '>=12'} - picomatch@4.0.3: - resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} + picomatch@4.0.4: + resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} engines: {node: '>=12'} pify@2.3.0: @@ -10269,8 +10389,8 @@ packages: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} engines: {node: '>= 0.10'} - pump@3.0.3: - resolution: {integrity: sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==} + pump@3.0.4: + resolution: {integrity: sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==} punycode@1.4.1: resolution: {integrity: sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==} @@ -10614,8 +10734,13 @@ packages: deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true - robust-predicates@3.0.2: - resolution: {integrity: sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==} + robust-predicates@3.0.3: + resolution: {integrity: sha512-NS3levdsRIUOmiJ8FZWCP7LG3QpJyrs/TE0Zpf1yvZu8cAJJ6QMW92H1c7kWpdIHo8RvmLxN/o2JXTKHp74lUA==} + + rolldown@1.0.0-rc.10: + resolution: {integrity: sha512-q7j6vvarRFmKpgJUT8HCAUljkgzEp4LAhPlJUvQhA5LA1SUL36s5QCysMutErzL3EbNOZOkoziSx9iZC4FddKA==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true rollup-plugin-visualizer@6.0.11: resolution: {integrity: sha512-TBwVHVY7buHjIKVLqr9scTVFwqZqMXINcCphPwIWKPDCOBIa+jCQfafvbjRJDZgXdq/A996Dy6yGJ/+/NtAXDQ==} @@ -10692,11 +10817,11 @@ packages: safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - sanitize-filename@1.6.3: - resolution: {integrity: sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg==} + sanitize-filename@1.6.4: + resolution: {integrity: sha512-9ZyI08PsvdQl2r/bBIGubpVdR3RR9sY6RDiWFPreA21C/EFlQhmgo20UZlNjZMMZNubusLhAQozkA0Od5J21Eg==} - sanitize-html@2.17.1: - resolution: {integrity: sha512-ehFCW+q1a4CSOWRAdX97BX/6/PDEkCqw7/0JXZAGQV57FQB3YOkTa/rrzHPeJ+Aghy4vZAFfWMYyfxIiB7F/gw==} + sanitize-html@2.17.2: + resolution: {integrity: sha512-EnffJUl46VE9uvZ0XeWzObHLurClLlT12gsOk1cHyP2Ol1P0BnBnsXmShlBmWVJM+dKieQI68R0tsPY5m/B+Jg==} sass@1.97.1: resolution: {integrity: sha512-uf6HoO8fy6ClsrShvMgaKUn14f2EHQLQRtpsZZLeU/Mv0Q1K5P0+x2uvH6Cub39TVVbWNSrraUhDAoFph6vh0A==} @@ -10786,8 +10911,8 @@ packages: set-blocking@2.0.0: resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} - set-cookie-parser@3.0.1: - resolution: {integrity: sha512-n7Z7dXZhJbwuAHhNzkTti6Aw9QDDjZtm3JTpTGATIdNzdQz5GuFs22w90BcvF4INfnrL5xrX3oGsuqO5Dx3A1Q==} + set-cookie-parser@3.1.0: + resolution: {integrity: sha512-kjnC1DXBHcxaOaOXBHBeRtltsDG2nUiUni+jP92M9gYdW12rsmx92UsfpH7o5tDRs7I1ZZPSQJQGv3UaRfCiuw==} set-function-length@1.2.2: resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} @@ -11012,6 +11137,9 @@ packages: std-env@3.10.0: resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} + std-env@4.0.0: + resolution: {integrity: sha512-zUMPtQ/HBY3/50VbpkupYHbRroTRZJPRLvreamgErJVys0ceuzMkD44J/QjqhHjOzK42GQ3QZIeFG1OYfOtKqQ==} + stdin-discarder@0.2.2: resolution: {integrity: sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==} engines: {node: '>=18'} @@ -11023,8 +11151,8 @@ packages: resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} engines: {node: '>=10.0.0'} - streamx@2.23.0: - resolution: {integrity: sha512-kn+e44esVfn2Fa/O0CPFcex27fjIL6MkVae0Mm6q+E6f0hWv578YCERbv+4m02cjxvDsPKLnmxral/rR6lBMAg==} + streamx@2.25.0: + resolution: {integrity: sha512-0nQuG6jf1w+wddNEEXCF4nTg3LtufWINB5eFEN+5TNZW7KWJp6x87+JFL43vaAUPyCfH1wID+mNVyW6OHtFamg==} string-width@4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} @@ -11090,8 +11218,8 @@ packages: strip-literal@3.1.0: resolution: {integrity: sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==} - strtok3@10.3.4: - resolution: {integrity: sha512-KIy5nylvC5le1OdaaoCJ07L+8iQzJHGH6pWDuzS+d07Cu7n1MZ2x26P8ZKIWfbK02+XIL8Mp4RkWeqdUCrDMfg==} + strtok3@10.3.5: + resolution: {integrity: sha512-ki4hZQfh5rX0QDLLkOCj+h+CVNkqmp/CMf8v8kZpkNVK6jGQooMytqzLZYUVYIZcFZ6yDB70EfD8POcFXiF5oA==} engines: {node: '>=18'} style-mod@4.1.3: @@ -11145,8 +11273,8 @@ packages: peerDependencies: svelte: '>= 3.43.1 < 6' - svelte-check@4.4.4: - resolution: {integrity: sha512-F1pGqXc710Oi/wTI4d/x7d6lgPwwfx1U6w3Q35n4xsC2e8C/yN2sM1+mWxjlMcpAfWucjlq4vPi+P4FZ8a14sQ==} + svelte-check@4.4.5: + resolution: {integrity: sha512-1bSwIRCvvmSHrlK52fOlZmVtUZgil43jNL/2H18pRpa+eQjzGt6e3zayxhp1S7GajPFKNM/2PMCG+DZFHlG9fw==} engines: {node: '>= 18.0.0'} hasBin: true peerDependencies: @@ -11218,8 +11346,8 @@ packages: peerDependencies: svelte: ^5.30.2 - svelte@5.53.7: - resolution: {integrity: sha512-uxck1KI7JWtlfP3H6HOWi/94soAl23jsGJkBzN2BAWcQng0+lTrRNhxActFqORgnO9BHVd1hKJhG+ljRuIUWfQ==} + svelte@5.54.1: + resolution: {integrity: sha512-ow8tncN097Ty8U1H+C3bM1xNlsCbnO2UZeN0lWBnv8f3jKho7QTTQ2LWbMXrPQDodLjH91n4kpNnLolyRhVE6A==} engines: {node: '>=18'} svg-parser@2.0.4: @@ -11293,8 +11421,8 @@ packages: engines: {node: '>=14.0.0'} hasBin: true - tailwindcss@4.2.1: - resolution: {integrity: sha512-/tBrSQ36vCleJkAOsy9kbNTgaxvGbyOamC30PRePTQe/o1MFwEKHQk4Cn7BNGaPtjp+PuUrByJehM1hgxfq4sw==} + tailwindcss@4.2.2: + resolution: {integrity: sha512-KWBIxs1Xb6NoLdMVqhbhgwZf2PGBpPEiwOqgI4pFIYbNTfBXiKYyWoTsXgBQ9WFg/OlhnvHaY+AEpW7wSmFo2Q==} tapable@2.3.0: resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} @@ -11303,15 +11431,15 @@ packages: tar-fs@2.1.4: resolution: {integrity: sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==} - tar-fs@3.1.1: - resolution: {integrity: sha512-LZA0oaPOc2fVo82Txf3gw+AkEd38szODlptMYejQUhndHMLQ9M059uXR+AfS7DNo0NpINvSqDsvyaCrBVkptWg==} + tar-fs@3.1.2: + resolution: {integrity: sha512-QGxxTxxyleAdyM3kpFs14ymbYmNFrfY+pHj7Z8FgtbZ7w2//VAgLMac7sT6nRpIHjppXO2AwwEOg0bPFVRcmXw==} tar-stream@2.2.0: resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} engines: {node: '>=6'} - tar-stream@3.1.7: - resolution: {integrity: sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==} + tar-stream@3.1.8: + resolution: {integrity: sha512-U6QpVRyCGHva435KoNWy9PRoi2IFYCgtEhq9nmrPPpbRacPs9IH4aJ3gbrFC8dPcXvdSZ4XXfXT5Fshbp2MtlQ==} tar@6.2.1: resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==} @@ -11351,11 +11479,11 @@ packages: resolution: {integrity: sha512-u9E6A+ZDYdp7a4WnarkXPZOx8Ilz46+kby6p1yZ8zsGTz9gYa6FIS7lj2oezzNKmtdyyJNNmmXDppga5GB7kSw==} engines: {node: '>=18'} - testcontainers@11.12.0: - resolution: {integrity: sha512-VWtH+UQejVYYvb53ohEZRbx2naxyDvwO9lQ6A0VgmVE2Oh8r9EF09I+BfmrXpd9N9ntpzhao9di2yNwibSz5KA==} + testcontainers@11.13.0: + resolution: {integrity: sha512-fzTvgOtd6U/esOzgmDatJh79OSK0tU6vjDOJ3B6ICrrJf0dqCWtFdpOr6f/g/KixMxKDTDbszmZYjSORJXsVCQ==} - text-decoder@1.2.3: - resolution: {integrity: sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==} + text-decoder@1.2.7: + resolution: {integrity: sha512-vlLytXkeP4xvEq2otHeJfSQIRyWxo/oZGEbXrtEEF9Hnmrdly59sUbzZ/QgyWuLYHctCHxFF4tRQZNQ9k60ExQ==} text-encoding@0.6.4: resolution: {integrity: sha512-hJnc6Qg3dWoOMkqP53F0dzRIgtmsAge09kxUIqGrEUS4qr5rWLckGYaQAVr+opBrIMRErGgy6f5aPnyPpyGRfg==} @@ -11412,8 +11540,8 @@ packages: tinyexec@0.3.2: resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} - tinyexec@1.0.2: - resolution: {integrity: sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==} + tinyexec@1.0.4: + resolution: {integrity: sha512-u9r3uZC0bdpGOXtlxUIdwf9pkmvhqJdrVCH9fapQtgy/OeTTMZ1nqH7agtvEfmGui6e1XxjcdrlxvxJvc3sMqw==} engines: {node: '>=18'} tinyglobby@0.2.15: @@ -11431,8 +11559,8 @@ packages: resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==} engines: {node: '>=14.0.0'} - tinyrainbow@3.0.3: - resolution: {integrity: sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==} + tinyrainbow@3.1.0: + resolution: {integrity: sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==} engines: {node: '>=14.0.0'} tinyspy@4.0.4: @@ -11501,8 +11629,8 @@ packages: truncate-utf8-bytes@1.0.2: resolution: {integrity: sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ==} - ts-api-utils@2.4.0: - resolution: {integrity: sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==} + ts-api-utils@2.5.0: + resolution: {integrity: sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==} engines: {node: '>=18.12'} peerDependencies: typescript: '>=4.8.4' @@ -11580,8 +11708,8 @@ packages: typedarray@0.0.6: resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} - typescript-eslint@8.56.1: - resolution: {integrity: sha512-U4lM6pjmBX7J5wk4szltF7I1cGBHXZopnAXCMXb3+fZ3B/0Z3hq3wS/CCUB2NZBNAExK92mCU2tEohWuwVMsDQ==} + typescript-eslint@8.57.1: + resolution: {integrity: sha512-fLvZWf+cAGw3tqMCYzGIU6yR8K+Y9NT2z23RwOjlNFF2HwSB3KhdEFI5lSBv8tNmFkkBShSjsCjzx1vahZfISA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 @@ -11628,8 +11756,8 @@ packages: undici-types@7.18.2: resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} - undici@7.22.0: - resolution: {integrity: sha512-RqslV2Us5BrllB+JeiZnK4peryVTndy9Dnqq62S3yYRRTj0tFQCwEniUy2167skdGOy3vqRzEvl1Dm4sV2ReDg==} + undici@7.24.6: + resolution: {integrity: sha512-Xi4agocCbRzt0yYMZGMA6ApD7gvtUFaxm4ZmeacWI4cZxaF6C+8I8QfofC20NAePiB/IcvZmzkJ7XPa471AEtA==} engines: {node: '>=20.18.1'} unicode-canonical-property-names-ecmascript@2.0.1: @@ -11877,10 +12005,53 @@ packages: yaml: optional: true - vitefu@1.1.1: - resolution: {integrity: sha512-B/Fegf3i8zh0yFbpzZ21amWzHmuNlLlmJT6n7bu5e+pCHUKQIfXSYokrqOBGEMMe9UG2sostKQF9mml/vYaWJQ==} + vite@8.0.1: + resolution: {integrity: sha512-wt+Z2qIhfFt85uiyRt5LPU4oVEJBXj8hZNWKeqFG4gRG/0RaRGJ7njQCwzFVjO+v4+Ipmf5CY7VdmZRAYYBPHw==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true peerDependencies: - vite: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0 + '@types/node': ^20.19.0 || >=22.12.0 + '@vitejs/devtools': ^0.1.0 + esbuild: ^0.27.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 + + vitefu@1.1.2: + resolution: {integrity: sha512-zpKATdUbzbsycPFBN71nS2uzBUQiVnFoOrr2rvqv34S1lcAgMKKkjWleLGeiJlZ8lwCXvtWaRn7R3ZC16SYRuw==} + peerDependencies: + vite: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-beta.0 peerDependenciesMeta: vite: optional: true @@ -11919,20 +12090,21 @@ packages: jsdom: optional: true - vitest@4.0.18: - resolution: {integrity: sha512-hOQuK7h0FGKgBAas7v0mSAsnvrIgAvWmRFjmzpJ7SwFHH3g1k2u37JtYwOwmEKhK6ZO3v9ggDBBm0La1LCK4uQ==} + vitest@4.1.0: + resolution: {integrity: sha512-YbDrMF9jM2Lqc++2530UourxZHmkKLxrs4+mYhEwqWS97WJ7wOYEkcr+QfRgJ3PW9wz3odRijLZjHEaRLTNbqw==} engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} hasBin: true peerDependencies: '@edge-runtime/vm': '*' '@opentelemetry/api': ^1.9.0 '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 - '@vitest/browser-playwright': 4.0.18 - '@vitest/browser-preview': 4.0.18 - '@vitest/browser-webdriverio': 4.0.18 - '@vitest/ui': 4.0.18 + '@vitest/browser-playwright': 4.1.0 + '@vitest/browser-preview': 4.1.0 + '@vitest/browser-webdriverio': 4.1.0 + '@vitest/ui': 4.1.0 happy-dom: '*' jsdom: '*' + vite: ^6.0.0 || ^7.0.0 || ^8.0.0-0 peerDependenciesMeta: '@edge-runtime/vm': optional: true @@ -12174,8 +12346,8 @@ packages: utf-8-validate: optional: true - ws@8.19.0: - resolution: {integrity: sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==} + ws@8.20.0: + resolution: {integrity: sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==} engines: {node: '>=10.0.0'} peerDependencies: bufferutil: ^4.0.1 @@ -12230,12 +12402,12 @@ packages: resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==} engines: {node: '>=18'} - yaml@1.10.2: - resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} + yaml@1.10.3: + resolution: {integrity: sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA==} engines: {node: '>= 6'} - yaml@2.8.2: - resolution: {integrity: sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==} + yaml@2.8.3: + resolution: {integrity: sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==} engines: {node: '>= 14.6'} hasBin: true @@ -12491,7 +12663,7 @@ snapshots: '@antfu/install-pkg@1.1.0': dependencies: package-manager-detector: 1.6.0 - tinyexec: 1.0.2 + tinyexec: 1.0.4 '@asamuzakjp/css-color@3.2.0': dependencies: @@ -12517,7 +12689,7 @@ snapshots: '@babel/helper-compilation-targets': 7.27.2 '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5) '@babel/helpers': 7.28.4 - '@babel/parser': 7.29.0 + '@babel/parser': 7.29.2 '@babel/template': 7.27.2 '@babel/traverse': 7.28.5 '@babel/types': 7.29.0 @@ -12532,7 +12704,7 @@ snapshots: '@babel/generator@7.28.5': dependencies: - '@babel/parser': 7.29.0 + '@babel/parser': 7.29.2 '@babel/types': 7.29.0 '@jridgewell/gen-mapping': 0.3.13 '@jridgewell/trace-mapping': 0.3.31 @@ -12656,7 +12828,7 @@ snapshots: '@babel/template': 7.27.2 '@babel/types': 7.29.0 - '@babel/parser@7.29.0': + '@babel/parser@7.29.2': dependencies: '@babel/types': 7.29.0 @@ -13230,12 +13402,12 @@ snapshots: dependencies: core-js-pure: 3.47.0 - '@babel/runtime@7.28.6': {} + '@babel/runtime@7.29.2': {} '@babel/template@7.27.2': dependencies: '@babel/code-frame': 7.29.0 - '@babel/parser': 7.29.0 + '@babel/parser': 7.29.2 '@babel/types': 7.29.0 '@babel/traverse@7.28.5': @@ -13243,7 +13415,7 @@ snapshots: '@babel/code-frame': 7.29.0 '@babel/generator': 7.28.5 '@babel/helper-globals': 7.28.0 - '@babel/parser': 7.29.0 + '@babel/parser': 7.29.2 '@babel/template': 7.27.2 '@babel/types': 7.29.0 debug: 4.4.3 @@ -13259,7 +13431,7 @@ snapshots: '@bcoe/v8-coverage@1.0.2': {} - '@borewit/text-codec@0.2.1': {} + '@borewit/text-codec@0.2.2': {} '@braintree/sanitize-url@7.1.1': {} @@ -13669,7 +13841,7 @@ snapshots: '@babel/preset-env': 7.28.5(@babel/core@7.28.5) '@babel/preset-react': 7.28.5(@babel/core@7.28.5) '@babel/preset-typescript': 7.28.5(@babel/core@7.28.5) - '@babel/runtime': 7.28.6 + '@babel/runtime': 7.29.2 '@babel/runtime-corejs3': 7.28.4 '@babel/traverse': 7.28.5 '@docusaurus/logger': 3.9.2 @@ -14441,7 +14613,18 @@ snapshots: - uglify-js - webpack-cli - '@emnapi/runtime@1.7.1': + '@emnapi/core@1.9.1': + dependencies: + '@emnapi/wasi-threads': 1.2.0 + tslib: 2.8.1 + optional: true + + '@emnapi/runtime@1.9.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@emnapi/wasi-threads@1.2.0': dependencies: tslib: 2.8.1 optional: true @@ -14452,7 +14635,7 @@ snapshots: '@esbuild/aix-ppc64@0.25.12': optional: true - '@esbuild/aix-ppc64@0.27.3': + '@esbuild/aix-ppc64@0.27.4': optional: true '@esbuild/android-arm64@0.19.12': @@ -14461,7 +14644,7 @@ snapshots: '@esbuild/android-arm64@0.25.12': optional: true - '@esbuild/android-arm64@0.27.3': + '@esbuild/android-arm64@0.27.4': optional: true '@esbuild/android-arm@0.19.12': @@ -14470,7 +14653,7 @@ snapshots: '@esbuild/android-arm@0.25.12': optional: true - '@esbuild/android-arm@0.27.3': + '@esbuild/android-arm@0.27.4': optional: true '@esbuild/android-x64@0.19.12': @@ -14479,7 +14662,7 @@ snapshots: '@esbuild/android-x64@0.25.12': optional: true - '@esbuild/android-x64@0.27.3': + '@esbuild/android-x64@0.27.4': optional: true '@esbuild/darwin-arm64@0.19.12': @@ -14488,7 +14671,7 @@ snapshots: '@esbuild/darwin-arm64@0.25.12': optional: true - '@esbuild/darwin-arm64@0.27.3': + '@esbuild/darwin-arm64@0.27.4': optional: true '@esbuild/darwin-x64@0.19.12': @@ -14497,7 +14680,7 @@ snapshots: '@esbuild/darwin-x64@0.25.12': optional: true - '@esbuild/darwin-x64@0.27.3': + '@esbuild/darwin-x64@0.27.4': optional: true '@esbuild/freebsd-arm64@0.19.12': @@ -14506,7 +14689,7 @@ snapshots: '@esbuild/freebsd-arm64@0.25.12': optional: true - '@esbuild/freebsd-arm64@0.27.3': + '@esbuild/freebsd-arm64@0.27.4': optional: true '@esbuild/freebsd-x64@0.19.12': @@ -14515,7 +14698,7 @@ snapshots: '@esbuild/freebsd-x64@0.25.12': optional: true - '@esbuild/freebsd-x64@0.27.3': + '@esbuild/freebsd-x64@0.27.4': optional: true '@esbuild/linux-arm64@0.19.12': @@ -14524,7 +14707,7 @@ snapshots: '@esbuild/linux-arm64@0.25.12': optional: true - '@esbuild/linux-arm64@0.27.3': + '@esbuild/linux-arm64@0.27.4': optional: true '@esbuild/linux-arm@0.19.12': @@ -14533,7 +14716,7 @@ snapshots: '@esbuild/linux-arm@0.25.12': optional: true - '@esbuild/linux-arm@0.27.3': + '@esbuild/linux-arm@0.27.4': optional: true '@esbuild/linux-ia32@0.19.12': @@ -14542,7 +14725,7 @@ snapshots: '@esbuild/linux-ia32@0.25.12': optional: true - '@esbuild/linux-ia32@0.27.3': + '@esbuild/linux-ia32@0.27.4': optional: true '@esbuild/linux-loong64@0.19.12': @@ -14551,7 +14734,7 @@ snapshots: '@esbuild/linux-loong64@0.25.12': optional: true - '@esbuild/linux-loong64@0.27.3': + '@esbuild/linux-loong64@0.27.4': optional: true '@esbuild/linux-mips64el@0.19.12': @@ -14560,7 +14743,7 @@ snapshots: '@esbuild/linux-mips64el@0.25.12': optional: true - '@esbuild/linux-mips64el@0.27.3': + '@esbuild/linux-mips64el@0.27.4': optional: true '@esbuild/linux-ppc64@0.19.12': @@ -14569,7 +14752,7 @@ snapshots: '@esbuild/linux-ppc64@0.25.12': optional: true - '@esbuild/linux-ppc64@0.27.3': + '@esbuild/linux-ppc64@0.27.4': optional: true '@esbuild/linux-riscv64@0.19.12': @@ -14578,7 +14761,7 @@ snapshots: '@esbuild/linux-riscv64@0.25.12': optional: true - '@esbuild/linux-riscv64@0.27.3': + '@esbuild/linux-riscv64@0.27.4': optional: true '@esbuild/linux-s390x@0.19.12': @@ -14587,7 +14770,7 @@ snapshots: '@esbuild/linux-s390x@0.25.12': optional: true - '@esbuild/linux-s390x@0.27.3': + '@esbuild/linux-s390x@0.27.4': optional: true '@esbuild/linux-x64@0.19.12': @@ -14596,13 +14779,13 @@ snapshots: '@esbuild/linux-x64@0.25.12': optional: true - '@esbuild/linux-x64@0.27.3': + '@esbuild/linux-x64@0.27.4': optional: true '@esbuild/netbsd-arm64@0.25.12': optional: true - '@esbuild/netbsd-arm64@0.27.3': + '@esbuild/netbsd-arm64@0.27.4': optional: true '@esbuild/netbsd-x64@0.19.12': @@ -14611,13 +14794,13 @@ snapshots: '@esbuild/netbsd-x64@0.25.12': optional: true - '@esbuild/netbsd-x64@0.27.3': + '@esbuild/netbsd-x64@0.27.4': optional: true '@esbuild/openbsd-arm64@0.25.12': optional: true - '@esbuild/openbsd-arm64@0.27.3': + '@esbuild/openbsd-arm64@0.27.4': optional: true '@esbuild/openbsd-x64@0.19.12': @@ -14626,13 +14809,13 @@ snapshots: '@esbuild/openbsd-x64@0.25.12': optional: true - '@esbuild/openbsd-x64@0.27.3': + '@esbuild/openbsd-x64@0.27.4': optional: true '@esbuild/openharmony-arm64@0.25.12': optional: true - '@esbuild/openharmony-arm64@0.27.3': + '@esbuild/openharmony-arm64@0.27.4': optional: true '@esbuild/sunos-x64@0.19.12': @@ -14641,7 +14824,7 @@ snapshots: '@esbuild/sunos-x64@0.25.12': optional: true - '@esbuild/sunos-x64@0.27.3': + '@esbuild/sunos-x64@0.27.4': optional: true '@esbuild/win32-arm64@0.19.12': @@ -14650,7 +14833,7 @@ snapshots: '@esbuild/win32-arm64@0.25.12': optional: true - '@esbuild/win32-arm64@0.27.3': + '@esbuild/win32-arm64@0.27.4': optional: true '@esbuild/win32-ia32@0.19.12': @@ -14659,7 +14842,7 @@ snapshots: '@esbuild/win32-ia32@0.25.12': optional: true - '@esbuild/win32-ia32@0.27.3': + '@esbuild/win32-ia32@0.27.4': optional: true '@esbuild/win32-x64@0.19.12': @@ -14668,41 +14851,41 @@ snapshots: '@esbuild/win32-x64@0.25.12': optional: true - '@esbuild/win32-x64@0.27.3': + '@esbuild/win32-x64@0.27.4': optional: true - '@eslint-community/eslint-utils@4.9.1(eslint@10.0.2(jiti@2.6.1))': + '@eslint-community/eslint-utils@4.9.1(eslint@10.1.0(jiti@2.6.1))': dependencies: - eslint: 10.0.2(jiti@2.6.1) + eslint: 10.1.0(jiti@2.6.1) eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.2': {} - '@eslint/config-array@0.23.2': + '@eslint/config-array@0.23.3': dependencies: - '@eslint/object-schema': 3.0.2 + '@eslint/object-schema': 3.0.3 debug: 4.4.3 minimatch: 10.2.4 transitivePeerDependencies: - supports-color - '@eslint/config-helpers@0.5.2': + '@eslint/config-helpers@0.5.3': dependencies: - '@eslint/core': 1.1.0 + '@eslint/core': 1.1.1 - '@eslint/core@1.1.0': + '@eslint/core@1.1.1': dependencies: '@types/json-schema': 7.0.15 - '@eslint/js@10.0.1(eslint@10.0.2(jiti@2.6.1))': + '@eslint/js@10.0.1(eslint@10.1.0(jiti@2.6.1))': optionalDependencies: - eslint: 10.0.2(jiti@2.6.1) + eslint: 10.1.0(jiti@2.6.1) - '@eslint/object-schema@3.0.2': {} + '@eslint/object-schema@3.0.3': {} - '@eslint/plugin-kit@0.6.0': + '@eslint/plugin-kit@0.6.1': dependencies: - '@eslint/core': 1.1.0 + '@eslint/core': 1.1.1 levn: 0.4.1 '@extism/extism@2.0.0-rc13': {} @@ -14729,6 +14912,8 @@ snapshots: '@floating-ui/utils@0.2.10': {} + '@formatjs/bigdecimal@0.2.0': {} + '@formatjs/ecma402-abstract@2.3.6': dependencies: '@formatjs/fast-memoize': 2.2.7 @@ -14736,20 +14921,17 @@ snapshots: decimal.js: 10.6.0 tslib: 2.8.1 - '@formatjs/ecma402-abstract@3.1.1': + '@formatjs/ecma402-abstract@3.2.0': dependencies: - '@formatjs/fast-memoize': 3.1.0 - '@formatjs/intl-localematcher': 0.8.1 - decimal.js: 10.6.0 - tslib: 2.8.1 + '@formatjs/bigdecimal': 0.2.0 + '@formatjs/fast-memoize': 3.1.1 + '@formatjs/intl-localematcher': 0.8.2 '@formatjs/fast-memoize@2.2.7': dependencies: tslib: 2.8.1 - '@formatjs/fast-memoize@3.1.0': - dependencies: - tslib: 2.8.1 + '@formatjs/fast-memoize@3.1.1': {} '@formatjs/icu-messageformat-parser@2.11.4': dependencies: @@ -14757,30 +14939,27 @@ snapshots: '@formatjs/icu-skeleton-parser': 1.8.16 tslib: 2.8.1 - '@formatjs/icu-messageformat-parser@3.5.1': + '@formatjs/icu-messageformat-parser@3.5.3': dependencies: - '@formatjs/ecma402-abstract': 3.1.1 - '@formatjs/icu-skeleton-parser': 2.1.1 - tslib: 2.8.1 + '@formatjs/ecma402-abstract': 3.2.0 + '@formatjs/icu-skeleton-parser': 2.1.3 '@formatjs/icu-skeleton-parser@1.8.16': dependencies: '@formatjs/ecma402-abstract': 2.3.6 tslib: 2.8.1 - '@formatjs/icu-skeleton-parser@2.1.1': + '@formatjs/icu-skeleton-parser@2.1.3': dependencies: - '@formatjs/ecma402-abstract': 3.1.1 - tslib: 2.8.1 + '@formatjs/ecma402-abstract': 3.2.0 '@formatjs/intl-localematcher@0.6.2': dependencies: tslib: 2.8.1 - '@formatjs/intl-localematcher@0.8.1': + '@formatjs/intl-localematcher@0.8.2': dependencies: - '@formatjs/fast-memoize': 3.1.0 - tslib: 2.8.1 + '@formatjs/fast-memoize': 3.1.1 '@fortawesome/fontawesome-common-types@7.1.0': {} @@ -14792,10 +14971,10 @@ snapshots: dependencies: '@fortawesome/fontawesome-common-types': 7.1.0 - '@golevelup/nestjs-discovery@5.0.0(@nestjs/common@11.1.16(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.16)': + '@golevelup/nestjs-discovery@5.0.0(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17)': dependencies: - '@nestjs/common': 11.1.16(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/core': 11.1.16(@nestjs/common@11.1.16(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.16)(@nestjs/websockets@11.1.16)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/common': 11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(@nestjs/websockets@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2) lodash: 4.17.23 '@grpc/grpc-js@1.14.3': @@ -14926,7 +15105,7 @@ snapshots: '@img/sharp-wasm32@0.34.5': dependencies: - '@emnapi/runtime': 1.7.1 + '@emnapi/runtime': 1.9.1 optional: true '@img/sharp-win32-arm64@0.34.5': @@ -14943,31 +15122,31 @@ snapshots: '@immich/sql-tools@0.3.2': dependencies: commander: 14.0.3 - kysely: 0.28.11 - kysely-postgres-js: 3.0.0(kysely@0.28.11)(postgres@3.4.8) + kysely: 0.28.14 + kysely-postgres-js: 3.0.0(kysely@0.28.14)(postgres@3.4.8) pg-connection-string: 2.12.0 postgres: 3.4.8 - '@immich/svelte-markdown-preprocess@0.2.1(svelte@5.53.7)': + '@immich/svelte-markdown-preprocess@0.2.1(svelte@5.54.1)': dependencies: front-matter: 4.0.2 marked: 17.0.3 node-emoji: 2.2.0 - svelte: 5.53.7 + svelte: 5.54.1 - '@immich/ui@0.65.3(@sveltejs/kit@2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.7)(vite@7.3.1(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(svelte@5.53.7)(typescript@5.9.3)(vite@7.3.1(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(svelte@5.53.7)': + '@immich/ui@0.69.0(@sveltejs/kit@2.55.0(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.54.1)(vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)))(svelte@5.54.1)(typescript@5.9.3)(vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)))(svelte@5.54.1)': dependencies: - '@immich/svelte-markdown-preprocess': 0.2.1(svelte@5.53.7) + '@immich/svelte-markdown-preprocess': 0.2.1(svelte@5.54.1) '@internationalized/date': 3.10.0 '@mdi/js': 7.4.47 - bits-ui: 2.16.0(@internationalized/date@3.10.0)(@sveltejs/kit@2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.7)(vite@7.3.1(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(svelte@5.53.7)(typescript@5.9.3)(vite@7.3.1(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(svelte@5.53.7) + bits-ui: 2.16.0(@internationalized/date@3.10.0)(@sveltejs/kit@2.55.0(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.54.1)(vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)))(svelte@5.54.1)(typescript@5.9.3)(vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)))(svelte@5.54.1) luxon: 3.7.2 simple-icons: 16.9.0 - svelte: 5.53.7 + svelte: 5.54.1 svelte-highlight: 7.9.0 tailwind-merge: 3.5.0 - tailwind-variants: 3.2.2(tailwind-merge@3.5.0)(tailwindcss@4.2.1) - tailwindcss: 4.2.1 + tailwind-variants: 3.2.2(tailwind-merge@3.5.0)(tailwindcss@4.2.2) + tailwindcss: 4.2.2 transitivePeerDependencies: - '@sveltejs/kit' @@ -15223,21 +15402,21 @@ snapshots: dependencies: vary: 1.1.2 - '@koa/router@15.3.0(koa@3.1.1)': + '@koa/router@15.4.0(koa@3.1.2)': dependencies: debug: 4.4.3 http-errors: 2.0.1 - koa: 3.1.1 + koa: 3.1.2 koa-compose: 4.1.0 path-to-regexp: 8.3.0 transitivePeerDependencies: - supports-color - '@koddsson/eslint-plugin-tscompat@0.2.0(eslint@10.0.2(jiti@2.6.1))(typescript@5.9.3)': + '@koddsson/eslint-plugin-tscompat@0.2.0(eslint@10.1.0(jiti@2.6.1))(typescript@5.9.3)': dependencies: '@mdn/browser-compat-data': 6.1.5 - '@typescript-eslint/type-utils': 8.56.1(eslint@10.0.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/utils': 8.56.1(eslint@10.0.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/type-utils': 8.57.1(eslint@10.1.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/utils': 8.57.1(eslint@10.1.0(jiti@2.6.1))(typescript@5.9.3) browserslist: 4.28.1 transitivePeerDependencies: - eslint @@ -15270,11 +15449,6 @@ snapshots: '@lukeed/csprng@1.1.0': {} - '@mapbox/geojson-rewind@0.5.2': - dependencies: - get-stream: 6.0.1 - minimist: 1.2.8 - '@mapbox/jsonlint-lines-primitives@2.0.2': {} '@mapbox/mapbox-gl-rtl-text@0.3.0': {} @@ -15326,7 +15500,11 @@ snapshots: '@maplibre/geojson-vt@5.0.4': {} - '@maplibre/maplibre-gl-style-spec@24.6.0': + '@maplibre/geojson-vt@6.0.4': + dependencies: + kdbush: 4.0.2 + + '@maplibre/maplibre-gl-style-spec@24.7.0': dependencies: '@mapbox/jsonlint-lines-primitives': 2.0.2 '@mapbox/unitbezier': 0.0.1 @@ -15336,7 +15514,7 @@ snapshots: rw: 1.3.3 tinyqueue: 3.0.0 - '@maplibre/mlt@1.1.6': + '@maplibre/mlt@1.1.8': dependencies: '@mapbox/point-geometry': 1.1.0 @@ -15424,21 +15602,28 @@ snapshots: '@namnode/store@0.1.0': {} - '@nestjs/bull-shared@11.0.4(@nestjs/common@11.1.16(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.16)': + '@napi-rs/wasm-runtime@1.1.1': dependencies: - '@nestjs/common': 11.1.16(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/core': 11.1.16(@nestjs/common@11.1.16(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.16)(@nestjs/websockets@11.1.16)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@emnapi/core': 1.9.1 + '@emnapi/runtime': 1.9.1 + '@tybys/wasm-util': 0.10.1 + optional: true + + '@nestjs/bull-shared@11.0.4(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17)': + dependencies: + '@nestjs/common': 11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(@nestjs/websockets@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2) tslib: 2.8.1 - '@nestjs/bullmq@11.0.4(@nestjs/common@11.1.16(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.16)(bullmq@5.70.4)': + '@nestjs/bullmq@11.0.4(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17)(bullmq@5.71.0)': dependencies: - '@nestjs/bull-shared': 11.0.4(@nestjs/common@11.1.16(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.16) - '@nestjs/common': 11.1.16(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/core': 11.1.16(@nestjs/common@11.1.16(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.16)(@nestjs/websockets@11.1.16)(reflect-metadata@0.2.2)(rxjs@7.8.2) - bullmq: 5.70.4 + '@nestjs/bull-shared': 11.0.4(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17) + '@nestjs/common': 11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(@nestjs/websockets@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2) + bullmq: 5.71.0 tslib: 2.8.1 - '@nestjs/cli@11.0.16(@swc/core@1.15.18(@swc/helpers@0.5.17))(@types/node@24.12.0)': + '@nestjs/cli@11.0.16(@swc/core@1.15.18(@swc/helpers@0.5.17))(@types/node@24.12.0)(esbuild@0.27.4)': dependencies: '@angular-devkit/core': 19.2.19(chokidar@4.0.3) '@angular-devkit/schematics': 19.2.19(chokidar@4.0.3) @@ -15449,14 +15634,14 @@ snapshots: chokidar: 4.0.3 cli-table3: 0.6.5 commander: 4.1.1 - fork-ts-checker-webpack-plugin: 9.1.0(typescript@5.9.3)(webpack@5.104.1(@swc/core@1.15.18(@swc/helpers@0.5.17))) + fork-ts-checker-webpack-plugin: 9.1.0(typescript@5.9.3)(webpack@5.104.1(@swc/core@1.15.18(@swc/helpers@0.5.17))(esbuild@0.27.4)) glob: 13.0.0 node-emoji: 1.11.0 ora: 5.4.1 tsconfig-paths: 4.2.0 tsconfig-paths-webpack-plugin: 4.2.0 typescript: 5.9.3 - webpack: 5.104.1(@swc/core@1.15.18(@swc/helpers@0.5.17)) + webpack: 5.104.1(@swc/core@1.15.18(@swc/helpers@0.5.17))(esbuild@0.27.4) webpack-node-externals: 3.0.0 optionalDependencies: '@swc/core': 1.15.18(@swc/helpers@0.5.17) @@ -15466,9 +15651,9 @@ snapshots: - uglify-js - webpack-cli - '@nestjs/common@11.1.16(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2)': + '@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2)': dependencies: - file-type: 21.3.0 + file-type: 21.3.2 iterare: 1.2.1 load-esm: 1.0.3 reflect-metadata: 0.2.2 @@ -15481,9 +15666,9 @@ snapshots: transitivePeerDependencies: - supports-color - '@nestjs/core@11.1.16(@nestjs/common@11.1.16(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.16)(@nestjs/websockets@11.1.16)(reflect-metadata@0.2.2)(rxjs@7.8.2)': + '@nestjs/core@11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(@nestjs/websockets@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2)': dependencies: - '@nestjs/common': 11.1.16(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/common': 11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) '@nuxt/opencollective': 0.4.1 fast-safe-stringify: 2.1.1 iterare: 1.2.1 @@ -15493,21 +15678,21 @@ snapshots: tslib: 2.8.1 uid: 2.0.2 optionalDependencies: - '@nestjs/platform-express': 11.1.16(@nestjs/common@11.1.16(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.16) - '@nestjs/websockets': 11.1.16(@nestjs/common@11.1.16(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.16)(@nestjs/platform-socket.io@11.1.16)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/platform-express': 11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17) + '@nestjs/websockets': 11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17)(@nestjs/platform-socket.io@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/mapped-types@2.1.0(@nestjs/common@11.1.16(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)': + '@nestjs/mapped-types@2.1.0(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)': dependencies: - '@nestjs/common': 11.1.16(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/common': 11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) reflect-metadata: 0.2.2 optionalDependencies: class-transformer: 0.5.1 class-validator: 0.15.1 - '@nestjs/platform-express@11.1.16(@nestjs/common@11.1.16(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.16)': + '@nestjs/platform-express@11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17)': dependencies: - '@nestjs/common': 11.1.16(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/core': 11.1.16(@nestjs/common@11.1.16(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.16)(@nestjs/websockets@11.1.16)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/common': 11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(@nestjs/websockets@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2) cors: 2.8.6 express: 5.2.1 multer: 2.1.1 @@ -15516,10 +15701,10 @@ snapshots: transitivePeerDependencies: - supports-color - '@nestjs/platform-socket.io@11.1.16(@nestjs/common@11.1.16(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/websockets@11.1.16)(rxjs@7.8.2)': + '@nestjs/platform-socket.io@11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/websockets@11.1.17)(rxjs@7.8.2)': dependencies: - '@nestjs/common': 11.1.16(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/websockets': 11.1.16(@nestjs/common@11.1.16(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.16)(@nestjs/platform-socket.io@11.1.16)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/common': 11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/websockets': 11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17)(@nestjs/platform-socket.io@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2) rxjs: 7.8.2 socket.io: 4.8.3 tslib: 2.8.1 @@ -15528,10 +15713,10 @@ snapshots: - supports-color - utf-8-validate - '@nestjs/schedule@6.1.1(@nestjs/common@11.1.16(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.16)': + '@nestjs/schedule@6.1.1(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17)': dependencies: - '@nestjs/common': 11.1.16(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/core': 11.1.16(@nestjs/common@11.1.16(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.16)(@nestjs/websockets@11.1.16)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/common': 11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(@nestjs/websockets@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2) cron: 4.4.0 '@nestjs/schematics@11.0.9(chokidar@4.0.3)(typescript@5.9.3)': @@ -15545,12 +15730,12 @@ snapshots: transitivePeerDependencies: - chokidar - '@nestjs/swagger@11.2.6(@nestjs/common@11.1.16(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.16)(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)': + '@nestjs/swagger@11.2.6(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17)(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)': dependencies: '@microsoft/tsdoc': 0.16.0 - '@nestjs/common': 11.1.16(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/core': 11.1.16(@nestjs/common@11.1.16(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.16)(@nestjs/websockets@11.1.16)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/mapped-types': 2.1.0(@nestjs/common@11.1.16(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2) + '@nestjs/common': 11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(@nestjs/websockets@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/mapped-types': 2.1.0(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2) js-yaml: 4.1.1 lodash: 4.17.23 path-to-regexp: 8.3.0 @@ -15560,25 +15745,25 @@ snapshots: class-transformer: 0.5.1 class-validator: 0.15.1 - '@nestjs/testing@11.1.16(@nestjs/common@11.1.16(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.16)(@nestjs/platform-express@11.1.16)': + '@nestjs/testing@11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17)(@nestjs/platform-express@11.1.17)': dependencies: - '@nestjs/common': 11.1.16(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/core': 11.1.16(@nestjs/common@11.1.16(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.16)(@nestjs/websockets@11.1.16)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/common': 11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(@nestjs/websockets@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2) tslib: 2.8.1 optionalDependencies: - '@nestjs/platform-express': 11.1.16(@nestjs/common@11.1.16(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.16) + '@nestjs/platform-express': 11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17) - '@nestjs/websockets@11.1.16(@nestjs/common@11.1.16(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.16)(@nestjs/platform-socket.io@11.1.16)(reflect-metadata@0.2.2)(rxjs@7.8.2)': + '@nestjs/websockets@11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17)(@nestjs/platform-socket.io@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2)': dependencies: - '@nestjs/common': 11.1.16(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/core': 11.1.16(@nestjs/common@11.1.16(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.16)(@nestjs/websockets@11.1.16)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/common': 11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(@nestjs/websockets@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2) iterare: 1.2.1 object-hash: 3.0.0 reflect-metadata: 0.2.2 rxjs: 7.8.2 tslib: 2.8.1 optionalDependencies: - '@nestjs/platform-socket.io': 11.1.16(@nestjs/common@11.1.16(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/websockets@11.1.16)(rxjs@7.8.2) + '@nestjs/platform-socket.io': 11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/websockets@11.1.17)(rxjs@7.8.2) '@noble/hashes@1.8.0': {} @@ -15624,7 +15809,7 @@ snapshots: dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/core': 2.6.0(@opentelemetry/api@1.9.0) - yaml: 2.8.2 + yaml: 2.8.3 '@opentelemetry/context-async-hooks@2.6.0(@opentelemetry/api@1.9.0)': dependencies: @@ -15902,6 +16087,8 @@ snapshots: '@opentelemetry/api': 1.9.0 '@opentelemetry/core': 2.6.0(@opentelemetry/api@1.9.0) + '@oxc-project/types@0.120.0': {} + '@paralleldrive/cuid2@2.3.1': dependencies: '@noble/hashes': 1.8.0 @@ -16161,11 +16348,60 @@ snapshots: '@codemirror/state': 6.5.3 '@codemirror/view': 6.39.8 + '@rolldown/binding-android-arm64@1.0.0-rc.10': + optional: true + + '@rolldown/binding-darwin-arm64@1.0.0-rc.10': + optional: true + + '@rolldown/binding-darwin-x64@1.0.0-rc.10': + optional: true + + '@rolldown/binding-freebsd-x64@1.0.0-rc.10': + optional: true + + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.10': + optional: true + + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.10': + optional: true + + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.10': + optional: true + + '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.10': + optional: true + + '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.10': + optional: true + + '@rolldown/binding-linux-x64-gnu@1.0.0-rc.10': + optional: true + + '@rolldown/binding-linux-x64-musl@1.0.0-rc.10': + optional: true + + '@rolldown/binding-openharmony-arm64@1.0.0-rc.10': + optional: true + + '@rolldown/binding-wasm32-wasi@1.0.0-rc.10': + dependencies: + '@napi-rs/wasm-runtime': 1.1.1 + optional: true + + '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.10': + optional: true + + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.10': + optional: true + + '@rolldown/pluginutils@1.0.0-rc.10': {} + '@rollup/pluginutils@5.3.0(rollup@4.55.1)': dependencies: '@types/estree': 1.0.8 estree-walker: 2.0.2 - picomatch: 4.0.3 + picomatch: 4.0.4 optionalDependencies: rollup: 4.55.1 @@ -16267,7 +16503,7 @@ snapshots: '@slorber/react-helmet-async@1.3.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@babel/runtime': 7.28.6 + '@babel/runtime': 7.29.2 invariant: 2.2.4 prop-types: 15.8.1 react: 18.3.1 @@ -16300,65 +16536,53 @@ snapshots: dependencies: acorn: 8.16.0 - '@sveltejs/adapter-static@3.0.10(@sveltejs/kit@2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.7)(vite@7.3.1(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(svelte@5.53.7)(typescript@5.9.3)(vite@7.3.1(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))': + '@sveltejs/adapter-static@3.0.10(@sveltejs/kit@2.55.0(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.54.1)(vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)))(svelte@5.54.1)(typescript@5.9.3)(vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)))': dependencies: - '@sveltejs/kit': 2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.7)(vite@7.3.1(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(svelte@5.53.7)(typescript@5.9.3)(vite@7.3.1(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + '@sveltejs/kit': 2.55.0(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.54.1)(vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)))(svelte@5.54.1)(typescript@5.9.3)(vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) - '@sveltejs/enhanced-img@0.10.3(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.7)(vite@7.3.1(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(rollup@4.55.1)(svelte@5.53.7)(vite@7.3.1(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))': + '@sveltejs/enhanced-img@0.10.4(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.54.1)(vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)))(rollup@4.55.1)(svelte@5.54.1)(vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))': dependencies: - '@sveltejs/vite-plugin-svelte': 6.2.4(svelte@5.53.7)(vite@7.3.1(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + '@sveltejs/vite-plugin-svelte': 7.0.0(svelte@5.54.1)(vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) magic-string: 0.30.21 sharp: 0.34.5 - svelte: 5.53.7 - svelte-parse-markup: 0.1.5(svelte@5.53.7) - vite: 7.3.1(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + svelte: 5.54.1 + svelte-parse-markup: 0.1.5(svelte@5.54.1) + vite: 8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3) vite-imagetools: 9.0.3(rollup@4.55.1) zimmerframe: 1.1.4 transitivePeerDependencies: - rollup - supports-color - '@sveltejs/kit@2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.7)(vite@7.3.1(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(svelte@5.53.7)(typescript@5.9.3)(vite@7.3.1(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))': + '@sveltejs/kit@2.55.0(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.54.1)(vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)))(svelte@5.54.1)(typescript@5.9.3)(vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))': dependencies: '@standard-schema/spec': 1.1.0 '@sveltejs/acorn-typescript': 1.0.9(acorn@8.16.0) - '@sveltejs/vite-plugin-svelte': 6.2.4(svelte@5.53.7)(vite@7.3.1(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + '@sveltejs/vite-plugin-svelte': 7.0.0(svelte@5.54.1)(vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) '@types/cookie': 0.6.0 acorn: 8.16.0 cookie: 0.6.0 - devalue: 5.6.3 + devalue: 5.6.4 esm-env: 1.2.2 kleur: 4.1.5 magic-string: 0.30.21 mrmime: 2.0.1 - set-cookie-parser: 3.0.1 + set-cookie-parser: 3.1.0 sirv: 3.0.2 - svelte: 5.53.7 - vite: 7.3.1(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + svelte: 5.54.1 + vite: 8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3) optionalDependencies: '@opentelemetry/api': 1.9.0 typescript: 5.9.3 - '@sveltejs/vite-plugin-svelte-inspector@5.0.1(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.7)(vite@7.3.1(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(svelte@5.53.7)(vite@7.3.1(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))': + '@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.54.1)(vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))': dependencies: - '@sveltejs/vite-plugin-svelte': 6.2.4(svelte@5.53.7)(vite@7.3.1(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) - debug: 4.4.3 - svelte: 5.53.7 - vite: 7.3.1(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) - transitivePeerDependencies: - - supports-color - - '@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.7)(vite@7.3.1(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))': - dependencies: - '@sveltejs/vite-plugin-svelte-inspector': 5.0.1(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.7)(vite@7.3.1(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(svelte@5.53.7)(vite@7.3.1(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) deepmerge: 4.3.1 magic-string: 0.30.21 obug: 2.1.1 - svelte: 5.53.7 - vite: 7.3.1(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) - vitefu: 1.1.1(vite@7.3.1(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) - transitivePeerDependencies: - - supports-color + svelte: 5.54.1 + vite: 8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3) + vitefu: 1.1.2(vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) '@svgr/babel-plugin-add-jsx-attribute@8.0.0(@babel/core@7.28.5)': dependencies: @@ -16514,78 +16738,78 @@ snapshots: dependencies: defer-to-connect: 2.0.1 - '@tailwindcss/node@4.2.1': + '@tailwindcss/node@4.2.2': dependencies: '@jridgewell/remapping': 2.3.5 enhanced-resolve: 5.20.0 jiti: 2.6.1 - lightningcss: 1.31.1 + lightningcss: 1.32.0 magic-string: 0.30.21 source-map-js: 1.2.1 - tailwindcss: 4.2.1 + tailwindcss: 4.2.2 - '@tailwindcss/oxide-android-arm64@4.2.1': + '@tailwindcss/oxide-android-arm64@4.2.2': optional: true - '@tailwindcss/oxide-darwin-arm64@4.2.1': + '@tailwindcss/oxide-darwin-arm64@4.2.2': optional: true - '@tailwindcss/oxide-darwin-x64@4.2.1': + '@tailwindcss/oxide-darwin-x64@4.2.2': optional: true - '@tailwindcss/oxide-freebsd-x64@4.2.1': + '@tailwindcss/oxide-freebsd-x64@4.2.2': optional: true - '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.1': + '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.2': optional: true - '@tailwindcss/oxide-linux-arm64-gnu@4.2.1': + '@tailwindcss/oxide-linux-arm64-gnu@4.2.2': optional: true - '@tailwindcss/oxide-linux-arm64-musl@4.2.1': + '@tailwindcss/oxide-linux-arm64-musl@4.2.2': optional: true - '@tailwindcss/oxide-linux-x64-gnu@4.2.1': + '@tailwindcss/oxide-linux-x64-gnu@4.2.2': optional: true - '@tailwindcss/oxide-linux-x64-musl@4.2.1': + '@tailwindcss/oxide-linux-x64-musl@4.2.2': optional: true - '@tailwindcss/oxide-wasm32-wasi@4.2.1': + '@tailwindcss/oxide-wasm32-wasi@4.2.2': optional: true - '@tailwindcss/oxide-win32-arm64-msvc@4.2.1': + '@tailwindcss/oxide-win32-arm64-msvc@4.2.2': optional: true - '@tailwindcss/oxide-win32-x64-msvc@4.2.1': + '@tailwindcss/oxide-win32-x64-msvc@4.2.2': optional: true - '@tailwindcss/oxide@4.2.1': + '@tailwindcss/oxide@4.2.2': optionalDependencies: - '@tailwindcss/oxide-android-arm64': 4.2.1 - '@tailwindcss/oxide-darwin-arm64': 4.2.1 - '@tailwindcss/oxide-darwin-x64': 4.2.1 - '@tailwindcss/oxide-freebsd-x64': 4.2.1 - '@tailwindcss/oxide-linux-arm-gnueabihf': 4.2.1 - '@tailwindcss/oxide-linux-arm64-gnu': 4.2.1 - '@tailwindcss/oxide-linux-arm64-musl': 4.2.1 - '@tailwindcss/oxide-linux-x64-gnu': 4.2.1 - '@tailwindcss/oxide-linux-x64-musl': 4.2.1 - '@tailwindcss/oxide-wasm32-wasi': 4.2.1 - '@tailwindcss/oxide-win32-arm64-msvc': 4.2.1 - '@tailwindcss/oxide-win32-x64-msvc': 4.2.1 + '@tailwindcss/oxide-android-arm64': 4.2.2 + '@tailwindcss/oxide-darwin-arm64': 4.2.2 + '@tailwindcss/oxide-darwin-x64': 4.2.2 + '@tailwindcss/oxide-freebsd-x64': 4.2.2 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.2.2 + '@tailwindcss/oxide-linux-arm64-gnu': 4.2.2 + '@tailwindcss/oxide-linux-arm64-musl': 4.2.2 + '@tailwindcss/oxide-linux-x64-gnu': 4.2.2 + '@tailwindcss/oxide-linux-x64-musl': 4.2.2 + '@tailwindcss/oxide-wasm32-wasi': 4.2.2 + '@tailwindcss/oxide-win32-arm64-msvc': 4.2.2 + '@tailwindcss/oxide-win32-x64-msvc': 4.2.2 - '@tailwindcss/vite@4.2.1(vite@7.3.1(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))': + '@tailwindcss/vite@4.2.2(vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))': dependencies: - '@tailwindcss/node': 4.2.1 - '@tailwindcss/oxide': 4.2.1 - tailwindcss: 4.2.1 - vite: 7.3.1(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + '@tailwindcss/node': 4.2.2 + '@tailwindcss/oxide': 4.2.2 + tailwindcss: 4.2.2 + vite: 8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3) '@testing-library/dom@10.4.1': dependencies: '@babel/code-frame': 7.29.0 - '@babel/runtime': 7.28.6 + '@babel/runtime': 7.29.2 '@types/aria-query': 5.0.4 aria-query: 5.3.0 dom-accessibility-api: 0.5.16 @@ -16602,18 +16826,18 @@ snapshots: picocolors: 1.1.1 redent: 3.0.0 - '@testing-library/svelte-core@1.0.0(svelte@5.53.7)': + '@testing-library/svelte-core@1.0.0(svelte@5.54.1)': dependencies: - svelte: 5.53.7 + svelte: 5.54.1 - '@testing-library/svelte@5.3.1(svelte@5.53.7)(vite@7.3.1(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vitest@4.0.18(@opentelemetry/api@1.9.0)(@types/node@25.4.0)(happy-dom@20.8.3)(jiti@2.6.1)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))': + '@testing-library/svelte@5.3.1(svelte@5.54.1)(vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))(vitest@4.1.0(@opentelemetry/api@1.9.0)(@types/node@25.5.0)(happy-dom@20.8.4)(jsdom@26.1.0(canvas@2.11.2))(vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)))': dependencies: '@testing-library/dom': 10.4.1 - '@testing-library/svelte-core': 1.0.0(svelte@5.53.7) - svelte: 5.53.7 + '@testing-library/svelte-core': 1.0.0(svelte@5.54.1) + svelte: 5.54.1 optionalDependencies: - vite: 7.3.1(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) - vitest: 4.0.18(@opentelemetry/api@1.9.0)(@types/node@25.4.0)(happy-dom@20.8.3)(jiti@2.6.1)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + vite: 8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3) + vitest: 4.1.0(@opentelemetry/api@1.9.0)(@types/node@25.5.0)(happy-dom@20.8.4)(jsdom@26.1.0(canvas@2.11.2))(vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) '@testing-library/user-event@14.6.1(@testing-library/dom@10.4.1)': dependencies: @@ -16630,25 +16854,30 @@ snapshots: '@trysound/sax@0.2.0': {} - '@turf/boolean-point-in-polygon@7.3.2': + '@turf/boolean-point-in-polygon@7.3.4': dependencies: - '@turf/helpers': 7.3.2 - '@turf/invariant': 7.3.2 + '@turf/helpers': 7.3.4 + '@turf/invariant': 7.3.4 '@types/geojson': 7946.0.16 point-in-polygon-hao: 1.2.4 tslib: 2.8.1 - '@turf/helpers@7.3.2': + '@turf/helpers@7.3.4': dependencies: '@types/geojson': 7946.0.16 tslib: 2.8.1 - '@turf/invariant@7.3.2': + '@turf/invariant@7.3.4': dependencies: - '@turf/helpers': 7.3.2 + '@turf/helpers': 7.3.4 '@types/geojson': 7946.0.16 tslib: 2.8.1 + '@tybys/wasm-util@0.10.1': + dependencies: + tslib: 2.8.1 + optional: true + '@types/accepts@1.3.7': dependencies: '@types/node': 24.12.0 @@ -17043,7 +17272,7 @@ snapshots: dependencies: undici-types: 7.16.0 - '@types/node@25.4.0': + '@types/node@25.5.0': dependencies: undici-types: 7.18.2 optional: true @@ -17062,7 +17291,7 @@ snapshots: '@types/pg-pool@2.0.7': dependencies: - '@types/pg': 8.18.0 + '@types/pg': 8.20.0 '@types/pg@8.15.6': dependencies: @@ -17070,7 +17299,7 @@ snapshots: pg-protocol: 1.13.0 pg-types: 2.2.0 - '@types/pg@8.18.0': + '@types/pg@8.20.0': dependencies: '@types/node': 24.12.0 pg-protocol: 1.13.0 @@ -17212,102 +17441,102 @@ snapshots: dependencies: '@types/yargs-parser': 21.0.3 - '@typescript-eslint/eslint-plugin@8.56.1(@typescript-eslint/parser@8.56.1(eslint@10.0.2(jiti@2.6.1))(typescript@5.9.3))(eslint@10.0.2(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/eslint-plugin@8.57.1(@typescript-eslint/parser@8.57.1(eslint@10.1.0(jiti@2.6.1))(typescript@5.9.3))(eslint@10.1.0(jiti@2.6.1))(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.56.1(eslint@10.0.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.56.1 - '@typescript-eslint/type-utils': 8.56.1(eslint@10.0.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/utils': 8.56.1(eslint@10.0.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.56.1 - eslint: 10.0.2(jiti@2.6.1) + '@typescript-eslint/parser': 8.57.1(eslint@10.1.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.57.1 + '@typescript-eslint/type-utils': 8.57.1(eslint@10.1.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/utils': 8.57.1(eslint@10.1.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.57.1 + eslint: 10.1.0(jiti@2.6.1) ignore: 7.0.5 natural-compare: 1.4.0 - ts-api-utils: 2.4.0(typescript@5.9.3) + ts-api-utils: 2.5.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.56.1(eslint@10.0.2(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/parser@8.57.1(eslint@10.1.0(jiti@2.6.1))(typescript@5.9.3)': dependencies: - '@typescript-eslint/scope-manager': 8.56.1 - '@typescript-eslint/types': 8.56.1 - '@typescript-eslint/typescript-estree': 8.56.1(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.56.1 + '@typescript-eslint/scope-manager': 8.57.1 + '@typescript-eslint/types': 8.57.1 + '@typescript-eslint/typescript-estree': 8.57.1(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.57.1 debug: 4.4.3 - eslint: 10.0.2(jiti@2.6.1) + eslint: 10.1.0(jiti@2.6.1) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.56.1(typescript@5.9.3)': + '@typescript-eslint/project-service@8.57.1(typescript@5.9.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.56.1(typescript@5.9.3) - '@typescript-eslint/types': 8.56.1 + '@typescript-eslint/tsconfig-utils': 8.57.1(typescript@5.9.3) + '@typescript-eslint/types': 8.57.1 debug: 4.4.3 typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@8.56.1': + '@typescript-eslint/scope-manager@8.57.1': dependencies: - '@typescript-eslint/types': 8.56.1 - '@typescript-eslint/visitor-keys': 8.56.1 + '@typescript-eslint/types': 8.57.1 + '@typescript-eslint/visitor-keys': 8.57.1 - '@typescript-eslint/tsconfig-utils@8.56.1(typescript@5.9.3)': + '@typescript-eslint/tsconfig-utils@8.57.1(typescript@5.9.3)': dependencies: typescript: 5.9.3 - '@typescript-eslint/type-utils@8.56.1(eslint@10.0.2(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/type-utils@8.57.1(eslint@10.1.0(jiti@2.6.1))(typescript@5.9.3)': dependencies: - '@typescript-eslint/types': 8.56.1 - '@typescript-eslint/typescript-estree': 8.56.1(typescript@5.9.3) - '@typescript-eslint/utils': 8.56.1(eslint@10.0.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/types': 8.57.1 + '@typescript-eslint/typescript-estree': 8.57.1(typescript@5.9.3) + '@typescript-eslint/utils': 8.57.1(eslint@10.1.0(jiti@2.6.1))(typescript@5.9.3) debug: 4.4.3 - eslint: 10.0.2(jiti@2.6.1) - ts-api-utils: 2.4.0(typescript@5.9.3) + eslint: 10.1.0(jiti@2.6.1) + ts-api-utils: 2.5.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/types@8.56.1': {} + '@typescript-eslint/types@8.57.1': {} - '@typescript-eslint/typescript-estree@8.56.1(typescript@5.9.3)': + '@typescript-eslint/typescript-estree@8.57.1(typescript@5.9.3)': dependencies: - '@typescript-eslint/project-service': 8.56.1(typescript@5.9.3) - '@typescript-eslint/tsconfig-utils': 8.56.1(typescript@5.9.3) - '@typescript-eslint/types': 8.56.1 - '@typescript-eslint/visitor-keys': 8.56.1 + '@typescript-eslint/project-service': 8.57.1(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.57.1(typescript@5.9.3) + '@typescript-eslint/types': 8.57.1 + '@typescript-eslint/visitor-keys': 8.57.1 debug: 4.4.3 minimatch: 10.2.4 semver: 7.7.4 tinyglobby: 0.2.15 - ts-api-utils: 2.4.0(typescript@5.9.3) + ts-api-utils: 2.5.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.56.1(eslint@10.0.2(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/utils@8.57.1(eslint@10.1.0(jiti@2.6.1))(typescript@5.9.3)': dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.0.2(jiti@2.6.1)) - '@typescript-eslint/scope-manager': 8.56.1 - '@typescript-eslint/types': 8.56.1 - '@typescript-eslint/typescript-estree': 8.56.1(typescript@5.9.3) - eslint: 10.0.2(jiti@2.6.1) + '@eslint-community/eslint-utils': 4.9.1(eslint@10.1.0(jiti@2.6.1)) + '@typescript-eslint/scope-manager': 8.57.1 + '@typescript-eslint/types': 8.57.1 + '@typescript-eslint/typescript-estree': 8.57.1(typescript@5.9.3) + eslint: 10.1.0(jiti@2.6.1) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@8.56.1': + '@typescript-eslint/visitor-keys@8.57.1': dependencies: - '@typescript-eslint/types': 8.56.1 + '@typescript-eslint/types': 8.57.1 eslint-visitor-keys: 5.0.1 '@ungap/structured-clone@1.3.0': {} '@vercel/oidc@3.0.5': {} - '@vitest/coverage-v8@3.2.4(vitest@3.2.4(@types/debug@4.1.12)(@types/node@24.12.0)(happy-dom@20.8.3)(jiti@2.6.1)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))': + '@vitest/coverage-v8@3.2.4(vitest@3.2.4(@types/debug@4.1.12)(@types/node@24.12.0)(happy-dom@20.8.4)(jiti@2.6.1)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.32.0)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))': dependencies: '@ampproject/remapping': 2.3.0 '@bcoe/v8-coverage': 1.0.2 @@ -17322,37 +17551,37 @@ snapshots: std-env: 3.10.0 test-exclude: 7.0.2 tinyrainbow: 2.0.0 - vitest: 3.2.4(@types/debug@4.1.12)(@types/node@24.12.0)(happy-dom@20.8.3)(jiti@2.6.1)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + vitest: 3.2.4(@types/debug@4.1.12)(@types/node@24.12.0)(happy-dom@20.8.4)(jiti@2.6.1)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.32.0)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3) transitivePeerDependencies: - supports-color - '@vitest/coverage-v8@4.0.18(vitest@4.0.18(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.3)(jiti@2.6.1)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))': + '@vitest/coverage-v8@4.1.0(vitest@4.1.0(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.4)(jsdom@26.1.0(canvas@2.11.2))(vite@8.0.1(@types/node@24.12.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)))': dependencies: '@bcoe/v8-coverage': 1.0.2 - '@vitest/utils': 4.0.18 - ast-v8-to-istanbul: 0.3.12 + '@vitest/utils': 4.1.0 + ast-v8-to-istanbul: 1.0.0 istanbul-lib-coverage: 3.2.2 istanbul-lib-report: 3.0.1 istanbul-reports: 3.2.0 magicast: 0.5.2 obug: 2.1.1 - std-env: 3.10.0 - tinyrainbow: 3.0.3 - vitest: 4.0.18(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.3)(jiti@2.6.1)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + std-env: 4.0.0 + tinyrainbow: 3.1.0 + vitest: 4.1.0(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.4)(jsdom@26.1.0(canvas@2.11.2))(vite@8.0.1(@types/node@24.12.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) - '@vitest/coverage-v8@4.0.18(vitest@4.0.18(@opentelemetry/api@1.9.0)(@types/node@25.4.0)(happy-dom@20.8.3)(jiti@2.6.1)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))': + '@vitest/coverage-v8@4.1.0(vitest@4.1.0(@opentelemetry/api@1.9.0)(@types/node@25.5.0)(happy-dom@20.8.4)(jsdom@26.1.0(canvas@2.11.2))(vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)))': dependencies: '@bcoe/v8-coverage': 1.0.2 - '@vitest/utils': 4.0.18 - ast-v8-to-istanbul: 0.3.12 + '@vitest/utils': 4.1.0 + ast-v8-to-istanbul: 1.0.0 istanbul-lib-coverage: 3.2.2 istanbul-lib-report: 3.0.1 istanbul-reports: 3.2.0 magicast: 0.5.2 obug: 2.1.1 - std-env: 3.10.0 - tinyrainbow: 3.0.3 - vitest: 4.0.18(@opentelemetry/api@1.9.0)(@types/node@25.4.0)(happy-dom@20.8.3)(jiti@2.6.1)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + std-env: 4.0.0 + tinyrainbow: 3.1.0 + vitest: 4.1.0(@opentelemetry/api@1.9.0)(@types/node@25.5.0)(happy-dom@20.8.4)(jsdom@26.1.0(canvas@2.11.2))(vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) '@vitest/expect@3.2.4': dependencies: @@ -17362,46 +17591,46 @@ snapshots: chai: 5.3.3 tinyrainbow: 2.0.0 - '@vitest/expect@4.0.18': + '@vitest/expect@4.1.0': dependencies: '@standard-schema/spec': 1.1.0 '@types/chai': 5.2.3 - '@vitest/spy': 4.0.18 - '@vitest/utils': 4.0.18 + '@vitest/spy': 4.1.0 + '@vitest/utils': 4.1.0 chai: 6.2.2 - tinyrainbow: 3.0.3 + tinyrainbow: 3.1.0 - '@vitest/mocker@3.2.4(vite@7.3.1(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))': + '@vitest/mocker@3.2.4(vite@7.3.1(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))': dependencies: '@vitest/spy': 3.2.4 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 7.3.1(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + vite: 7.3.1(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3) - '@vitest/mocker@4.0.18(vite@7.3.1(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))': + '@vitest/mocker@4.1.0(vite@8.0.1(@types/node@24.12.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))': dependencies: - '@vitest/spy': 4.0.18 + '@vitest/spy': 4.1.0 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 7.3.1(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + vite: 8.0.1(@types/node@24.12.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3) - '@vitest/mocker@4.0.18(vite@7.3.1(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))': + '@vitest/mocker@4.1.0(vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))': dependencies: - '@vitest/spy': 4.0.18 + '@vitest/spy': 4.1.0 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 7.3.1(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + vite: 8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3) '@vitest/pretty-format@3.2.4': dependencies: tinyrainbow: 2.0.0 - '@vitest/pretty-format@4.0.18': + '@vitest/pretty-format@4.1.0': dependencies: - tinyrainbow: 3.0.3 + tinyrainbow: 3.1.0 '@vitest/runner@3.2.4': dependencies: @@ -17409,9 +17638,9 @@ snapshots: pathe: 2.0.3 strip-literal: 3.1.0 - '@vitest/runner@4.0.18': + '@vitest/runner@4.1.0': dependencies: - '@vitest/utils': 4.0.18 + '@vitest/utils': 4.1.0 pathe: 2.0.3 '@vitest/snapshot@3.2.4': @@ -17420,9 +17649,10 @@ snapshots: magic-string: 0.30.21 pathe: 2.0.3 - '@vitest/snapshot@4.0.18': + '@vitest/snapshot@4.1.0': dependencies: - '@vitest/pretty-format': 4.0.18 + '@vitest/pretty-format': 4.1.0 + '@vitest/utils': 4.1.0 magic-string: 0.30.21 pathe: 2.0.3 @@ -17430,7 +17660,7 @@ snapshots: dependencies: tinyspy: 4.0.4 - '@vitest/spy@4.0.18': {} + '@vitest/spy@4.1.0': {} '@vitest/utils@3.2.4': dependencies: @@ -17438,10 +17668,11 @@ snapshots: loupe: 3.2.1 tinyrainbow: 2.0.0 - '@vitest/utils@4.0.18': + '@vitest/utils@4.1.0': dependencies: - '@vitest/pretty-format': 4.0.18 - tinyrainbow: 3.0.3 + '@vitest/pretty-format': 4.1.0 + convert-source-map: 2.0.0 + tinyrainbow: 3.1.0 '@webassemblyjs/ast@1.14.1': dependencies: @@ -17527,10 +17758,10 @@ snapshots: dependencies: '@namnode/store': 0.1.0 - '@zoom-image/svelte@0.3.9(svelte@5.53.7)': + '@zoom-image/svelte@0.3.9(svelte@5.54.1)': dependencies: '@zoom-image/core': 0.42.0 - svelte: 5.53.7 + svelte: 5.54.1 abbrev@1.1.1: {} @@ -17682,7 +17913,7 @@ snapshots: anymatch@3.1.3: dependencies: normalize-path: 3.0.0 - picomatch: 2.3.1 + picomatch: 2.3.2 append-field@1.0.0: {} @@ -17705,10 +17936,11 @@ snapshots: buffer-crc32: 1.0.0 readable-stream: 4.7.0 readdir-glob: 1.1.3 - tar-stream: 3.1.7 + tar-stream: 3.1.8 zip-stream: 6.0.1 transitivePeerDependencies: - bare-abort-controller + - bare-buffer - react-native-b4a are-we-there-yet@2.0.0: @@ -17758,6 +17990,12 @@ snapshots: estree-walker: 3.0.3 js-tokens: 10.0.0 + ast-v8-to-istanbul@1.0.0: + dependencies: + '@jridgewell/trace-mapping': 0.3.31 + estree-walker: 3.0.3 + js-tokens: 10.0.0 + astring@1.9.0: {} async-lock@1.4.1: {} @@ -17783,7 +18021,7 @@ snapshots: axobject-query@4.1.0: {} - b4a@1.7.3: {} + b4a@1.8.0: {} babel-loader@9.2.1(@babel/core@7.28.5)(webpack@5.104.1): dependencies: @@ -17830,41 +18068,35 @@ snapshots: bare-events@2.8.2: {} - bare-fs@4.5.4: + bare-fs@4.5.6: dependencies: bare-events: 2.8.2 bare-path: 3.0.0 - bare-stream: 2.8.0(bare-events@2.8.2) - bare-url: 2.3.2 + bare-stream: 2.11.0(bare-events@2.8.2) + bare-url: 2.4.0 fast-fifo: 1.3.2 transitivePeerDependencies: - bare-abort-controller - react-native-b4a - optional: true - bare-os@3.6.2: - optional: true + bare-os@3.8.0: {} bare-path@3.0.0: dependencies: - bare-os: 3.6.2 - optional: true + bare-os: 3.8.0 - bare-stream@2.8.0(bare-events@2.8.2): + bare-stream@2.11.0(bare-events@2.8.2): dependencies: - streamx: 2.23.0 + streamx: 2.25.0 teex: 1.0.1 optionalDependencies: bare-events: 2.8.2 transitivePeerDependencies: - - bare-abort-controller - react-native-b4a - optional: true - bare-url@2.3.2: + bare-url@2.4.0: dependencies: bare-path: 3.0.0 - optional: true base64-js@1.5.1: {} @@ -17894,15 +18126,15 @@ snapshots: binary-extensions@2.3.0: {} - bits-ui@2.16.0(@internationalized/date@3.10.0)(@sveltejs/kit@2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.7)(vite@7.3.1(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(svelte@5.53.7)(typescript@5.9.3)(vite@7.3.1(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(svelte@5.53.7): + bits-ui@2.16.0(@internationalized/date@3.10.0)(@sveltejs/kit@2.55.0(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.54.1)(vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)))(svelte@5.54.1)(typescript@5.9.3)(vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)))(svelte@5.54.1): dependencies: '@floating-ui/core': 1.7.3 '@floating-ui/dom': 1.7.4 '@internationalized/date': 3.10.0 esm-env: 1.2.2 - runed: 0.35.1(@sveltejs/kit@2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.7)(vite@7.3.1(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(svelte@5.53.7)(typescript@5.9.3)(vite@7.3.1(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(svelte@5.53.7) - svelte: 5.53.7 - svelte-toolbelt: 0.10.6(@sveltejs/kit@2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.7)(vite@7.3.1(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(svelte@5.53.7)(typescript@5.9.3)(vite@7.3.1(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(svelte@5.53.7) + runed: 0.35.1(@sveltejs/kit@2.55.0(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.54.1)(vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)))(svelte@5.54.1)(typescript@5.9.3)(vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)))(svelte@5.54.1) + svelte: 5.54.1 + svelte-toolbelt: 0.10.6(@sveltejs/kit@2.55.0(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.54.1)(vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)))(svelte@5.54.1)(typescript@5.9.3)(vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)))(svelte@5.54.1) tabbable: 6.4.0 transitivePeerDependencies: - '@sveltejs/kit' @@ -17982,7 +18214,7 @@ snapshots: dependencies: balanced-match: 1.0.2 - brace-expansion@5.0.4: + brace-expansion@5.0.5: dependencies: balanced-match: 4.0.4 @@ -18019,7 +18251,7 @@ snapshots: builtin-modules@5.0.0: {} - bullmq@5.70.4: + bullmq@5.71.0: dependencies: cron-parser: 4.9.0 ioredis: 5.9.3 @@ -18119,7 +18351,7 @@ snapshots: canvas@2.11.2: dependencies: '@mapbox/node-pre-gyp': 1.0.11 - nan: 2.25.0 + nan: 2.26.2 simple-get: 3.1.1 transitivePeerDependencies: - encoding @@ -18129,7 +18361,7 @@ snapshots: canvas@2.11.2(encoding@0.1.13): dependencies: '@mapbox/node-pre-gyp': 1.0.11(encoding@0.1.13) - nan: 2.25.0 + nan: 2.26.2 simple-get: 3.1.1 transitivePeerDependencies: - encoding @@ -18511,7 +18743,7 @@ snapshots: cpu-features@0.0.10: dependencies: buildcheck: 0.0.7 - nan: 2.25.0 + nan: 2.26.2 optional: true crc-32@1.2.2: {} @@ -18961,7 +19193,7 @@ snapshots: delaunator@5.0.1: dependencies: - robust-predicates: 3.0.2 + robust-predicates: 3.0.3 delayed-stream@1.0.0: {} @@ -18993,7 +19225,7 @@ snapshots: transitivePeerDependencies: - supports-color - devalue@5.6.3: {} + devalue@5.6.4: {} devlop@1.1.0: dependencies: @@ -19026,11 +19258,11 @@ snapshots: dependencies: '@leichtgewicht/ip-codec': 2.0.5 - docker-compose@1.3.1: + docker-compose@1.3.3: dependencies: - yaml: 2.8.2 + yaml: 2.8.3 - docker-modem@5.0.6: + docker-modem@5.0.7: dependencies: debug: 4.4.3 readable-stream: 3.6.2 @@ -19039,12 +19271,12 @@ snapshots: transitivePeerDependencies: - supports-color - dockerode@4.0.9: + dockerode@4.0.10: dependencies: '@balena/dockerignore': 1.0.2 '@grpc/grpc-js': 1.14.3 '@grpc/proto-loader': 0.7.15 - docker-modem: 5.0.6 + docker-modem: 5.0.7 protobufjs: 7.5.4 tar-fs: 2.1.4 uuid: 10.0.0 @@ -19063,7 +19295,7 @@ snapshots: lunr: 2.3.9 lunr-languages: 1.14.0 mark.js: 8.11.1 - minimatch: 3.1.2 + minimatch: 3.1.5 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) rehype-parse: 7.0.1 @@ -19337,34 +19569,34 @@ snapshots: '@esbuild/win32-ia32': 0.25.12 '@esbuild/win32-x64': 0.25.12 - esbuild@0.27.3: + esbuild@0.27.4: 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 + '@esbuild/aix-ppc64': 0.27.4 + '@esbuild/android-arm': 0.27.4 + '@esbuild/android-arm64': 0.27.4 + '@esbuild/android-x64': 0.27.4 + '@esbuild/darwin-arm64': 0.27.4 + '@esbuild/darwin-x64': 0.27.4 + '@esbuild/freebsd-arm64': 0.27.4 + '@esbuild/freebsd-x64': 0.27.4 + '@esbuild/linux-arm': 0.27.4 + '@esbuild/linux-arm64': 0.27.4 + '@esbuild/linux-ia32': 0.27.4 + '@esbuild/linux-loong64': 0.27.4 + '@esbuild/linux-mips64el': 0.27.4 + '@esbuild/linux-ppc64': 0.27.4 + '@esbuild/linux-riscv64': 0.27.4 + '@esbuild/linux-s390x': 0.27.4 + '@esbuild/linux-x64': 0.27.4 + '@esbuild/netbsd-arm64': 0.27.4 + '@esbuild/netbsd-x64': 0.27.4 + '@esbuild/openbsd-arm64': 0.27.4 + '@esbuild/openbsd-x64': 0.27.4 + '@esbuild/openharmony-arm64': 0.27.4 + '@esbuild/sunos-x64': 0.27.4 + '@esbuild/win32-arm64': 0.27.4 + '@esbuild/win32-ia32': 0.27.4 + '@esbuild/win32-x64': 0.27.4 escalade@3.2.0: {} @@ -19378,36 +19610,36 @@ snapshots: escape-string-regexp@5.0.0: {} - eslint-config-prettier@10.1.8(eslint@10.0.2(jiti@2.6.1)): + eslint-config-prettier@10.1.8(eslint@10.1.0(jiti@2.6.1)): dependencies: - eslint: 10.0.2(jiti@2.6.1) + eslint: 10.1.0(jiti@2.6.1) - eslint-plugin-compat@6.2.1(eslint@10.0.2(jiti@2.6.1)): + eslint-plugin-compat@6.2.1(eslint@10.1.0(jiti@2.6.1)): dependencies: '@mdn/browser-compat-data': 6.1.5 ast-metadata-inferer: 0.8.1 browserslist: 4.28.1 - eslint: 10.0.2(jiti@2.6.1) + eslint: 10.1.0(jiti@2.6.1) find-up: 5.0.0 globals: 15.15.0 lodash.memoize: 4.1.2 semver: 7.7.4 - eslint-plugin-prettier@5.5.5(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@10.0.2(jiti@2.6.1)))(eslint@10.0.2(jiti@2.6.1))(prettier@3.8.1): + eslint-plugin-prettier@5.5.5(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@10.1.0(jiti@2.6.1)))(eslint@10.1.0(jiti@2.6.1))(prettier@3.8.1): dependencies: - eslint: 10.0.2(jiti@2.6.1) + eslint: 10.1.0(jiti@2.6.1) prettier: 3.8.1 prettier-linter-helpers: 1.0.1 synckit: 0.11.12 optionalDependencies: '@types/eslint': 9.6.1 - eslint-config-prettier: 10.1.8(eslint@10.0.2(jiti@2.6.1)) + eslint-config-prettier: 10.1.8(eslint@10.1.0(jiti@2.6.1)) - eslint-plugin-svelte@3.15.0(eslint@10.0.2(jiti@2.6.1))(svelte@5.53.7): + eslint-plugin-svelte@3.16.0(eslint@10.1.0(jiti@2.6.1))(svelte@5.54.1): dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.0.2(jiti@2.6.1)) + '@eslint-community/eslint-utils': 4.9.1(eslint@10.1.0(jiti@2.6.1)) '@jridgewell/sourcemap-codec': 1.5.5 - eslint: 10.0.2(jiti@2.6.1) + eslint: 10.1.0(jiti@2.6.1) esutils: 2.0.3 globals: 16.5.0 known-css-properties: 0.37.0 @@ -19415,21 +19647,21 @@ snapshots: postcss-load-config: 3.1.4(postcss@8.5.8) postcss-safe-parser: 7.0.1(postcss@8.5.8) semver: 7.7.4 - svelte-eslint-parser: 1.6.0(svelte@5.53.7) + svelte-eslint-parser: 1.6.0(svelte@5.54.1) optionalDependencies: - svelte: 5.53.7 + svelte: 5.54.1 transitivePeerDependencies: - ts-node - eslint-plugin-unicorn@63.0.0(eslint@10.0.2(jiti@2.6.1)): + eslint-plugin-unicorn@63.0.0(eslint@10.1.0(jiti@2.6.1)): dependencies: '@babel/helper-validator-identifier': 7.28.5 - '@eslint-community/eslint-utils': 4.9.1(eslint@10.0.2(jiti@2.6.1)) + '@eslint-community/eslint-utils': 4.9.1(eslint@10.1.0(jiti@2.6.1)) change-case: 5.4.4 ci-info: 4.3.1 clean-regexp: 1.0.0 core-js-compat: 3.47.0 - eslint: 10.0.2(jiti@2.6.1) + eslint: 10.1.0(jiti@2.6.1) find-up-simple: 1.0.1 globals: 16.5.0 indent-string: 5.0.0 @@ -19451,7 +19683,7 @@ snapshots: esrecurse: 4.3.0 estraverse: 5.3.0 - eslint-scope@9.1.1: + eslint-scope@9.1.2: dependencies: '@types/esrecurse': 4.3.1 '@types/estree': 1.0.8 @@ -19464,14 +19696,14 @@ snapshots: eslint-visitor-keys@5.0.1: {} - eslint@10.0.2(jiti@2.6.1): + eslint@10.1.0(jiti@2.6.1): dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.0.2(jiti@2.6.1)) + '@eslint-community/eslint-utils': 4.9.1(eslint@10.1.0(jiti@2.6.1)) '@eslint-community/regexpp': 4.12.2 - '@eslint/config-array': 0.23.2 - '@eslint/config-helpers': 0.5.2 - '@eslint/core': 1.1.0 - '@eslint/plugin-kit': 0.6.0 + '@eslint/config-array': 0.23.3 + '@eslint/config-helpers': 0.5.3 + '@eslint/core': 1.1.1 + '@eslint/plugin-kit': 0.6.1 '@humanfs/node': 0.16.7 '@humanwhocodes/module-importer': 1.0.1 '@humanwhocodes/retry': 0.4.3 @@ -19480,9 +19712,9 @@ snapshots: cross-spawn: 7.0.6 debug: 4.4.3 escape-string-regexp: 4.0.0 - eslint-scope: 9.1.1 + eslint-scope: 9.1.2 eslint-visitor-keys: 5.0.1 - espree: 11.1.1 + espree: 11.2.0 esquery: 1.7.0 esutils: 2.0.3 fast-deep-equal: 3.1.3 @@ -19516,7 +19748,7 @@ snapshots: acorn-jsx: 5.3.2(acorn@8.16.0) eslint-visitor-keys: 4.2.1 - espree@11.1.1: + espree@11.2.0: dependencies: acorn: 8.16.0 acorn-jsx: 5.3.2(acorn@8.16.0) @@ -19664,7 +19896,7 @@ snapshots: methods: 1.1.2 on-finished: 2.4.1 parseurl: 1.3.3 - path-to-regexp: 0.1.12 + path-to-regexp: 0.1.13 proxy-addr: 2.0.7 qs: 6.14.1 range-parser: 1.2.1 @@ -19775,9 +20007,9 @@ snapshots: dependencies: websocket-driver: 0.7.4 - fdir@6.5.0(picomatch@4.0.3): + fdir@6.5.0(picomatch@4.0.4): optionalDependencies: - picomatch: 4.0.3 + picomatch: 4.0.4 feed@4.2.2: dependencies: @@ -19803,10 +20035,10 @@ snapshots: dependencies: stream-source: 0.3.5 - file-type@21.3.0: + file-type@21.3.2: dependencies: '@tokenizer/inflate': 0.4.1 - strtok3: 10.3.4 + strtok3: 10.3.5 token-types: 6.1.2 uint8array-extras: 1.5.0 transitivePeerDependencies: @@ -19863,12 +20095,12 @@ snapshots: flat-cache@4.0.1: dependencies: - flatted: 3.3.3 + flatted: 3.4.2 keyv: 4.5.4 flat@5.0.2: {} - flatted@3.3.3: {} + flatted@3.4.2: {} fluent-ffmpeg@2.1.3: dependencies: @@ -19882,7 +20114,7 @@ snapshots: cross-spawn: 7.0.6 signal-exit: 4.1.0 - fork-ts-checker-webpack-plugin@9.1.0(typescript@5.9.3)(webpack@5.104.1(@swc/core@1.15.18(@swc/helpers@0.5.17))): + fork-ts-checker-webpack-plugin@9.1.0(typescript@5.9.3)(webpack@5.104.1(@swc/core@1.15.18(@swc/helpers@0.5.17))(esbuild@0.27.4)): dependencies: '@babel/code-frame': 7.29.0 chalk: 4.1.2 @@ -19891,13 +20123,13 @@ snapshots: deepmerge: 4.3.1 fs-extra: 10.1.0 memfs: 3.5.3 - minimatch: 3.1.2 + minimatch: 3.1.5 node-abort-controller: 3.1.1 schema-utils: 3.3.0 semver: 7.7.4 tapable: 2.3.0 typescript: 5.9.3 - webpack: 5.104.1(@swc/core@1.15.18(@swc/helpers@0.5.17)) + webpack: 5.104.1(@swc/core@1.15.18(@swc/helpers@0.5.17))(esbuild@0.27.4) form-data-encoder@2.1.4: {} @@ -19981,10 +20213,10 @@ snapshots: geo-coordinates-parser@1.7.4: {} - geo-tz@8.1.5: + geo-tz@8.1.6: dependencies: - '@turf/boolean-point-in-polygon': 7.3.2 - '@turf/helpers': 7.3.2 + '@turf/boolean-point-in-polygon': 7.3.4 + '@turf/helpers': 7.3.4 geobuf: 3.0.2 pbf: 3.3.0 @@ -20015,7 +20247,7 @@ snapshots: get-own-enumerable-property-symbols@3.0.2: {} - get-port@7.1.0: {} + get-port@7.2.0: {} get-proto@1.0.1: dependencies: @@ -20050,7 +20282,7 @@ snapshots: dependencies: foreground-child: 3.3.1 jackspeak: 3.4.3 - minimatch: 9.0.6 + minimatch: 9.0.9 minipass: 7.1.2 package-json-from-dist: 1.0.1 path-scurry: 1.11.1 @@ -20081,7 +20313,7 @@ snapshots: fs.realpath: 1.0.0 inflight: 1.0.6 inherits: 2.0.4 - minimatch: 3.1.2 + minimatch: 3.1.5 once: 1.4.0 path-is-absolute: 1.0.1 @@ -20160,14 +20392,14 @@ snapshots: optionalDependencies: uglify-js: 3.19.3 - happy-dom@20.8.3: + happy-dom@20.8.4: dependencies: '@types/node': 24.12.0 '@types/whatwg-mimetype': 3.0.2 '@types/ws': 8.18.1 entities: 7.0.1 whatwg-mimetype: 3.0.0 - ws: 8.19.0 + ws: 8.20.0 transitivePeerDependencies: - bufferutil - utf-8-validate @@ -20338,11 +20570,13 @@ snapshots: he@1.2.0: {} + helmet@8.1.0: {} + highlight.js@11.11.1: {} history@4.10.1: dependencies: - '@babel/runtime': 7.28.6 + '@babel/runtime': 7.29.2 loose-envify: 1.4.0 resolve-pathname: 3.0.0 tiny-invariant: 1.3.3 @@ -20623,18 +20857,17 @@ snapshots: '@formatjs/icu-messageformat-parser': 2.11.4 tslib: 2.8.1 - intl-messageformat@11.1.2: + intl-messageformat@11.2.0: dependencies: - '@formatjs/ecma402-abstract': 3.1.1 - '@formatjs/fast-memoize': 3.1.0 - '@formatjs/icu-messageformat-parser': 3.5.1 - tslib: 2.8.1 + '@formatjs/ecma402-abstract': 3.2.0 + '@formatjs/fast-memoize': 3.1.1 + '@formatjs/icu-messageformat-parser': 3.5.3 invariant@2.2.4: dependencies: loose-envify: 1.4.0 - ioredis@5.10.0: + ioredis@5.10.1: dependencies: '@ioredis/commands': 1.5.1 cluster-key-slot: 1.1.2 @@ -20835,7 +21068,7 @@ snapshots: chalk: 4.1.2 ci-info: 3.9.0 graceful-fs: 4.2.11 - picomatch: 2.3.1 + picomatch: 2.3.2 jest-worker@27.5.1: dependencies: @@ -20868,7 +21101,7 @@ snapshots: jose@5.10.0: {} - jose@6.1.3: {} + jose@6.2.2: {} js-tokens@10.0.0: {} @@ -20905,7 +21138,7 @@ snapshots: whatwg-encoding: 3.1.1 whatwg-mimetype: 4.0.0 whatwg-url: 14.2.0 - ws: 8.19.0 + ws: 8.20.0 xml-name-validator: 5.0.0 optionalDependencies: canvas: 2.11.2(encoding@0.1.13) @@ -20935,7 +21168,7 @@ snapshots: whatwg-encoding: 3.1.1 whatwg-mimetype: 4.0.0 whatwg-url: 14.2.0 - ws: 8.19.0 + ws: 8.20.0 xml-name-validator: 5.0.0 optionalDependencies: canvas: 2.11.2 @@ -21037,10 +21270,10 @@ snapshots: koa-compose@4.1.0: {} - koa@3.1.1: + koa@3.1.2: dependencies: accepts: 1.3.8 - content-disposition: 0.5.4 + content-disposition: 1.0.1 content-type: 1.0.5 cookies: 0.9.1 delegates: 1.0.0 @@ -21058,13 +21291,13 @@ snapshots: type-is: 2.0.1 vary: 1.1.2 - kysely-postgres-js@3.0.0(kysely@0.28.11)(postgres@3.4.8): + kysely-postgres-js@3.0.0(kysely@0.28.14)(postgres@3.4.8): dependencies: - kysely: 0.28.11 + kysely: 0.28.14 optionalDependencies: postgres: 3.4.8 - kysely@0.28.11: {} + kysely@0.28.14: {} langium@3.3.1: dependencies: @@ -21102,54 +21335,54 @@ snapshots: libphonenumber-js@1.12.38: {} - lightningcss-android-arm64@1.31.1: + lightningcss-android-arm64@1.32.0: optional: true - lightningcss-darwin-arm64@1.31.1: + lightningcss-darwin-arm64@1.32.0: optional: true - lightningcss-darwin-x64@1.31.1: + lightningcss-darwin-x64@1.32.0: optional: true - lightningcss-freebsd-x64@1.31.1: + lightningcss-freebsd-x64@1.32.0: optional: true - lightningcss-linux-arm-gnueabihf@1.31.1: + lightningcss-linux-arm-gnueabihf@1.32.0: optional: true - lightningcss-linux-arm64-gnu@1.31.1: + lightningcss-linux-arm64-gnu@1.32.0: optional: true - lightningcss-linux-arm64-musl@1.31.1: + lightningcss-linux-arm64-musl@1.32.0: optional: true - lightningcss-linux-x64-gnu@1.31.1: + lightningcss-linux-x64-gnu@1.32.0: optional: true - lightningcss-linux-x64-musl@1.31.1: + lightningcss-linux-x64-musl@1.32.0: optional: true - lightningcss-win32-arm64-msvc@1.31.1: + lightningcss-win32-arm64-msvc@1.32.0: optional: true - lightningcss-win32-x64-msvc@1.31.1: + lightningcss-win32-x64-msvc@1.32.0: optional: true - lightningcss@1.31.1: + lightningcss@1.32.0: dependencies: detect-libc: 2.1.2 optionalDependencies: - lightningcss-android-arm64: 1.31.1 - lightningcss-darwin-arm64: 1.31.1 - lightningcss-darwin-x64: 1.31.1 - lightningcss-freebsd-x64: 1.31.1 - lightningcss-linux-arm-gnueabihf: 1.31.1 - lightningcss-linux-arm64-gnu: 1.31.1 - lightningcss-linux-arm64-musl: 1.31.1 - lightningcss-linux-x64-gnu: 1.31.1 - lightningcss-linux-x64-musl: 1.31.1 - lightningcss-win32-arm64-msvc: 1.31.1 - lightningcss-win32-x64-msvc: 1.31.1 + 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 lilconfig@2.1.0: {} @@ -21276,13 +21509,13 @@ snapshots: magicast@0.3.5: dependencies: - '@babel/parser': 7.29.0 + '@babel/parser': 7.29.2 '@babel/types': 7.29.0 source-map-js: 1.2.1 magicast@0.5.2: dependencies: - '@babel/parser': 7.29.0 + '@babel/parser': 7.29.2 '@babel/types': 7.29.0 source-map-js: 1.2.1 @@ -21310,21 +21543,19 @@ snapshots: transitivePeerDependencies: - supports-color - maplibre-gl@5.19.0: + maplibre-gl@5.21.0: dependencies: - '@mapbox/geojson-rewind': 0.5.2 '@mapbox/jsonlint-lines-primitives': 2.0.2 '@mapbox/point-geometry': 1.1.0 '@mapbox/tiny-sdf': 2.0.7 '@mapbox/unitbezier': 0.0.1 '@mapbox/vector-tile': 2.0.4 '@mapbox/whoots-js': 3.1.0 - '@maplibre/geojson-vt': 5.0.4 - '@maplibre/maplibre-gl-style-spec': 24.6.0 - '@maplibre/mlt': 1.1.6 + '@maplibre/geojson-vt': 6.0.4 + '@maplibre/maplibre-gl-style-spec': 24.7.0 + '@maplibre/mlt': 1.1.8 '@maplibre/vt-pbf': 4.3.0 '@types/geojson': 7946.0.16 - '@types/supercluster': 7.1.3 earcut: 3.0.2 gl-matrix: 3.4.4 kdbush: 4.0.2 @@ -21332,7 +21563,6 @@ snapshots: pbf: 4.0.1 potpack: 2.1.0 quickselect: 3.0.0 - supercluster: 8.0.1 tinyqueue: 3.0.0 mark.js@8.11.1: {} @@ -21906,7 +22136,7 @@ snapshots: micromatch@4.0.8: dependencies: braces: 3.0.3 - picomatch: 2.3.1 + picomatch: 2.3.2 mime-db@1.33.0: {} @@ -21953,19 +22183,23 @@ snapshots: minimatch@10.2.4: dependencies: - brace-expansion: 5.0.4 + brace-expansion: 5.0.5 minimatch@3.1.2: dependencies: brace-expansion: 1.1.12 - minimatch@5.1.6: + minimatch@3.1.5: + dependencies: + brace-expansion: 1.1.12 + + minimatch@5.1.9: dependencies: brace-expansion: 2.0.2 - minimatch@9.0.6: + minimatch@9.0.9: dependencies: - brace-expansion: 5.0.4 + brace-expansion: 2.0.2 minimist@1.2.8: {} @@ -22083,12 +22317,12 @@ snapshots: object-assign: 4.1.1 thenify-all: 1.6.0 - nan@2.25.0: + nan@2.26.2: optional: true nanoid@3.3.11: {} - nanoid@5.1.6: {} + nanoid@5.1.7: {} natural-compare-lite@1.4.0: {} @@ -22109,12 +22343,12 @@ snapshots: neo-async@2.6.2: {} - nest-commander@3.20.1(@nestjs/common@11.1.16(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.16)(@types/inquirer@8.2.12)(@types/node@24.12.0)(typescript@5.9.3): + nest-commander@3.20.1(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17)(@types/inquirer@8.2.12)(@types/node@24.12.0)(typescript@5.9.3): dependencies: '@fig/complete-commander': 3.2.0(commander@11.1.0) - '@golevelup/nestjs-discovery': 5.0.0(@nestjs/common@11.1.16(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.16) - '@nestjs/common': 11.1.16(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/core': 11.1.16(@nestjs/common@11.1.16(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.16)(@nestjs/websockets@11.1.16)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@golevelup/nestjs-discovery': 5.0.0(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17) + '@nestjs/common': 11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(@nestjs/websockets@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2) '@types/inquirer': 8.2.12 commander: 11.1.0 cosmiconfig: 8.3.6(typescript@5.9.3) @@ -22123,25 +22357,25 @@ snapshots: - '@types/node' - typescript - nestjs-cls@5.4.3(@nestjs/common@11.1.16(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.16)(reflect-metadata@0.2.2)(rxjs@7.8.2): + nestjs-cls@5.4.3(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2): dependencies: - '@nestjs/common': 11.1.16(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/core': 11.1.16(@nestjs/common@11.1.16(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.16)(@nestjs/websockets@11.1.16)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/common': 11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(@nestjs/websockets@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2) reflect-metadata: 0.2.2 rxjs: 7.8.2 - nestjs-kysely@3.1.2(@nestjs/common@11.1.16(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.16)(kysely@0.28.11)(reflect-metadata@0.2.2): + nestjs-kysely@3.1.2(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17)(kysely@0.28.14)(reflect-metadata@0.2.2): dependencies: - '@nestjs/common': 11.1.16(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/core': 11.1.16(@nestjs/common@11.1.16(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.16)(@nestjs/websockets@11.1.16)(reflect-metadata@0.2.2)(rxjs@7.8.2) - kysely: 0.28.11 + '@nestjs/common': 11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(@nestjs/websockets@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2) + kysely: 0.28.14 reflect-metadata: 0.2.2 tslib: 2.8.1 - nestjs-otel@7.0.1(@nestjs/common@11.1.16(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.16): + nestjs-otel@7.0.1(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17): dependencies: - '@nestjs/common': 11.1.16(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/core': 11.1.16(@nestjs/common@11.1.16(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.16)(@nestjs/websockets@11.1.16)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/common': 11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(@nestjs/websockets@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2) '@opentelemetry/api': 1.9.0 '@opentelemetry/host-metrics': 0.36.2(@opentelemetry/api@1.9.0) response-time: 2.3.4 @@ -22292,18 +22526,19 @@ snapshots: obug@2.1.1: {} - oidc-provider@9.6.1: + oidc-provider@9.7.1: dependencies: '@koa/cors': 5.0.0 - '@koa/router': 15.3.0(koa@3.1.1) + '@koa/router': 15.4.0(koa@3.1.2) debug: 4.4.3 eta: 4.5.1 - jose: 6.1.3 + jose: 6.2.2 jsesc: 3.1.0 - koa: 3.1.1 - nanoid: 5.1.6 + koa: 3.1.2 + nanoid: 5.1.7 quick-lru: 7.3.0 raw-body: 3.0.2 + undici: 7.24.6 transitivePeerDependencies: - supports-color @@ -22342,7 +22577,7 @@ snapshots: openid-client@6.8.2: dependencies: - jose: 6.1.3 + jose: 6.2.2 oauth4webapi: 3.8.5 optionator@0.9.4: @@ -22522,7 +22757,7 @@ snapshots: array-source: 0.0.4 file-source: 0.6.1 - path-to-regexp@0.1.12: {} + path-to-regexp@0.1.13: {} path-to-regexp@1.9.0: dependencies: @@ -22586,11 +22821,11 @@ snapshots: picocolors@1.1.1: {} - picomatch@2.3.1: {} + picomatch@2.3.2: {} picomatch@4.0.2: {} - picomatch@4.0.3: {} + picomatch@4.0.4: {} pify@2.3.0: {} @@ -22637,7 +22872,7 @@ snapshots: point-in-polygon-hao@1.2.4: dependencies: - robust-predicates: 3.0.2 + robust-predicates: 3.0.3 points-on-curve@0.2.0: {} @@ -22803,18 +23038,18 @@ snapshots: postcss-load-config@3.1.4(postcss@8.5.8): dependencies: lilconfig: 2.1.0 - yaml: 1.10.2 + yaml: 1.10.3 optionalDependencies: postcss: 8.5.8 - postcss-load-config@6.0.1(jiti@1.21.7)(postcss@8.5.8)(tsx@4.21.0)(yaml@2.8.2): + postcss-load-config@6.0.1(jiti@1.21.7)(postcss@8.5.8)(tsx@4.21.0)(yaml@2.8.3): dependencies: lilconfig: 3.1.3 optionalDependencies: jiti: 1.21.7 postcss: 8.5.8 tsx: 4.21.0 - yaml: 2.8.2 + yaml: 2.8.3 postcss-loader@7.3.4(postcss@8.5.8)(typescript@5.9.3)(webpack@5.104.1): dependencies: @@ -23155,10 +23390,10 @@ snapshots: dependencies: prettier: 3.8.1 - prettier-plugin-svelte@3.5.1(prettier@3.8.1)(svelte@5.53.7): + prettier-plugin-svelte@3.5.1(prettier@3.8.1)(svelte@5.54.1): dependencies: prettier: 3.8.1 - svelte: 5.53.7 + svelte: 5.54.1 prettier@3.8.1: {} @@ -23248,7 +23483,7 @@ snapshots: forwarded: 0.2.0 ipaddr.js: 1.9.1 - pump@3.0.3: + pump@3.0.4: dependencies: end-of-stream: 1.4.5 once: 1.4.0 @@ -23334,7 +23569,7 @@ snapshots: react-email@4.3.2: dependencies: - '@babel/parser': 7.29.0 + '@babel/parser': 7.29.2 '@babel/traverse': 7.28.5 chokidar: 4.0.3 commander: 13.1.0 @@ -23367,7 +23602,7 @@ snapshots: react-loadable-ssr-addon-v5-slorber@1.0.1(@docusaurus/react-loadable@6.0.0(react@18.3.1))(webpack@5.104.1): dependencies: - '@babel/runtime': 7.28.6 + '@babel/runtime': 7.29.2 react-loadable: '@docusaurus/react-loadable@6.0.0(react@18.3.1)' webpack: 5.104.1 @@ -23377,13 +23612,13 @@ snapshots: react-router-config@5.1.1(react-router@5.3.4(react@18.3.1))(react@18.3.1): dependencies: - '@babel/runtime': 7.28.6 + '@babel/runtime': 7.29.2 react: 18.3.1 react-router: 5.3.4(react@18.3.1) react-router-dom@5.3.4(react@18.3.1): dependencies: - '@babel/runtime': 7.28.6 + '@babel/runtime': 7.29.2 history: 4.10.1 loose-envify: 1.4.0 prop-types: 15.8.1 @@ -23394,7 +23629,7 @@ snapshots: react-router@5.3.4(react@18.3.1): dependencies: - '@babel/runtime': 7.28.6 + '@babel/runtime': 7.29.2 history: 4.10.1 hoist-non-react-statics: 3.3.2 loose-envify: 1.4.0 @@ -23441,11 +23676,11 @@ snapshots: readdir-glob@1.1.3: dependencies: - minimatch: 5.1.6 + minimatch: 5.1.9 readdirp@3.6.0: dependencies: - picomatch: 2.3.1 + picomatch: 2.3.2 readdirp@4.1.2: {} @@ -23686,15 +23921,37 @@ snapshots: dependencies: glob: 7.2.3 - robust-predicates@3.0.2: {} + robust-predicates@3.0.3: {} - rollup-plugin-visualizer@6.0.11(rollup@4.55.1): + rolldown@1.0.0-rc.10: + dependencies: + '@oxc-project/types': 0.120.0 + '@rolldown/pluginutils': 1.0.0-rc.10 + optionalDependencies: + '@rolldown/binding-android-arm64': 1.0.0-rc.10 + '@rolldown/binding-darwin-arm64': 1.0.0-rc.10 + '@rolldown/binding-darwin-x64': 1.0.0-rc.10 + '@rolldown/binding-freebsd-x64': 1.0.0-rc.10 + '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-rc.10 + '@rolldown/binding-linux-arm64-gnu': 1.0.0-rc.10 + '@rolldown/binding-linux-arm64-musl': 1.0.0-rc.10 + '@rolldown/binding-linux-ppc64-gnu': 1.0.0-rc.10 + '@rolldown/binding-linux-s390x-gnu': 1.0.0-rc.10 + '@rolldown/binding-linux-x64-gnu': 1.0.0-rc.10 + '@rolldown/binding-linux-x64-musl': 1.0.0-rc.10 + '@rolldown/binding-openharmony-arm64': 1.0.0-rc.10 + '@rolldown/binding-wasm32-wasi': 1.0.0-rc.10 + '@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.10 + '@rolldown/binding-win32-x64-msvc': 1.0.0-rc.10 + + rollup-plugin-visualizer@6.0.11(rolldown@1.0.0-rc.10)(rollup@4.55.1): dependencies: open: 8.4.2 - picomatch: 4.0.3 + picomatch: 4.0.4 source-map: 0.7.6 yargs: 17.7.2 optionalDependencies: + rolldown: 1.0.0-rc.10 rollup: 4.55.1 rollup@4.55.1: @@ -23763,14 +24020,14 @@ snapshots: dependencies: queue-microtask: 1.2.3 - runed@0.35.1(@sveltejs/kit@2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.7)(vite@7.3.1(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(svelte@5.53.7)(typescript@5.9.3)(vite@7.3.1(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(svelte@5.53.7): + runed@0.35.1(@sveltejs/kit@2.55.0(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.54.1)(vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)))(svelte@5.54.1)(typescript@5.9.3)(vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)))(svelte@5.54.1): dependencies: dequal: 2.0.3 esm-env: 1.2.2 lz-string: 1.5.0 - svelte: 5.53.7 + svelte: 5.54.1 optionalDependencies: - '@sveltejs/kit': 2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.7)(vite@7.3.1(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(svelte@5.53.7)(typescript@5.9.3)(vite@7.3.1(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + '@sveltejs/kit': 2.55.0(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.54.1)(vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)))(svelte@5.54.1)(typescript@5.9.3)(vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) rw@1.3.3: {} @@ -23792,15 +24049,15 @@ snapshots: safer-buffer@2.1.2: {} - sanitize-filename@1.6.3: + sanitize-filename@1.6.4: dependencies: truncate-utf8-bytes: 1.0.2 - sanitize-html@2.17.1: + sanitize-html@2.17.2: dependencies: deepmerge: 4.3.1 escape-string-regexp: 4.0.0 - htmlparser2: 8.0.2 + htmlparser2: 10.1.0 is-plain-object: 5.0.0 parse-srcset: 1.0.2 postcss: 8.5.8 @@ -23947,7 +24204,7 @@ snapshots: set-blocking@2.0.0: {} - set-cookie-parser@3.0.1: {} + set-cookie-parser@3.1.0: {} set-function-length@1.2.2: dependencies: @@ -24230,7 +24487,7 @@ snapshots: bcrypt-pbkdf: 1.0.2 optionalDependencies: cpu-features: 0.0.10 - nan: 2.25.0 + nan: 2.26.2 ssri@13.0.1: dependencies: @@ -24246,17 +24503,19 @@ snapshots: std-env@3.10.0: {} + std-env@4.0.0: {} + stdin-discarder@0.2.2: {} stream-source@0.3.5: {} streamsearch@1.1.0: {} - streamx@2.23.0: + streamx@2.25.0: dependencies: events-universal: 1.0.1 fast-fifo: 1.3.2 - text-decoder: 1.2.3 + text-decoder: 1.2.7 transitivePeerDependencies: - bare-abort-controller - react-native-b4a @@ -24326,7 +24585,7 @@ snapshots: dependencies: js-tokens: 9.0.1 - strtok3@10.3.4: + strtok3@10.3.5: dependencies: '@tokenizer/token': 0.3.0 @@ -24394,23 +24653,23 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} - svelte-awesome@3.3.5(svelte@5.53.7): + svelte-awesome@3.3.5(svelte@5.54.1): dependencies: - svelte: 5.53.7 + svelte: 5.54.1 - svelte-check@4.4.4(picomatch@4.0.3)(svelte@5.53.7)(typescript@5.9.3): + svelte-check@4.4.5(picomatch@4.0.4)(svelte@5.54.1)(typescript@5.9.3): dependencies: '@jridgewell/trace-mapping': 0.3.31 chokidar: 4.0.3 - fdir: 6.5.0(picomatch@4.0.3) + fdir: 6.5.0(picomatch@4.0.4) picocolors: 1.1.1 sade: 1.8.1 - svelte: 5.53.7 + svelte: 5.54.1 typescript: 5.9.3 transitivePeerDependencies: - picomatch - svelte-eslint-parser@1.6.0(svelte@5.53.7): + svelte-eslint-parser@1.6.0(svelte@5.54.1): dependencies: eslint-scope: 8.4.0 eslint-visitor-keys: 4.2.1 @@ -24420,7 +24679,7 @@ snapshots: postcss-selector-parser: 7.1.1 semver: 7.7.4 optionalDependencies: - svelte: 5.53.7 + svelte: 5.54.1 svelte-floating-ui@1.5.8: dependencies: @@ -24433,7 +24692,7 @@ snapshots: dependencies: highlight.js: 11.11.1 - svelte-i18n@4.0.1(svelte@5.53.7): + svelte-i18n@4.0.1(svelte@5.54.1): dependencies: cli-color: 2.0.4 deepmerge: 4.3.1 @@ -24441,10 +24700,10 @@ snapshots: estree-walker: 2.0.2 intl-messageformat: 10.7.18 sade: 1.8.1 - svelte: 5.53.7 + svelte: 5.54.1 tiny-glob: 0.2.9 - svelte-jsoneditor@3.11.0(svelte@5.53.7): + svelte-jsoneditor@3.11.0(svelte@5.54.1): dependencies: '@codemirror/autocomplete': 6.20.0 '@codemirror/commands': 6.10.1 @@ -24471,42 +24730,42 @@ snapshots: memoize-one: 6.0.0 natural-compare-lite: 1.4.0 sass: 1.97.1 - svelte: 5.53.7 - svelte-awesome: 3.3.5(svelte@5.53.7) + svelte: 5.54.1 + svelte-awesome: 3.3.5(svelte@5.54.1) svelte-select: 5.8.3 vanilla-picker: 2.12.3 - svelte-maplibre@1.2.6(svelte@5.53.7): + svelte-maplibre@1.2.6(svelte@5.54.1): dependencies: d3-geo: 3.1.1 dequal: 2.0.3 just-compare: 2.3.0 - maplibre-gl: 5.19.0 + maplibre-gl: 5.21.0 pmtiles: 3.2.1 - svelte: 5.53.7 + svelte: 5.54.1 - svelte-parse-markup@0.1.5(svelte@5.53.7): + svelte-parse-markup@0.1.5(svelte@5.54.1): dependencies: - svelte: 5.53.7 + svelte: 5.54.1 - svelte-persisted-store@0.12.0(svelte@5.53.7): + svelte-persisted-store@0.12.0(svelte@5.54.1): dependencies: - svelte: 5.53.7 + svelte: 5.54.1 svelte-select@5.8.3: dependencies: svelte-floating-ui: 1.5.8 - svelte-toolbelt@0.10.6(@sveltejs/kit@2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.7)(vite@7.3.1(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(svelte@5.53.7)(typescript@5.9.3)(vite@7.3.1(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(svelte@5.53.7): + svelte-toolbelt@0.10.6(@sveltejs/kit@2.55.0(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.54.1)(vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)))(svelte@5.54.1)(typescript@5.9.3)(vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)))(svelte@5.54.1): dependencies: clsx: 2.1.1 - runed: 0.35.1(@sveltejs/kit@2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.7)(vite@7.3.1(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(svelte@5.53.7)(typescript@5.9.3)(vite@7.3.1(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(svelte@5.53.7) + runed: 0.35.1(@sveltejs/kit@2.55.0(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.54.1)(vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)))(svelte@5.54.1)(typescript@5.9.3)(vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)))(svelte@5.54.1) style-to-object: 1.0.14 - svelte: 5.53.7 + svelte: 5.54.1 transitivePeerDependencies: - '@sveltejs/kit' - svelte@5.53.7: + svelte@5.54.1: dependencies: '@jridgewell/remapping': 2.3.5 '@jridgewell/sourcemap-codec': 1.5.5 @@ -24517,7 +24776,7 @@ snapshots: aria-query: 5.3.1 axobject-query: 4.1.0 clsx: 2.1.1 - devalue: 5.6.3 + devalue: 5.6.4 esm-env: 1.2.2 esrap: 2.2.3 is-reference: 3.0.3 @@ -24562,27 +24821,27 @@ snapshots: tailwind-merge@3.5.0: {} - tailwind-variants@3.2.2(tailwind-merge@3.5.0)(tailwindcss@4.2.1): + tailwind-variants@3.2.2(tailwind-merge@3.5.0)(tailwindcss@4.2.2): dependencies: - tailwindcss: 4.2.1 + tailwindcss: 4.2.2 optionalDependencies: tailwind-merge: 3.5.0 - tailwindcss-email-variants@3.0.5(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.2)): + tailwindcss-email-variants@3.0.5(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.3)): dependencies: - tailwindcss: 3.4.19(tsx@4.21.0)(yaml@2.8.2) + tailwindcss: 3.4.19(tsx@4.21.0)(yaml@2.8.3) - tailwindcss-mso@2.0.3(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.2)): + tailwindcss-mso@2.0.3(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.3)): dependencies: - tailwindcss: 3.4.19(tsx@4.21.0)(yaml@2.8.2) + tailwindcss: 3.4.19(tsx@4.21.0)(yaml@2.8.3) - tailwindcss-preset-email@1.4.1(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.2)): + tailwindcss-preset-email@1.4.1(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.3)): dependencies: - tailwindcss: 3.4.19(tsx@4.21.0)(yaml@2.8.2) - tailwindcss-email-variants: 3.0.5(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.2)) - tailwindcss-mso: 2.0.3(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.2)) + tailwindcss: 3.4.19(tsx@4.21.0)(yaml@2.8.3) + tailwindcss-email-variants: 3.0.5(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.3)) + tailwindcss-mso: 2.0.3(tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.3)) - tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.2): + tailwindcss@3.4.19(tsx@4.21.0)(yaml@2.8.3): dependencies: '@alloc/quick-lru': 5.2.0 arg: 5.0.2 @@ -24601,7 +24860,7 @@ snapshots: postcss: 8.5.8 postcss-import: 15.1.0(postcss@8.5.8) postcss-js: 4.1.0(postcss@8.5.8) - postcss-load-config: 6.0.1(jiti@1.21.7)(postcss@8.5.8)(tsx@4.21.0)(yaml@2.8.2) + postcss-load-config: 6.0.1(jiti@1.21.7)(postcss@8.5.8)(tsx@4.21.0)(yaml@2.8.3) postcss-nested: 6.2.0(postcss@8.5.8) postcss-selector-parser: 6.1.2 resolve: 1.22.11 @@ -24610,7 +24869,7 @@ snapshots: - tsx - yaml - tailwindcss@4.2.1: {} + tailwindcss@4.2.2: {} tapable@2.3.0: {} @@ -24618,15 +24877,15 @@ snapshots: dependencies: chownr: 1.1.4 mkdirp-classic: 0.5.3 - pump: 3.0.3 + pump: 3.0.4 tar-stream: 2.2.0 - tar-fs@3.1.1: + tar-fs@3.1.2: dependencies: - pump: 3.0.3 - tar-stream: 3.1.7 + pump: 3.0.4 + tar-stream: 3.1.8 optionalDependencies: - bare-fs: 4.5.4 + bare-fs: 4.5.6 bare-path: 3.0.0 transitivePeerDependencies: - bare-abort-controller @@ -24641,13 +24900,15 @@ snapshots: inherits: 2.0.4 readable-stream: 3.6.2 - tar-stream@3.1.7: + tar-stream@3.1.8: dependencies: - b4a: 1.7.3 + b4a: 1.8.0 + bare-fs: 4.5.6 fast-fifo: 1.3.2 - streamx: 2.23.0 + streamx: 2.25.0 transitivePeerDependencies: - bare-abort-controller + - bare-buffer - react-native-b4a tar@6.2.1: @@ -24669,22 +24930,22 @@ snapshots: teex@1.0.1: dependencies: - streamx: 2.23.0 + streamx: 2.25.0 transitivePeerDependencies: - bare-abort-controller - react-native-b4a - optional: true - terser-webpack-plugin@5.3.16(@swc/core@1.15.18(@swc/helpers@0.5.17))(webpack@5.104.1(@swc/core@1.15.18(@swc/helpers@0.5.17))): + terser-webpack-plugin@5.3.16(@swc/core@1.15.18(@swc/helpers@0.5.17))(esbuild@0.27.4)(webpack@5.104.1(@swc/core@1.15.18(@swc/helpers@0.5.17))(esbuild@0.27.4)): dependencies: '@jridgewell/trace-mapping': 0.3.31 jest-worker: 27.5.1 schema-utils: 4.3.3 serialize-javascript: 6.0.2 terser: 5.44.1 - webpack: 5.104.1(@swc/core@1.15.18(@swc/helpers@0.5.17)) + webpack: 5.104.1(@swc/core@1.15.18(@swc/helpers@0.5.17))(esbuild@0.27.4) optionalDependencies: '@swc/core': 1.15.18(@swc/helpers@0.5.17) + esbuild: 0.27.4 terser-webpack-plugin@5.3.16(webpack@5.104.1): dependencies: @@ -24708,7 +24969,7 @@ snapshots: glob: 10.5.0 minimatch: 10.2.4 - testcontainers@11.12.0: + testcontainers@11.13.0: dependencies: '@balena/dockerignore': 1.0.2 '@types/dockerode': 4.0.1 @@ -24716,24 +24977,24 @@ snapshots: async-lock: 1.4.1 byline: 5.0.0 debug: 4.4.3 - docker-compose: 1.3.1 - dockerode: 4.0.9 - get-port: 7.1.0 + docker-compose: 1.3.3 + dockerode: 4.0.10 + get-port: 7.2.0 proper-lockfile: 4.1.2 properties-reader: 3.0.1 ssh-remote-port-forward: 1.0.4 - tar-fs: 3.1.1 + tar-fs: 3.1.2 tmp: 0.2.5 - undici: 7.22.0 + undici: 7.24.6 transitivePeerDependencies: - bare-abort-controller - bare-buffer - react-native-b4a - supports-color - text-decoder@1.2.3: + text-decoder@1.2.7: dependencies: - b4a: 1.7.3 + b4a: 1.8.0 transitivePeerDependencies: - react-native-b4a @@ -24781,12 +25042,12 @@ snapshots: tinyexec@0.3.2: {} - tinyexec@1.0.2: {} + tinyexec@1.0.4: {} tinyglobby@0.2.15: dependencies: - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 + fdir: 6.5.0(picomatch@4.0.4) + picomatch: 4.0.4 tinypool@1.1.1: {} @@ -24794,7 +25055,7 @@ snapshots: tinyrainbow@2.0.0: {} - tinyrainbow@3.0.3: {} + tinyrainbow@3.1.0: {} tinyspy@4.0.4: {} @@ -24821,7 +25082,7 @@ snapshots: token-types@6.1.2: dependencies: - '@borewit/text-codec': 0.2.1 + '@borewit/text-codec': 0.2.2 '@tokenizer/token': 0.3.0 ieee754: 1.2.1 @@ -24855,7 +25116,7 @@ snapshots: dependencies: utf8-byte-length: 1.0.5 - ts-api-utils@2.4.0(typescript@5.9.3): + ts-api-utils@2.5.0(typescript@5.9.3): dependencies: typescript: 5.9.3 @@ -24886,7 +25147,7 @@ snapshots: tsx@4.21.0: dependencies: - esbuild: 0.27.3 + esbuild: 0.27.4 get-tsconfig: 4.13.0 optionalDependencies: fsevents: 2.3.3 @@ -24922,13 +25183,13 @@ snapshots: typedarray@0.0.6: {} - typescript-eslint@8.56.1(eslint@10.0.2(jiti@2.6.1))(typescript@5.9.3): + typescript-eslint@8.57.1(eslint@10.1.0(jiti@2.6.1))(typescript@5.9.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.56.1(@typescript-eslint/parser@8.56.1(eslint@10.0.2(jiti@2.6.1))(typescript@5.9.3))(eslint@10.0.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/parser': 8.56.1(eslint@10.0.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/typescript-estree': 8.56.1(typescript@5.9.3) - '@typescript-eslint/utils': 8.56.1(eslint@10.0.2(jiti@2.6.1))(typescript@5.9.3) - eslint: 10.0.2(jiti@2.6.1) + '@typescript-eslint/eslint-plugin': 8.57.1(@typescript-eslint/parser@8.57.1(eslint@10.1.0(jiti@2.6.1))(typescript@5.9.3))(eslint@10.1.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/parser': 8.57.1(eslint@10.1.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/typescript-estree': 8.57.1(typescript@5.9.3) + '@typescript-eslint/utils': 8.57.1(eslint@10.1.0(jiti@2.6.1))(typescript@5.9.3) + eslint: 10.1.0(jiti@2.6.1) typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -24963,7 +25224,7 @@ snapshots: undici-types@7.18.2: optional: true - undici@7.22.0: {} + undici@7.24.6: {} unicode-canonical-property-names-ecmascript@2.0.1: {} @@ -25075,7 +25336,7 @@ snapshots: dependencies: '@jridgewell/remapping': 2.3.5 acorn: 8.16.0 - picomatch: 4.0.3 + picomatch: 4.0.4 webpack-virtual-modules: 0.6.2 update-browserslist-db@1.2.3(browserslist@4.28.1): @@ -25199,13 +25460,13 @@ snapshots: - rollup - supports-color - vite-node@3.2.4(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2): + vite-node@3.2.4(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3): dependencies: cac: 6.7.14 debug: 4.4.3 es-module-lexer: 1.7.0 pathe: 2.0.3 - vite: 7.3.1(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + vite: 7.3.1(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3) transitivePeerDependencies: - '@types/node' - jiti @@ -25220,21 +25481,21 @@ snapshots: - tsx - yaml - vite-tsconfig-paths@6.1.1(typescript@5.9.3)(vite@7.3.1(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)): + vite-tsconfig-paths@6.1.1(typescript@5.9.3)(vite@8.0.1(@types/node@24.12.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)): dependencies: debug: 4.4.3 globrex: 0.1.2 tsconfck: 3.1.6(typescript@5.9.3) - vite: 7.3.1(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + vite: 8.0.1(@types/node@24.12.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3) transitivePeerDependencies: - supports-color - typescript - vite@7.3.1(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2): + vite@7.3.1(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3): dependencies: - esbuild: 0.27.3 - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 + esbuild: 0.27.4 + fdir: 6.5.0(picomatch@4.0.4) + picomatch: 4.0.4 postcss: 8.5.8 rollup: 4.55.1 tinyglobby: 0.2.15 @@ -25242,43 +25503,59 @@ snapshots: '@types/node': 24.12.0 fsevents: 2.3.3 jiti: 2.6.1 - lightningcss: 1.31.1 + lightningcss: 1.32.0 sass: 1.97.1 terser: 5.44.1 tsx: 4.21.0 - yaml: 2.8.2 + yaml: 2.8.3 - vite@7.3.1(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2): + vite@8.0.1(@types/node@24.12.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3): dependencies: - esbuild: 0.27.3 - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 + lightningcss: 1.32.0 + picomatch: 4.0.4 postcss: 8.5.8 - rollup: 4.55.1 + rolldown: 1.0.0-rc.10 tinyglobby: 0.2.15 optionalDependencies: - '@types/node': 25.4.0 + '@types/node': 24.12.0 + esbuild: 0.27.4 fsevents: 2.3.3 jiti: 2.6.1 - lightningcss: 1.31.1 sass: 1.97.1 terser: 5.44.1 tsx: 4.21.0 - yaml: 2.8.2 + yaml: 2.8.3 - vitefu@1.1.1(vite@7.3.1(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)): - optionalDependencies: - vite: 7.3.1(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) - - vitest-fetch-mock@0.4.5(vitest@4.0.18(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.3)(jiti@2.6.1)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)): + vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3): dependencies: - vitest: 4.0.18(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.3)(jiti@2.6.1)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + lightningcss: 1.32.0 + picomatch: 4.0.4 + postcss: 8.5.8 + rolldown: 1.0.0-rc.10 + tinyglobby: 0.2.15 + optionalDependencies: + '@types/node': 25.5.0 + esbuild: 0.27.4 + fsevents: 2.3.3 + jiti: 2.6.1 + sass: 1.97.1 + terser: 5.44.1 + tsx: 4.21.0 + yaml: 2.8.3 - vitest@3.2.4(@types/debug@4.1.12)(@types/node@24.12.0)(happy-dom@20.8.3)(jiti@2.6.1)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2): + vitefu@1.1.2(vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)): + optionalDependencies: + vite: 8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3) + + vitest-fetch-mock@0.4.5(vitest@4.1.0(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.4)(jsdom@26.1.0(canvas@2.11.2))(vite@8.0.1(@types/node@24.12.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3))): + dependencies: + vitest: 4.1.0(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.4)(jsdom@26.1.0(canvas@2.11.2))(vite@8.0.1(@types/node@24.12.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + + vitest@3.2.4(@types/debug@4.1.12)(@types/node@24.12.0)(happy-dom@20.8.4)(jiti@2.6.1)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.32.0)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3): dependencies: '@types/chai': 5.2.3 '@vitest/expect': 3.2.4 - '@vitest/mocker': 3.2.4(vite@7.3.1(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + '@vitest/mocker': 3.2.4(vite@7.3.1(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) '@vitest/pretty-format': 3.2.4 '@vitest/runner': 3.2.4 '@vitest/snapshot': 3.2.4 @@ -25289,20 +25566,20 @@ snapshots: expect-type: 1.3.0 magic-string: 0.30.21 pathe: 2.0.3 - picomatch: 4.0.3 + picomatch: 4.0.4 std-env: 3.10.0 tinybench: 2.9.0 tinyexec: 0.3.2 tinyglobby: 0.2.15 tinypool: 1.1.1 tinyrainbow: 2.0.0 - vite: 7.3.1(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) - vite-node: 3.2.4(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + vite: 7.3.1(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3) + vite-node: 3.2.4(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3) why-is-node-running: 2.3.0 optionalDependencies: '@types/debug': 4.1.12 '@types/node': 24.12.0 - happy-dom: 20.8.3 + happy-dom: 20.8.4 jsdom: 26.1.0(canvas@2.11.2) transitivePeerDependencies: - jiti @@ -25318,125 +25595,95 @@ snapshots: - tsx - yaml - vitest@4.0.18(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.3)(jiti@2.6.1)(jsdom@26.1.0(canvas@2.11.2(encoding@0.1.13)))(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2): + vitest@4.1.0(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.4)(jsdom@26.1.0(canvas@2.11.2(encoding@0.1.13)))(vite@8.0.1(@types/node@24.12.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)): dependencies: - '@vitest/expect': 4.0.18 - '@vitest/mocker': 4.0.18(vite@7.3.1(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) - '@vitest/pretty-format': 4.0.18 - '@vitest/runner': 4.0.18 - '@vitest/snapshot': 4.0.18 - '@vitest/spy': 4.0.18 - '@vitest/utils': 4.0.18 - es-module-lexer: 1.7.0 + '@vitest/expect': 4.1.0 + '@vitest/mocker': 4.1.0(vite@8.0.1(@types/node@24.12.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + '@vitest/pretty-format': 4.1.0 + '@vitest/runner': 4.1.0 + '@vitest/snapshot': 4.1.0 + '@vitest/spy': 4.1.0 + '@vitest/utils': 4.1.0 + es-module-lexer: 2.0.0 expect-type: 1.3.0 magic-string: 0.30.21 obug: 2.1.1 pathe: 2.0.3 - picomatch: 4.0.3 - std-env: 3.10.0 + picomatch: 4.0.4 + std-env: 4.0.0 tinybench: 2.9.0 - tinyexec: 1.0.2 + tinyexec: 1.0.4 tinyglobby: 0.2.15 - tinyrainbow: 3.0.3 - vite: 7.3.1(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + tinyrainbow: 3.1.0 + vite: 8.0.1(@types/node@24.12.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3) why-is-node-running: 2.3.0 optionalDependencies: '@opentelemetry/api': 1.9.0 '@types/node': 24.12.0 - happy-dom: 20.8.3 + happy-dom: 20.8.4 jsdom: 26.1.0(canvas@2.11.2(encoding@0.1.13)) transitivePeerDependencies: - - jiti - - less - - lightningcss - msw - - sass - - sass-embedded - - stylus - - sugarss - - terser - - tsx - - yaml - vitest@4.0.18(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.3)(jiti@2.6.1)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2): + vitest@4.1.0(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.4)(jsdom@26.1.0(canvas@2.11.2))(vite@8.0.1(@types/node@24.12.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)): dependencies: - '@vitest/expect': 4.0.18 - '@vitest/mocker': 4.0.18(vite@7.3.1(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) - '@vitest/pretty-format': 4.0.18 - '@vitest/runner': 4.0.18 - '@vitest/snapshot': 4.0.18 - '@vitest/spy': 4.0.18 - '@vitest/utils': 4.0.18 - es-module-lexer: 1.7.0 + '@vitest/expect': 4.1.0 + '@vitest/mocker': 4.1.0(vite@8.0.1(@types/node@24.12.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + '@vitest/pretty-format': 4.1.0 + '@vitest/runner': 4.1.0 + '@vitest/snapshot': 4.1.0 + '@vitest/spy': 4.1.0 + '@vitest/utils': 4.1.0 + es-module-lexer: 2.0.0 expect-type: 1.3.0 magic-string: 0.30.21 obug: 2.1.1 pathe: 2.0.3 - picomatch: 4.0.3 - std-env: 3.10.0 + picomatch: 4.0.4 + std-env: 4.0.0 tinybench: 2.9.0 - tinyexec: 1.0.2 + tinyexec: 1.0.4 tinyglobby: 0.2.15 - tinyrainbow: 3.0.3 - vite: 7.3.1(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + tinyrainbow: 3.1.0 + vite: 8.0.1(@types/node@24.12.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3) why-is-node-running: 2.3.0 optionalDependencies: '@opentelemetry/api': 1.9.0 '@types/node': 24.12.0 - happy-dom: 20.8.3 + happy-dom: 20.8.4 jsdom: 26.1.0(canvas@2.11.2) transitivePeerDependencies: - - jiti - - less - - lightningcss - msw - - sass - - sass-embedded - - stylus - - sugarss - - terser - - tsx - - yaml - vitest@4.0.18(@opentelemetry/api@1.9.0)(@types/node@25.4.0)(happy-dom@20.8.3)(jiti@2.6.1)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2): + vitest@4.1.0(@opentelemetry/api@1.9.0)(@types/node@25.5.0)(happy-dom@20.8.4)(jsdom@26.1.0(canvas@2.11.2))(vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)): dependencies: - '@vitest/expect': 4.0.18 - '@vitest/mocker': 4.0.18(vite@7.3.1(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) - '@vitest/pretty-format': 4.0.18 - '@vitest/runner': 4.0.18 - '@vitest/snapshot': 4.0.18 - '@vitest/spy': 4.0.18 - '@vitest/utils': 4.0.18 - es-module-lexer: 1.7.0 + '@vitest/expect': 4.1.0 + '@vitest/mocker': 4.1.0(vite@8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) + '@vitest/pretty-format': 4.1.0 + '@vitest/runner': 4.1.0 + '@vitest/snapshot': 4.1.0 + '@vitest/spy': 4.1.0 + '@vitest/utils': 4.1.0 + es-module-lexer: 2.0.0 expect-type: 1.3.0 magic-string: 0.30.21 obug: 2.1.1 pathe: 2.0.3 - picomatch: 4.0.3 - std-env: 3.10.0 + picomatch: 4.0.4 + std-env: 4.0.0 tinybench: 2.9.0 - tinyexec: 1.0.2 + tinyexec: 1.0.4 tinyglobby: 0.2.15 - tinyrainbow: 3.0.3 - vite: 7.3.1(@types/node@25.4.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + tinyrainbow: 3.1.0 + vite: 8.0.1(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3) why-is-node-running: 2.3.0 optionalDependencies: '@opentelemetry/api': 1.9.0 - '@types/node': 25.4.0 - happy-dom: 20.8.3 + '@types/node': 25.5.0 + happy-dom: 20.8.4 jsdom: 26.1.0(canvas@2.11.2) transitivePeerDependencies: - - jiti - - less - - lightningcss - msw - - sass - - sass-embedded - - stylus - - sugarss - - terser - - tsx - - yaml vscode-jsonrpc@8.2.0: {} @@ -25542,7 +25789,7 @@ snapshots: sockjs: 0.3.24 spdy: 4.0.2 webpack-dev-middleware: 7.4.5(webpack@5.104.1) - ws: 8.19.0 + ws: 8.20.0 optionalDependencies: webpack: 5.104.1 transitivePeerDependencies: @@ -25601,7 +25848,7 @@ snapshots: - esbuild - uglify-js - webpack@5.104.1(@swc/core@1.15.18(@swc/helpers@0.5.17)): + webpack@5.104.1(@swc/core@1.15.18(@swc/helpers@0.5.17))(esbuild@0.27.4): dependencies: '@types/eslint-scope': 3.7.7 '@types/estree': 1.0.8 @@ -25625,7 +25872,7 @@ snapshots: neo-async: 2.6.2 schema-utils: 4.3.3 tapable: 2.3.0 - terser-webpack-plugin: 5.3.16(@swc/core@1.15.18(@swc/helpers@0.5.17))(webpack@5.104.1(@swc/core@1.15.18(@swc/helpers@0.5.17))) + terser-webpack-plugin: 5.3.16(@swc/core@1.15.18(@swc/helpers@0.5.17))(esbuild@0.27.4)(webpack@5.104.1(@swc/core@1.15.18(@swc/helpers@0.5.17))(esbuild@0.27.4)) watchpack: 2.5.1 webpack-sources: 3.3.3 transitivePeerDependencies: @@ -25738,7 +25985,7 @@ snapshots: ws@8.18.3: {} - ws@8.19.0: {} + ws@8.20.0: {} wsl-utils@0.1.0: dependencies: @@ -25770,9 +26017,9 @@ snapshots: yallist@5.0.0: {} - yaml@1.10.2: {} + yaml@1.10.3: {} - yaml@2.8.2: {} + yaml@2.8.3: {} yargs-parser@18.1.3: dependencies: diff --git a/renovate.json b/renovate.json index fbbc8976bd..0fdf5a7f69 100644 --- a/renovate.json +++ b/renovate.json @@ -27,6 +27,10 @@ "matchUpdateTypes": ["major"], "enabled": false }, + { + "matchPackageNames": ["ghcr.io/immich-app/base-server-*"], + "maxMajorIncrement": 0 + }, { "matchPackageNames": ["ruby"], "groupName": "ruby", diff --git a/server/.nvmrc b/server/.nvmrc index 32f8c50de0..d845d9d88d 100644 --- a/server/.nvmrc +++ b/server/.nvmrc @@ -1 +1 @@ -24.13.1 +24.14.0 diff --git a/server/Dockerfile b/server/Dockerfile index 9cc53c1095..476d58b983 100644 --- a/server/Dockerfile +++ b/server/Dockerfile @@ -1,4 +1,4 @@ -FROM ghcr.io/immich-app/base-server-dev:202603031112@sha256:837536db5fd9e432f0f474ef9b61712fe3b3815821c3e4edf5e5b0b1f1ed30ad AS builder +FROM ghcr.io/immich-app/base-server-dev:202603251709@sha256:2bf3053c732fcb87ec90c3c614632ac44847423468ccc57fd935bff771828d9d AS builder ENV COREPACK_ENABLE_DOWNLOAD_PROMPT=0 \ CI=1 \ COREPACK_HOME=/tmp \ @@ -52,7 +52,7 @@ FROM builder AS plugins ARG TARGETPLATFORM -COPY --from=ghcr.io/jdx/mise:2026.1.1@sha256:a55c391f7582f34c58bce1a85090cd526596402ba77fc32b06c49b8404ef9c14 /usr/local/bin/mise /usr/local/bin/mise +COPY --from=ghcr.io/jdx/mise:2026.3.12@sha256:0210678cbf58413806531a27adb2c7daf1c37238e56e8f7ea381d73521571775 /usr/local/bin/mise /usr/local/bin/mise WORKDIR /usr/src/app COPY ./plugins/mise.toml ./plugins/ @@ -71,7 +71,7 @@ RUN --mount=type=cache,id=pnpm-plugins,target=/buildcache/pnpm-store \ --mount=type=cache,id=mise-tools-${TARGETPLATFORM},target=/buildcache/mise \ cd plugins && mise run build -FROM ghcr.io/immich-app/base-server-prod:202603031112@sha256:bb8c8645ee61977140121e56ba09db7ae656a7506f9a6af1be8461b4d81fdf03 +FROM ghcr.io/immich-app/base-server-prod:202603251709@sha256:17de30977ff87aa06758a56ad7f10d6b5c97bf9dab76e4ec4177a2a8d1b2b5f3 WORKDIR /usr/src/app ENV NODE_ENV=production \ diff --git a/server/Dockerfile.dev b/server/Dockerfile.dev index f64a1a904b..096ffdf0bf 100644 --- a/server/Dockerfile.dev +++ b/server/Dockerfile.dev @@ -1,5 +1,5 @@ # dev build -FROM ghcr.io/immich-app/base-server-dev:202603031112@sha256:837536db5fd9e432f0f474ef9b61712fe3b3815821c3e4edf5e5b0b1f1ed30ad AS dev +FROM ghcr.io/immich-app/base-server-dev:202603251709@sha256:2bf3053c732fcb87ec90c3c614632ac44847423468ccc57fd935bff771828d9d AS dev ENV COREPACK_ENABLE_DOWNLOAD_PROMPT=0 \ CI=1 \ diff --git a/server/bin/start.sh b/server/bin/start.sh index 0a26be8e0b..15f4411959 100755 --- a/server/bin/start.sh +++ b/server/bin/start.sh @@ -15,13 +15,12 @@ log_message() { log_message "Initializing Immich $IMMICH_SOURCE_REF" -# TODO: Update to mimalloc v3 when verified memory isn't released issue is fixed -# lib_path="/usr/lib/$(arch)-linux-gnu/libmimalloc.so.3" -# if [ -f "$lib_path" ]; then -# export LD_PRELOAD="$lib_path" -# else -# echo "skipping libmimalloc - path not found $lib_path" -# fi +lib_path="/usr/lib/$(arch)-linux-gnu/libmimalloc.so.3" +if [ -f "$lib_path" ]; then + export LD_PRELOAD="$lib_path" +else + echo "skipping libmimalloc - path not found $lib_path" +fi export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/usr/lib/jellyfin-ffmpeg/lib" SERVER_HOME="$(readlink -f "$(dirname "$0")/..")" diff --git a/server/helmet.json b/server/helmet.json new file mode 100644 index 0000000000..ec31752a52 --- /dev/null +++ b/server/helmet.json @@ -0,0 +1,21 @@ +{ + "contentSecurityPolicy": { + "directives": { + "default-src": ["'self'"], + "script-src": ["'self'", "'wasm-unsafe-eval", "'unsafe-inline'", "https://www.gstatic.com"], + "style-src": ["'self'", "'unsafe-inline'"], + "img-src": ["'self'", "'data:'", "'blob:'"], + "connect-src": [ + "'self'", + "blob:", + "https://pay.futo.org", + "https://static.immich.cloud", + "https://tiles.immich.cloud" + ], + "worker-src": ["'self'", "blob:"], + "frame-src": ["'none'"], + "object-src": ["'none'"], + "base-uri": ["'self'"] + } + } +} diff --git a/server/package.json b/server/package.json index 0af90c4ae5..8c4a65bb57 100644 --- a/server/package.json +++ b/server/package.json @@ -1,10 +1,15 @@ { "name": "immich", - "version": "2.6.1", + "version": "2.6.3", "description": "", "author": "", "private": true, "license": "GNU Affero General Public License version 3", + "files": [ + "bin", + "dist", + "helmet.json" + ], "scripts": { "build": "nest build", "format": "prettier --cache --check .", @@ -24,7 +29,7 @@ "typeorm": "typeorm", "migrations:debug": "sql-tools -u ${DB_URL:-postgres://postgres:postgres@localhost:5432/immich} migrations generate --debug", "migrations:generate": "sql-tools -u ${DB_URL:-postgres://postgres:postgres@localhost:5432/immich} migrations generate", - "migrations:create": "sql-tools -u ${DB_URL:-postgres://postgres:postgres@localhost:5432/immich} migrations generate", + "migrations:create": "sql-tools -u ${DB_URL:-postgres://postgres:postgres@localhost:5432/immich} migrations create", "migrations:run": "sql-tools -u ${DB_URL:-postgres://postgres:postgres@localhost:5432/immich} migrations run", "migrations:revert": "sql-tools -u ${DB_URL:-postgres://postgres:postgres@localhost:5432/immich} migrations revert", "schema:drop": "sql-tools -u ${DB_URL:-postgres://postgres:postgres@localhost:5432/immich} query 'DROP schema public cascade; CREATE schema public;'", @@ -77,12 +82,13 @@ "fluent-ffmpeg": "^2.1.2", "geo-tz": "^8.0.0", "handlebars": "^4.7.8", + "helmet": "^8.1.0", "i18n-iso-countries": "^7.6.0", "ioredis": "^5.8.2", "jose": "^5.10.0", "js-yaml": "^4.1.0", "jsonwebtoken": "^9.0.2", - "kysely": "0.28.11", + "kysely": "0.28.14", "kysely-postgres-js": "^3.0.0", "lodash": "^4.17.21", "luxon": "^3.4.2", @@ -136,7 +142,7 @@ "@types/luxon": "^3.6.2", "@types/mock-fs": "^4.13.1", "@types/multer": "^2.0.0", - "@types/node": "^24.11.0", + "@types/node": "^24.12.0", "@types/nodemailer": "^7.0.0", "@types/picomatch": "^4.0.0", "@types/pngjs": "^6.0.5", @@ -168,7 +174,7 @@ "vitest": "^3.0.0" }, "volta": { - "node": "24.13.1" + "node": "24.14.0" }, "overrides": { "sharp": "^0.34.5" diff --git a/server/resources/style-dark.json b/server/resources/style-dark.json deleted file mode 100644 index 91148e7814..0000000000 --- a/server/resources/style-dark.json +++ /dev/null @@ -1,3180 +0,0 @@ -{ - "version": 8, - "name": "Immich Map", - "id": "immich-map-dark", - "sources": { - "protomaps": { - "type": "vector", - "url": "https://tiles.immich.cloud/v1.json" - } - }, - "layers": [ - { - "id": "background", - "type": "background", - "paint": { - "background-color": "#2b2b2b" - } - }, - { - "id": "earth", - "type": "fill", - "source": "protomaps", - "source-layer": "earth", - "paint": { - "fill-color": "#141414" - } - }, - { - "id": "landuse_park", - "type": "fill", - "source": "protomaps", - "source-layer": "landuse", - "filter": [ - "any", - [ - "in", - "pmap:kind", - "national_park", - "park", - "cemetery", - "protected_area", - "nature_reserve", - "forest", - "golf_course" - ] - ], - "paint": { - "fill-color": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 0, - "#181818", - 12, - "#181818" - ] - } - }, - { - "id": "landuse_urban_green", - "type": "fill", - "source": "protomaps", - "source-layer": "landuse", - "filter": [ - "any", - [ - "in", - "pmap:kind", - "allotments", - "village_green", - "playground" - ] - ], - "paint": { - "fill-color": "#181818", - "fill-opacity": 0.7 - } - }, - { - "id": "landuse_hospital", - "type": "fill", - "source": "protomaps", - "source-layer": "landuse", - "filter": [ - "any", - [ - "==", - "pmap:kind", - "hospital" - ] - ], - "paint": { - "fill-color": "#1d1d1d" - } - }, - { - "id": "landuse_industrial", - "type": "fill", - "source": "protomaps", - "source-layer": "landuse", - "filter": [ - "any", - [ - "==", - "pmap:kind", - "industrial" - ] - ], - "paint": { - "fill-color": "#101010" - } - }, - { - "id": "landuse_school", - "type": "fill", - "source": "protomaps", - "source-layer": "landuse", - "filter": [ - "any", - [ - "in", - "pmap:kind", - "school", - "university", - "college" - ] - ], - "paint": { - "fill-color": "#111111" - } - }, - { - "id": "landuse_beach", - "type": "fill", - "source": "protomaps", - "source-layer": "landuse", - "filter": [ - "any", - [ - "in", - "pmap:kind", - "beach" - ] - ], - "paint": { - "fill-color": "#1f1f1f" - } - }, - { - "id": "landuse_zoo", - "type": "fill", - "source": "protomaps", - "source-layer": "landuse", - "filter": [ - "any", - [ - "in", - "pmap:kind", - "zoo" - ] - ], - "paint": { - "fill-color": "#191919" - } - }, - { - "id": "landuse_military", - "type": "fill", - "source": "protomaps", - "source-layer": "landuse", - "filter": [ - "any", - [ - "in", - "pmap:kind", - "military", - "naval_base", - "airfield" - ] - ], - "paint": { - "fill-color": "#191919" - } - }, - { - "id": "natural_wood", - "type": "fill", - "source": "protomaps", - "source-layer": "natural", - "filter": [ - "any", - [ - "in", - "pmap:kind", - "wood", - "nature_reserve", - "forest" - ] - ], - "paint": { - "fill-color": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 0, - "#1a1a1a", - 12, - "#1a1a1a" - ] - } - }, - { - "id": "natural_scrub", - "type": "fill", - "source": "protomaps", - "source-layer": "natural", - "filter": [ - "in", - "pmap:kind", - "scrub", - "grassland", - "grass" - ], - "paint": { - "fill-color": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 0, - "#1c1c1c", - 12, - "#1c1c1c" - ] - } - }, - { - "id": "natural_glacier", - "type": "fill", - "source": "protomaps", - "source-layer": "natural", - "filter": [ - "==", - "pmap:kind", - "glacier" - ], - "paint": { - "fill-color": "#191919" - } - }, - { - "id": "natural_sand", - "type": "fill", - "source": "protomaps", - "source-layer": "natural", - "filter": [ - "==", - "pmap:kind", - "sand" - ], - "paint": { - "fill-color": "#161616" - } - }, - { - "id": "landuse_aerodrome", - "type": "fill", - "source": "protomaps", - "source-layer": "landuse", - "filter": [ - "any", - [ - "in", - "pmap:kind", - "aerodrome" - ] - ], - "paint": { - "fill-color": "#191919" - } - }, - { - "id": "transit_runway", - "type": "line", - "source": "protomaps", - "source-layer": "transit", - "filter": [ - "any", - [ - "in", - "pmap:kind_detail", - "runway" - ] - ], - "paint": { - "line-color": "#323232", - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 10, - 0, - 12, - 4, - 18, - 30 - ] - } - }, - { - "id": "transit_taxiway", - "type": "line", - "source": "protomaps", - "source-layer": "transit", - "minzoom": 13, - "filter": [ - "any", - [ - "in", - "pmap:kind_detail", - "taxiway" - ] - ], - "paint": { - "line-color": "#323232", - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 13, - 0, - 13.5, - 1, - 15, - 6 - ] - } - }, - { - "id": "water", - "type": "fill", - "source": "protomaps", - "source-layer": "water", - "paint": { - "fill-color": "#333333" - } - }, - { - "id": "physical_line_stream", - "type": "line", - "source": "protomaps", - "source-layer": "physical_line", - "minzoom": 14, - "filter": [ - "all", - [ - "in", - "pmap:kind", - "stream" - ] - ], - "paint": { - "line-color": "#333333", - "line-width": 0.5 - } - }, - { - "id": "physical_line_river", - "type": "line", - "source": "protomaps", - "source-layer": "physical_line", - "minzoom": 9, - "filter": [ - "all", - [ - "in", - "pmap:kind", - "river" - ] - ], - "paint": { - "line-color": "#333333", - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 9, - 0, - 9.5, - 1, - 18, - 12 - ] - } - }, - { - "id": "landuse_pedestrian", - "type": "fill", - "source": "protomaps", - "source-layer": "landuse", - "filter": [ - "any", - [ - "==", - "pmap:kind", - "pedestrian" - ] - ], - "paint": { - "fill-color": "#191919" - } - }, - { - "id": "landuse_pier", - "type": "fill", - "source": "protomaps", - "source-layer": "landuse", - "filter": [ - "any", - [ - "==", - "pmap:kind", - "pier" - ] - ], - "paint": { - "fill-color": "#0a0a0a" - } - }, - { - "id": "roads_tunnels_other_casing", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "filter": [ - "all", - [ - "<", - "pmap:level", - 0 - ], - [ - "in", - "pmap:kind", - "other", - "path" - ] - ], - "paint": { - "line-color": "#101010", - "line-gap-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 14, - 0, - 20, - 7 - ] - } - }, - { - "id": "roads_tunnels_minor_casing", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "filter": [ - "all", - [ - "<", - "pmap:level", - 0 - ], - [ - "==", - "pmap:kind", - "minor_road" - ] - ], - "paint": { - "line-color": "#101010", - "line-dasharray": [ - 3, - 2 - ], - "line-gap-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 11, - 0, - 12.5, - 0.5, - 15, - 2, - 18, - 11 - ], - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 12, - 0, - 12.5, - 1 - ] - } - }, - { - "id": "roads_tunnels_link_casing", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "filter": [ - "all", - [ - "<", - "pmap:level", - 0 - ], - [ - "==", - "pmap:link", - 1 - ] - ], - "paint": { - "line-color": "#101010", - "line-dasharray": [ - 3, - 2 - ], - "line-gap-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 13, - 0, - 13.5, - 1, - 18, - 11 - ], - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 12, - 0, - 12.5, - 1 - ] - } - }, - { - "id": "roads_tunnels_medium_casing", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "filter": [ - "all", - [ - "<", - "pmap:level", - 0 - ], - [ - "==", - "pmap:kind", - "medium_road" - ] - ], - "paint": { - "line-color": "#101010", - "line-dasharray": [ - 3, - 2 - ], - "line-gap-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 7, - 0, - 7.5, - 0.5, - 18, - 13 - ], - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 10, - 0, - 10.5, - 1 - ] - } - }, - { - "id": "roads_tunnels_major_casing", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "filter": [ - "all", - [ - "<", - "pmap:level", - 0 - ], - [ - "==", - "pmap:kind", - "major_road" - ] - ], - "paint": { - "line-color": "#101010", - "line-dasharray": [ - 3, - 2 - ], - "line-gap-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 7, - 0, - 7.5, - 0.5, - 18, - 13 - ], - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 9, - 0, - 9.5, - 1 - ] - } - }, - { - "id": "roads_tunnels_highway_casing", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "filter": [ - "all", - [ - "<", - "pmap:level", - 0 - ], - [ - "==", - "pmap:kind", - "highway" - ], - [ - "!=", - "pmap:link", - 1 - ] - ], - "paint": { - "line-color": "#101010", - "line-dasharray": [ - 6, - 0.5 - ], - "line-gap-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 3, - 0, - 3.5, - 0.5, - 18, - 15 - ], - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 7, - 0, - 7.5, - 1, - 20, - 15 - ] - } - }, - { - "id": "roads_tunnels_other", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "filter": [ - "all", - [ - "<", - "pmap:level", - 0 - ], - [ - "in", - "pmap:kind", - "other", - "path" - ] - ], - "paint": { - "line-color": "#292929", - "line-dasharray": [ - 4.5, - 0.5 - ], - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 14, - 0, - 20, - 7 - ] - } - }, - { - "id": "roads_tunnels_minor", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "filter": [ - "all", - [ - "<", - "pmap:level", - 0 - ], - [ - "==", - "pmap:kind", - "minor_road" - ] - ], - "paint": { - "line-color": "#292929", - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 11, - 0, - 12.5, - 0.5, - 15, - 2, - 18, - 11 - ] - } - }, - { - "id": "roads_tunnels_link", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "filter": [ - "all", - [ - "<", - "pmap:level", - 0 - ], - [ - "==", - "pmap:link", - 1 - ] - ], - "paint": { - "line-color": "#292929", - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 13, - 0, - 13.5, - 1, - 18, - 11 - ] - } - }, - { - "id": "roads_tunnels_medium", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "filter": [ - "all", - [ - "<", - "pmap:level", - 0 - ], - [ - "==", - "pmap:kind", - "medium_road" - ] - ], - "paint": { - "line-color": "#292929", - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 7, - 0, - 12, - 1.2, - 15, - 3, - 18, - 13 - ] - } - }, - { - "id": "roads_tunnels_major", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "filter": [ - "all", - [ - "<", - "pmap:level", - 0 - ], - [ - "==", - "pmap:kind", - "major_road" - ] - ], - "paint": { - "line-color": "#292929", - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 6, - 0, - 12, - 1.6, - 15, - 3, - 18, - 13 - ] - } - }, - { - "id": "roads_tunnels_highway", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "filter": [ - "all", - [ - "<", - "pmap:level", - 0 - ], - [ - "==", - "pmap:kind", - "highway" - ], - [ - "!=", - "pmap:link", - 1 - ] - ], - "paint": { - "line-color": "#292929", - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 3, - 0, - 6, - 1.1, - 12, - 1.6, - 15, - 5, - 18, - 15 - ] - } - }, - { - "id": "buildings", - "type": "fill", - "source": "protomaps", - "source-layer": "buildings", - "paint": { - "fill-color": "#0a0a0a", - "fill-opacity": 0.5 - } - }, - { - "id": "transit_pier", - "type": "line", - "source": "protomaps", - "source-layer": "transit", - "filter": [ - "any", - [ - "==", - "pmap:kind", - "pier" - ] - ], - "paint": { - "line-color": "#0a0a0a", - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 12, - 0, - 12.5, - 0.5, - 20, - 16 - ] - } - }, - { - "id": "roads_minor_service_casing", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "minzoom": 13, - "filter": [ - "all", - [ - "==", - "pmap:level", - 0 - ], - [ - "==", - "pmap:kind", - "minor_road" - ], - [ - "==", - "pmap:kind_detail", - "service" - ] - ], - "paint": { - "line-color": "#141414", - "line-gap-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 13, - 0, - 18, - 8 - ], - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 13, - 0, - 13.5, - 0.8 - ] - } - }, - { - "id": "roads_minor_casing", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "filter": [ - "all", - [ - "==", - "pmap:level", - 0 - ], - [ - "==", - "pmap:kind", - "minor_road" - ], - [ - "!=", - "pmap:kind_detail", - "service" - ] - ], - "paint": { - "line-color": "#141414", - "line-gap-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 11, - 0, - 12.5, - 0.5, - 15, - 2, - 18, - 11 - ], - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 12, - 0, - 12.5, - 1 - ] - } - }, - { - "id": "roads_link_casing", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "minzoom": 13, - "filter": [ - "all", - [ - "==", - "pmap:link", - 1 - ] - ], - "paint": { - "line-color": "#141414", - "line-gap-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 13, - 0, - 13.5, - 1, - 18, - 11 - ], - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 13, - 0, - 13.5, - 1.5 - ] - } - }, - { - "id": "roads_medium_casing", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "filter": [ - "all", - [ - "==", - "pmap:level", - 0 - ], - [ - "==", - "pmap:kind", - "medium_road" - ] - ], - "paint": { - "line-color": "#141414", - "line-gap-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 7, - 0, - 12, - 1.2, - 15, - 3, - 18, - 13 - ], - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 10, - 0, - 10.5, - 1.5 - ] - } - }, - { - "id": "roads_major_casing_late", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "minzoom": 12, - "filter": [ - "all", - [ - "==", - "pmap:level", - 0 - ], - [ - "==", - "pmap:kind", - "major_road" - ] - ], - "paint": { - "line-color": "#141414", - "line-gap-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 6, - 0, - 12, - 1.6, - 15, - 3, - 18, - 13 - ], - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 9, - 0, - 9.5, - 1 - ] - } - }, - { - "id": "roads_highway_casing_late", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "minzoom": 12, - "filter": [ - "all", - [ - "==", - "pmap:level", - 0 - ], - [ - "==", - "pmap:kind", - "highway" - ], - [ - "!=", - "pmap:link", - 1 - ] - ], - "paint": { - "line-color": "#141414", - "line-gap-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 3, - 0, - 3.5, - 0.5, - 18, - 15 - ], - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 7, - 0, - 7.5, - 1, - 20, - 15 - ] - } - }, - { - "id": "roads_other", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "filter": [ - "all", - [ - "==", - "pmap:level", - 0 - ], - [ - "in", - "pmap:kind", - "other", - "path" - ] - ], - "paint": { - "line-color": "#1f1f1f", - "line-dasharray": [ - 3, - 1 - ], - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 14, - 0, - 20, - 7 - ] - } - }, - { - "id": "roads_link", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "filter": [ - "all", - [ - "==", - "pmap:link", - 1 - ] - ], - "paint": { - "line-color": "#1f1f1f", - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 13, - 0, - 13.5, - 1, - 18, - 11 - ] - } - }, - { - "id": "roads_minor_service", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "filter": [ - "all", - [ - "==", - "pmap:level", - 0 - ], - [ - "==", - "pmap:kind", - "minor_road" - ], - [ - "==", - "pmap:kind_detail", - "service" - ] - ], - "paint": { - "line-color": "#1f1f1f", - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 13, - 0, - 18, - 8 - ] - } - }, - { - "id": "roads_minor", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "filter": [ - "all", - [ - "==", - "pmap:level", - 0 - ], - [ - "==", - "pmap:kind", - "minor_road" - ], - [ - "!=", - "pmap:kind_detail", - "service" - ] - ], - "paint": { - "line-color": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 11, - "#292929", - 16, - "#1f1f1f" - ], - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 11, - 0, - 12.5, - 0.5, - 15, - 2, - 18, - 11 - ] - } - }, - { - "id": "roads_medium", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "filter": [ - "all", - [ - "==", - "pmap:level", - 0 - ], - [ - "==", - "pmap:kind", - "medium_road" - ] - ], - "paint": { - "line-color": "#292929", - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 7, - 0, - 12, - 1.2, - 15, - 3, - 18, - 13 - ] - } - }, - { - "id": "roads_major_casing_early", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "maxzoom": 12, - "filter": [ - "all", - [ - "==", - "pmap:level", - 0 - ], - [ - "==", - "pmap:kind", - "major_road" - ] - ], - "paint": { - "line-color": "#141414", - "line-gap-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 7, - 0, - 7.5, - 0.5, - 18, - 13 - ], - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 9, - 0, - 9.5, - 1 - ] - } - }, - { - "id": "roads_major", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "filter": [ - "all", - [ - "==", - "pmap:level", - 0 - ], - [ - "==", - "pmap:kind", - "major_road" - ] - ], - "paint": { - "line-color": "#292929", - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 6, - 0, - 12, - 1.6, - 15, - 3, - 18, - 13 - ] - } - }, - { - "id": "roads_highway_casing_early", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "maxzoom": 12, - "filter": [ - "all", - [ - "==", - "pmap:level", - 0 - ], - [ - "==", - "pmap:kind", - "highway" - ], - [ - "!=", - "pmap:link", - 1 - ] - ], - "paint": { - "line-color": "#141414", - "line-gap-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 3, - 0, - 3.5, - 0.5, - 18, - 15 - ], - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 7, - 0, - 7.5, - 1 - ] - } - }, - { - "id": "roads_highway", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "filter": [ - "all", - [ - "==", - "pmap:level", - 0 - ], - [ - "==", - "pmap:kind", - "highway" - ], - [ - "!=", - "pmap:link", - 1 - ] - ], - "paint": { - "line-color": "#292929", - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 3, - 0, - 6, - 1.1, - 12, - 1.6, - 15, - 5, - 18, - 15 - ] - } - }, - { - "id": "transit_railway", - "type": "line", - "source": "protomaps", - "source-layer": "transit", - "filter": [ - "all", - [ - "==", - "pmap:kind", - "rail" - ] - ], - "paint": { - "line-dasharray": [ - 0.3, - 0.75 - ], - "line-opacity": 0.5, - "line-color": "#292929", - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 3, - 0, - 6, - 0.15, - 18, - 9 - ] - } - }, - { - "id": "boundaries_country", - "type": "line", - "source": "protomaps", - "source-layer": "boundaries", - "filter": [ - "<=", - "pmap:min_admin_level", - 2 - ], - "paint": { - "line-color": "#707070", - "line-width": 1, - "line-dasharray": [ - 3, - 2 - ] - } - }, - { - "id": "boundaries", - "type": "line", - "source": "protomaps", - "source-layer": "boundaries", - "filter": [ - ">", - "pmap:min_admin_level", - 2 - ], - "paint": { - "line-color": "#707070", - "line-width": 0.5, - "line-dasharray": [ - 3, - 2 - ] - } - }, - { - "id": "roads_bridges_other_casing", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "minzoom": 12, - "filter": [ - "all", - [ - ">", - "pmap:level", - 0 - ], - [ - "in", - "pmap:kind", - "other", - "path" - ] - ], - "paint": { - "line-color": "#141414", - "line-gap-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 14, - 0, - 20, - 7 - ] - } - }, - { - "id": "roads_bridges_link_casing", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "minzoom": 12, - "filter": [ - "all", - [ - ">", - "pmap:level", - 0 - ], - [ - "==", - "pmap:link", - 1 - ] - ], - "paint": { - "line-color": "#141414", - "line-gap-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 13, - 0, - 13.5, - 1, - 18, - 11 - ], - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 12, - 0, - 12.5, - 1.5 - ] - } - }, - { - "id": "roads_bridges_minor_casing", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "minzoom": 12, - "filter": [ - "all", - [ - ">", - "pmap:level", - 0 - ], - [ - "==", - "pmap:kind", - "minor_road" - ] - ], - "paint": { - "line-color": "#141414", - "line-gap-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 11, - 0, - 12.5, - 0.5, - 15, - 2, - 18, - 11 - ], - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 13, - 0, - 13.5, - 0.8 - ] - } - }, - { - "id": "roads_bridges_medium_casing", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "minzoom": 12, - "filter": [ - "all", - [ - ">", - "pmap:level", - 0 - ], - [ - "==", - "pmap:kind", - "medium_road" - ] - ], - "paint": { - "line-color": "#141414", - "line-gap-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 7, - 0, - 12, - 1.2, - 15, - 3, - 18, - 13 - ], - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 10, - 0, - 10.5, - 1.5 - ] - } - }, - { - "id": "roads_bridges_major_casing", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "minzoom": 12, - "filter": [ - "all", - [ - ">", - "pmap:level", - 0 - ], - [ - "==", - "pmap:kind", - "major_road" - ] - ], - "paint": { - "line-color": "#141414", - "line-gap-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 7, - 0, - 7.5, - 0.5, - 18, - 10 - ], - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 9, - 0, - 9.5, - 1.5 - ] - } - }, - { - "id": "roads_bridges_other", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "minzoom": 12, - "filter": [ - "all", - [ - ">", - "pmap:level", - 0 - ], - [ - "in", - "pmap:kind", - "other", - "path" - ] - ], - "paint": { - "line-color": "#1f1f1f", - "line-dasharray": [ - 2, - 1 - ], - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 14, - 0, - 20, - 7 - ] - } - }, - { - "id": "roads_bridges_minor", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "minzoom": 12, - "filter": [ - "all", - [ - ">", - "pmap:level", - 0 - ], - [ - "==", - "pmap:kind", - "minor_road" - ] - ], - "paint": { - "line-color": "#1f1f1f", - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 11, - 0, - 12.5, - 0.5, - 15, - 2, - 18, - 11 - ] - } - }, - { - "id": "roads_bridges_link", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "minzoom": 12, - "filter": [ - "all", - [ - ">", - "pmap:level", - 0 - ], - [ - "==", - "pmap:link", - 1 - ] - ], - "paint": { - "line-color": "#1f1f1f", - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 13, - 0, - 13.5, - 1, - 18, - 11 - ] - } - }, - { - "id": "roads_bridges_medium", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "minzoom": 12, - "filter": [ - "all", - [ - ">", - "pmap:level", - 0 - ], - [ - "==", - "pmap:kind", - "medium_road" - ] - ], - "paint": { - "line-color": "#292929", - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 7, - 0, - 12, - 1.2, - 15, - 3, - 18, - 13 - ] - } - }, - { - "id": "roads_bridges_major", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "minzoom": 12, - "filter": [ - "all", - [ - ">", - "pmap:level", - 0 - ], - [ - "==", - "pmap:kind", - "major_road" - ] - ], - "paint": { - "line-color": "#292929", - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 6, - 0, - 12, - 1.6, - 15, - 3, - 18, - 13 - ] - } - }, - { - "id": "roads_bridges_highway_casing", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "minzoom": 12, - "filter": [ - "all", - [ - ">", - "pmap:level", - 0 - ], - [ - "==", - "pmap:kind", - "highway" - ], - [ - "!=", - "pmap:link", - 1 - ] - ], - "paint": { - "line-color": "#141414", - "line-gap-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 3, - 0, - 3.5, - 0.5, - 18, - 15 - ], - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 7, - 0, - 7.5, - 1, - 20, - 15 - ] - } - }, - { - "id": "roads_bridges_highway", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "filter": [ - "all", - [ - ">", - "pmap:level", - 0 - ], - [ - "==", - "pmap:kind", - "highway" - ], - [ - "!=", - "pmap:link", - 1 - ] - ], - "paint": { - "line-color": "#292929", - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 3, - 0, - 6, - 1.1, - 12, - 1.6, - 15, - 5, - 18, - 15 - ] - } - }, - { - "id": "physical_line_waterway_label", - "type": "symbol", - "source": "protomaps", - "source-layer": "physical_line", - "minzoom": 13, - "filter": [ - "all", - [ - "in", - "pmap:kind", - "river", - "stream" - ] - ], - "layout": { - "symbol-placement": "line", - "text-font": [ - "Noto Sans Regular" - ], - "text-field": [ - "get", - "name" - ], - "text-size": 12, - "text-letter-spacing": 0.3 - }, - "paint": { - "text-color": "#707070" - } - }, - { - "id": "physical_point_peak", - "type": "symbol", - "source": "protomaps", - "source-layer": "physical_point", - "filter": [ - "any", - [ - "==", - "pmap:kind", - "peak" - ] - ], - "layout": { - "text-font": [ - "Noto Sans Italic" - ], - "text-field": [ - "get", - "name" - ], - "text-size": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 10, - 8, - 16, - 12 - ], - "text-letter-spacing": 0.1, - "text-max-width": 9 - }, - "paint": { - "text-color": "#707070", - "text-halo-width": 1.5 - } - }, - { - "id": "roads_labels_minor", - "type": "symbol", - "source": "protomaps", - "source-layer": "roads", - "minzoom": 15, - "filter": [ - "any", - [ - "in", - "pmap:kind", - "minor_road", - "other", - "path" - ] - ], - "layout": { - "symbol-sort-key": [ - "get", - "pmap:min_zoom" - ], - "symbol-placement": "line", - "text-font": [ - "Noto Sans Regular" - ], - "text-field": [ - "get", - "name" - ], - "text-size": 12 - }, - "paint": { - "text-color": "#525252", - "text-halo-color": "#141414", - "text-halo-width": 2 - } - }, - { - "id": "physical_point_ocean", - "type": "symbol", - "source": "protomaps", - "source-layer": "physical_point", - "filter": [ - "any", - [ - "in", - "pmap:kind", - "sea", - "ocean", - "lake", - "water", - "bay", - "strait", - "fjord" - ] - ], - "layout": { - "text-font": [ - "Noto Sans Medium" - ], - "text-field": [ - "get", - "name" - ], - "text-size": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 3, - 10, - 10, - 12 - ], - "text-letter-spacing": 0.1, - "text-max-width": 9, - "text-transform": "uppercase" - }, - "paint": { - "text-color": "#707070" - } - }, - { - "id": "physical_point_lakes", - "type": "symbol", - "source": "protomaps", - "source-layer": "physical_point", - "filter": [ - "any", - [ - "in", - "pmap:kind", - "lake", - "water" - ] - ], - "layout": { - "text-font": [ - "Noto Sans Medium" - ], - "text-field": [ - "get", - "name" - ], - "text-size": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 3, - 0, - 6, - 12, - 10, - 12 - ], - "text-letter-spacing": 0.1, - "text-max-width": 9 - }, - "paint": { - "text-color": "#707070" - } - }, - { - "id": "roads_labels_major", - "type": "symbol", - "source": "protomaps", - "source-layer": "roads", - "minzoom": 11, - "filter": [ - "any", - [ - "in", - "pmap:kind", - "highway", - "major_road", - "medium_road" - ] - ], - "layout": { - "symbol-sort-key": [ - "get", - "pmap:min_zoom" - ], - "symbol-placement": "line", - "text-font": [ - "Noto Sans Regular" - ], - "text-field": [ - "get", - "name" - ], - "text-size": 12 - }, - "paint": { - "text-color": "#5c5c5c", - "text-halo-color": "#141414", - "text-halo-width": 2 - } - }, - { - "id": "places_subplace", - "type": "symbol", - "source": "protomaps", - "source-layer": "places", - "filter": [ - "==", - "pmap:kind", - "neighbourhood" - ], - "layout": { - "symbol-sort-key": [ - "get", - "pmap:min_zoom" - ], - "text-field": "{name}", - "text-font": [ - "Noto Sans Regular" - ], - "text-max-width": 7, - "text-letter-spacing": 0.1, - "text-padding": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 5, - 2, - 8, - 4, - 12, - 18, - 15, - 20 - ], - "text-size": [ - "interpolate", - [ - "exponential", - 1.2 - ], - [ - "zoom" - ], - 11, - 8, - 14, - 14, - 18, - 24 - ], - "text-transform": "uppercase" - }, - "paint": { - "text-color": "#5c5c5c", - "text-halo-color": "#141414", - "text-halo-width": 1.5 - } - }, - { - "id": "places_locality", - "type": "symbol", - "source": "protomaps", - "source-layer": "places", - "filter": [ - "==", - "pmap:kind", - "locality" - ], - "layout": { - "icon-image": [ - "step", - [ - "zoom" - ], - "townspot", - 8, - "" - ], - "icon-size": 0.7, - "text-field": "{name}", - "text-font": [ - "case", - [ - "<=", - [ - "get", - "pmap:min_zoom" - ], - 5 - ], - [ - "literal", - [ - "Noto Sans Medium" - ] - ], - [ - "literal", - [ - "Noto Sans Regular" - ] - ] - ], - "text-padding": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 5, - 3, - 8, - 7, - 12, - 11 - ], - "text-size": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 2, - [ - "case", - [ - "<", - [ - "get", - "pmap:population_rank" - ], - 13 - ], - 8, - [ - ">=", - [ - "get", - "pmap:population_rank" - ], - 13 - ], - 13, - 0 - ], - 4, - [ - "case", - [ - "<", - [ - "get", - "pmap:population_rank" - ], - 13 - ], - 10, - [ - ">=", - [ - "get", - "pmap:population_rank" - ], - 13 - ], - 15, - 0 - ], - 6, - [ - "case", - [ - "<", - [ - "get", - "pmap:population_rank" - ], - 12 - ], - 11, - [ - ">=", - [ - "get", - "pmap:population_rank" - ], - 12 - ], - 17, - 0 - ], - 8, - [ - "case", - [ - "<", - [ - "get", - "pmap:population_rank" - ], - 11 - ], - 11, - [ - ">=", - [ - "get", - "pmap:population_rank" - ], - 11 - ], - 18, - 0 - ], - 10, - [ - "case", - [ - "<", - [ - "get", - "pmap:population_rank" - ], - 9 - ], - 12, - [ - ">=", - [ - "get", - "pmap:population_rank" - ], - 9 - ], - 20, - 0 - ], - 15, - [ - "case", - [ - "<", - [ - "get", - "pmap:population_rank" - ], - 8 - ], - 12, - [ - ">=", - [ - "get", - "pmap:population_rank" - ], - 8 - ], - 22, - 0 - ] - ], - "icon-padding": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 0, - 0, - 8, - 4, - 10, - 8, - 12, - 6, - 22, - 2 - ], - "text-anchor": [ - "step", - [ - "zoom" - ], - "left", - 8, - "center" - ], - "text-radial-offset": 0.4 - }, - "paint": { - "text-color": "#999999", - "text-halo-color": "#141414", - "text-halo-width": 1 - } - }, - { - "id": "places_region", - "type": "symbol", - "source": "protomaps", - "source-layer": "places", - "filter": [ - "==", - "pmap:kind", - "region" - ], - "layout": { - "symbol-sort-key": [ - "get", - "pmap:min_zoom" - ], - "text-field": [ - "step", - [ - "zoom" - ], - [ - "get", - "name:short" - ], - 6, - [ - "get", - "name" - ] - ], - "text-font": [ - "Noto Sans Regular" - ], - "text-size": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 3, - 11, - 7, - 16 - ], - "text-radial-offset": 0.2, - "text-anchor": "center", - "text-transform": "uppercase" - }, - "paint": { - "text-color": "#3d3d3d", - "text-halo-color": "#141414", - "text-halo-width": 2 - } - }, - { - "id": "places_country", - "type": "symbol", - "source": "protomaps", - "source-layer": "places", - "filter": [ - "==", - "pmap:kind", - "country" - ], - "layout": { - "symbol-sort-key": [ - "get", - "pmap:min_zoom" - ], - "text-field": "{name}", - "text-font": [ - "Noto Sans Medium" - ], - "text-size": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 2, - [ - "case", - [ - "<", - [ - "get", - "pmap:population_rank" - ], - 10 - ], - 8, - [ - ">=", - [ - "get", - "pmap:population_rank" - ], - 10 - ], - 12, - 0 - ], - 6, - [ - "case", - [ - "<", - [ - "get", - "pmap:population_rank" - ], - 8 - ], - 10, - [ - ">=", - [ - "get", - "pmap:population_rank" - ], - 8 - ], - 18, - 0 - ], - 8, - [ - "case", - [ - "<", - [ - "get", - "pmap:population_rank" - ], - 7 - ], - 11, - [ - ">=", - [ - "get", - "pmap:population_rank" - ], - 7 - ], - 20, - 0 - ] - ], - "icon-padding": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 0, - 2, - 14, - 2, - 16, - 20, - 17, - 2, - 22, - 2 - ], - "text-transform": "uppercase" - }, - "paint": { - "text-color": "#707070" - } - } - ], - "sprite": "https://static.immich.cloud/tiles/sprites/v1/dark", - "glyphs": "https://static.immich.cloud/tiles/fonts/{fontstack}/{range}.pbf" -} diff --git a/server/resources/style-light.json b/server/resources/style-light.json deleted file mode 100644 index 612622ef85..0000000000 --- a/server/resources/style-light.json +++ /dev/null @@ -1,3180 +0,0 @@ -{ - "version": 8, - "name": "Immich Map", - "id": "immich-map-light", - "sources": { - "protomaps": { - "type": "vector", - "url": "https://tiles.immich.cloud/v1.json" - } - }, - "layers": [ - { - "id": "background", - "type": "background", - "paint": { - "background-color": "#cccccc" - } - }, - { - "id": "earth", - "type": "fill", - "source": "protomaps", - "source-layer": "earth", - "paint": { - "fill-color": "#e0e0e0" - } - }, - { - "id": "landuse_park", - "type": "fill", - "source": "protomaps", - "source-layer": "landuse", - "filter": [ - "any", - [ - "in", - "pmap:kind", - "national_park", - "park", - "cemetery", - "protected_area", - "nature_reserve", - "forest", - "golf_course" - ] - ], - "paint": { - "fill-color": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 0, - "#cfddd5", - 12, - "#9cd3b4" - ] - } - }, - { - "id": "landuse_urban_green", - "type": "fill", - "source": "protomaps", - "source-layer": "landuse", - "filter": [ - "any", - [ - "in", - "pmap:kind", - "allotments", - "village_green", - "playground" - ] - ], - "paint": { - "fill-color": "#9cd3b4", - "fill-opacity": 0.7 - } - }, - { - "id": "landuse_hospital", - "type": "fill", - "source": "protomaps", - "source-layer": "landuse", - "filter": [ - "any", - [ - "==", - "pmap:kind", - "hospital" - ] - ], - "paint": { - "fill-color": "#e4dad9" - } - }, - { - "id": "landuse_industrial", - "type": "fill", - "source": "protomaps", - "source-layer": "landuse", - "filter": [ - "any", - [ - "==", - "pmap:kind", - "industrial" - ] - ], - "paint": { - "fill-color": "#d1dde1" - } - }, - { - "id": "landuse_school", - "type": "fill", - "source": "protomaps", - "source-layer": "landuse", - "filter": [ - "any", - [ - "in", - "pmap:kind", - "school", - "university", - "college" - ] - ], - "paint": { - "fill-color": "#e4ded7" - } - }, - { - "id": "landuse_beach", - "type": "fill", - "source": "protomaps", - "source-layer": "landuse", - "filter": [ - "any", - [ - "in", - "pmap:kind", - "beach" - ] - ], - "paint": { - "fill-color": "#e8e4d0" - } - }, - { - "id": "landuse_zoo", - "type": "fill", - "source": "protomaps", - "source-layer": "landuse", - "filter": [ - "any", - [ - "in", - "pmap:kind", - "zoo" - ] - ], - "paint": { - "fill-color": "#c6dcdc" - } - }, - { - "id": "landuse_military", - "type": "fill", - "source": "protomaps", - "source-layer": "landuse", - "filter": [ - "any", - [ - "in", - "pmap:kind", - "military", - "naval_base", - "airfield" - ] - ], - "paint": { - "fill-color": "#c6dcdc" - } - }, - { - "id": "natural_wood", - "type": "fill", - "source": "protomaps", - "source-layer": "natural", - "filter": [ - "any", - [ - "in", - "pmap:kind", - "wood", - "nature_reserve", - "forest" - ] - ], - "paint": { - "fill-color": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 0, - "#d0ded0", - 12, - "#a0d9a0" - ] - } - }, - { - "id": "natural_scrub", - "type": "fill", - "source": "protomaps", - "source-layer": "natural", - "filter": [ - "in", - "pmap:kind", - "scrub", - "grassland", - "grass" - ], - "paint": { - "fill-color": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 0, - "#cedcd7", - 12, - "#99d2bb" - ] - } - }, - { - "id": "natural_glacier", - "type": "fill", - "source": "protomaps", - "source-layer": "natural", - "filter": [ - "==", - "pmap:kind", - "glacier" - ], - "paint": { - "fill-color": "#e7e7e7" - } - }, - { - "id": "natural_sand", - "type": "fill", - "source": "protomaps", - "source-layer": "natural", - "filter": [ - "==", - "pmap:kind", - "sand" - ], - "paint": { - "fill-color": "#e2e0d7" - } - }, - { - "id": "landuse_aerodrome", - "type": "fill", - "source": "protomaps", - "source-layer": "landuse", - "filter": [ - "any", - [ - "in", - "pmap:kind", - "aerodrome" - ] - ], - "paint": { - "fill-color": "#dadbdf" - } - }, - { - "id": "transit_runway", - "type": "line", - "source": "protomaps", - "source-layer": "transit", - "filter": [ - "any", - [ - "in", - "pmap:kind_detail", - "runway" - ] - ], - "paint": { - "line-color": "#e9e9ed", - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 10, - 0, - 12, - 4, - 18, - 30 - ] - } - }, - { - "id": "transit_taxiway", - "type": "line", - "source": "protomaps", - "source-layer": "transit", - "minzoom": 13, - "filter": [ - "any", - [ - "in", - "pmap:kind_detail", - "taxiway" - ] - ], - "paint": { - "line-color": "#e9e9ed", - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 13, - 0, - 13.5, - 1, - 15, - 6 - ] - } - }, - { - "id": "water", - "type": "fill", - "source": "protomaps", - "source-layer": "water", - "paint": { - "fill-color": "rgba(148, 209, 236, 0.66)" - } - }, - { - "id": "physical_line_stream", - "type": "line", - "source": "protomaps", - "source-layer": "physical_line", - "minzoom": 14, - "filter": [ - "all", - [ - "in", - "pmap:kind", - "stream" - ] - ], - "paint": { - "line-color": "rgba(148, 209, 236, 0.66)", - "line-width": 0.5 - } - }, - { - "id": "physical_line_river", - "type": "line", - "source": "protomaps", - "source-layer": "physical_line", - "minzoom": 9, - "filter": [ - "all", - [ - "in", - "pmap:kind", - "river" - ] - ], - "paint": { - "line-color": "rgba(148, 209, 236, 0.66)", - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 9, - 0, - 9.5, - 1, - 18, - 12 - ] - } - }, - { - "id": "landuse_pedestrian", - "type": "fill", - "source": "protomaps", - "source-layer": "landuse", - "filter": [ - "any", - [ - "==", - "pmap:kind", - "pedestrian" - ] - ], - "paint": { - "fill-color": "#e3e0d4" - } - }, - { - "id": "landuse_pier", - "type": "fill", - "source": "protomaps", - "source-layer": "landuse", - "filter": [ - "any", - [ - "==", - "pmap:kind", - "pier" - ] - ], - "paint": { - "fill-color": "#e0e0e0" - } - }, - { - "id": "roads_tunnels_other_casing", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "filter": [ - "all", - [ - "<", - "pmap:level", - 0 - ], - [ - "in", - "pmap:kind", - "other", - "path" - ] - ], - "paint": { - "line-color": "#e0e0e0", - "line-gap-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 14, - 0, - 20, - 7 - ] - } - }, - { - "id": "roads_tunnels_minor_casing", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "filter": [ - "all", - [ - "<", - "pmap:level", - 0 - ], - [ - "==", - "pmap:kind", - "minor_road" - ] - ], - "paint": { - "line-color": "#e0e0e0", - "line-dasharray": [ - 3, - 2 - ], - "line-gap-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 11, - 0, - 12.5, - 0.5, - 15, - 2, - 18, - 11 - ], - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 12, - 0, - 12.5, - 1 - ] - } - }, - { - "id": "roads_tunnels_link_casing", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "filter": [ - "all", - [ - "<", - "pmap:level", - 0 - ], - [ - "==", - "pmap:link", - 1 - ] - ], - "paint": { - "line-color": "#e0e0e0", - "line-dasharray": [ - 3, - 2 - ], - "line-gap-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 13, - 0, - 13.5, - 1, - 18, - 11 - ], - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 12, - 0, - 12.5, - 1 - ] - } - }, - { - "id": "roads_tunnels_medium_casing", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "filter": [ - "all", - [ - "<", - "pmap:level", - 0 - ], - [ - "==", - "pmap:kind", - "medium_road" - ] - ], - "paint": { - "line-color": "#e0e0e0", - "line-dasharray": [ - 3, - 2 - ], - "line-gap-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 7, - 0, - 7.5, - 0.5, - 18, - 13 - ], - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 10, - 0, - 10.5, - 1 - ] - } - }, - { - "id": "roads_tunnels_major_casing", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "filter": [ - "all", - [ - "<", - "pmap:level", - 0 - ], - [ - "==", - "pmap:kind", - "major_road" - ] - ], - "paint": { - "line-color": "#e0e0e0", - "line-dasharray": [ - 3, - 2 - ], - "line-gap-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 7, - 0, - 7.5, - 0.5, - 18, - 13 - ], - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 9, - 0, - 9.5, - 1 - ] - } - }, - { - "id": "roads_tunnels_highway_casing", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "filter": [ - "all", - [ - "<", - "pmap:level", - 0 - ], - [ - "==", - "pmap:kind", - "highway" - ], - [ - "!=", - "pmap:link", - 1 - ] - ], - "paint": { - "line-color": "#e0e0e0", - "line-dasharray": [ - 6, - 0.5 - ], - "line-gap-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 3, - 0, - 3.5, - 0.5, - 18, - 15 - ], - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 7, - 0, - 7.5, - 1, - 20, - 15 - ] - } - }, - { - "id": "roads_tunnels_other", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "filter": [ - "all", - [ - "<", - "pmap:level", - 0 - ], - [ - "in", - "pmap:kind", - "other", - "path" - ] - ], - "paint": { - "line-color": "#d5d5d5", - "line-dasharray": [ - 4.5, - 0.5 - ], - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 14, - 0, - 20, - 7 - ] - } - }, - { - "id": "roads_tunnels_minor", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "filter": [ - "all", - [ - "<", - "pmap:level", - 0 - ], - [ - "==", - "pmap:kind", - "minor_road" - ] - ], - "paint": { - "line-color": "#d5d5d5", - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 11, - 0, - 12.5, - 0.5, - 15, - 2, - 18, - 11 - ] - } - }, - { - "id": "roads_tunnels_link", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "filter": [ - "all", - [ - "<", - "pmap:level", - 0 - ], - [ - "==", - "pmap:link", - 1 - ] - ], - "paint": { - "line-color": "#d5d5d5", - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 13, - 0, - 13.5, - 1, - 18, - 11 - ] - } - }, - { - "id": "roads_tunnels_medium", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "filter": [ - "all", - [ - "<", - "pmap:level", - 0 - ], - [ - "==", - "pmap:kind", - "medium_road" - ] - ], - "paint": { - "line-color": "#d5d5d5", - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 7, - 0, - 12, - 1.2, - 15, - 3, - 18, - 13 - ] - } - }, - { - "id": "roads_tunnels_major", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "filter": [ - "all", - [ - "<", - "pmap:level", - 0 - ], - [ - "==", - "pmap:kind", - "major_road" - ] - ], - "paint": { - "line-color": "#d5d5d5", - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 6, - 0, - 12, - 1.6, - 15, - 3, - 18, - 13 - ] - } - }, - { - "id": "roads_tunnels_highway", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "filter": [ - "all", - [ - "<", - "pmap:level", - 0 - ], - [ - "==", - "pmap:kind", - "highway" - ], - [ - "!=", - "pmap:link", - 1 - ] - ], - "paint": { - "line-color": "#d5d5d5", - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 3, - 0, - 6, - 1.1, - 12, - 1.6, - 15, - 5, - 18, - 15 - ] - } - }, - { - "id": "buildings", - "type": "fill", - "source": "protomaps", - "source-layer": "buildings", - "paint": { - "fill-color": "#cccccc", - "fill-opacity": 0.5 - } - }, - { - "id": "transit_pier", - "type": "line", - "source": "protomaps", - "source-layer": "transit", - "filter": [ - "any", - [ - "==", - "pmap:kind", - "pier" - ] - ], - "paint": { - "line-color": "#e0e0e0", - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 12, - 0, - 12.5, - 0.5, - 20, - 16 - ] - } - }, - { - "id": "roads_minor_service_casing", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "minzoom": 13, - "filter": [ - "all", - [ - "==", - "pmap:level", - 0 - ], - [ - "==", - "pmap:kind", - "minor_road" - ], - [ - "==", - "pmap:kind_detail", - "service" - ] - ], - "paint": { - "line-color": "#e0e0e0", - "line-gap-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 13, - 0, - 18, - 8 - ], - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 13, - 0, - 13.5, - 0.8 - ] - } - }, - { - "id": "roads_minor_casing", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "filter": [ - "all", - [ - "==", - "pmap:level", - 0 - ], - [ - "==", - "pmap:kind", - "minor_road" - ], - [ - "!=", - "pmap:kind_detail", - "service" - ] - ], - "paint": { - "line-color": "#e0e0e0", - "line-gap-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 11, - 0, - 12.5, - 0.5, - 15, - 2, - 18, - 11 - ], - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 12, - 0, - 12.5, - 1 - ] - } - }, - { - "id": "roads_link_casing", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "minzoom": 13, - "filter": [ - "all", - [ - "==", - "pmap:link", - 1 - ] - ], - "paint": { - "line-color": "#e0e0e0", - "line-gap-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 13, - 0, - 13.5, - 1, - 18, - 11 - ], - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 13, - 0, - 13.5, - 1.5 - ] - } - }, - { - "id": "roads_medium_casing", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "filter": [ - "all", - [ - "==", - "pmap:level", - 0 - ], - [ - "==", - "pmap:kind", - "medium_road" - ] - ], - "paint": { - "line-color": "#e0e0e0", - "line-gap-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 7, - 0, - 12, - 1.2, - 15, - 3, - 18, - 13 - ], - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 10, - 0, - 10.5, - 1.5 - ] - } - }, - { - "id": "roads_major_casing_late", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "minzoom": 12, - "filter": [ - "all", - [ - "==", - "pmap:level", - 0 - ], - [ - "==", - "pmap:kind", - "major_road" - ] - ], - "paint": { - "line-color": "#e0e0e0", - "line-gap-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 6, - 0, - 12, - 1.6, - 15, - 3, - 18, - 13 - ], - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 9, - 0, - 9.5, - 1 - ] - } - }, - { - "id": "roads_highway_casing_late", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "minzoom": 12, - "filter": [ - "all", - [ - "==", - "pmap:level", - 0 - ], - [ - "==", - "pmap:kind", - "highway" - ], - [ - "!=", - "pmap:link", - 1 - ] - ], - "paint": { - "line-color": "#e0e0e0", - "line-gap-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 3, - 0, - 3.5, - 0.5, - 18, - 15 - ], - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 7, - 0, - 7.5, - 1, - 20, - 15 - ] - } - }, - { - "id": "roads_other", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "filter": [ - "all", - [ - "==", - "pmap:level", - 0 - ], - [ - "in", - "pmap:kind", - "other", - "path" - ] - ], - "paint": { - "line-color": "#ebebeb", - "line-dasharray": [ - 3, - 1 - ], - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 14, - 0, - 20, - 7 - ] - } - }, - { - "id": "roads_link", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "filter": [ - "all", - [ - "==", - "pmap:link", - 1 - ] - ], - "paint": { - "line-color": "#ffffff", - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 13, - 0, - 13.5, - 1, - 18, - 11 - ] - } - }, - { - "id": "roads_minor_service", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "filter": [ - "all", - [ - "==", - "pmap:level", - 0 - ], - [ - "==", - "pmap:kind", - "minor_road" - ], - [ - "==", - "pmap:kind_detail", - "service" - ] - ], - "paint": { - "line-color": "#ebebeb", - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 13, - 0, - 18, - 8 - ] - } - }, - { - "id": "roads_minor", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "filter": [ - "all", - [ - "==", - "pmap:level", - 0 - ], - [ - "==", - "pmap:kind", - "minor_road" - ], - [ - "!=", - "pmap:kind_detail", - "service" - ] - ], - "paint": { - "line-color": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 11, - "#ebebeb", - 16, - "#ffffff" - ], - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 11, - 0, - 12.5, - 0.5, - 15, - 2, - 18, - 11 - ] - } - }, - { - "id": "roads_medium", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "filter": [ - "all", - [ - "==", - "pmap:level", - 0 - ], - [ - "==", - "pmap:kind", - "medium_road" - ] - ], - "paint": { - "line-color": "#f5f5f5", - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 7, - 0, - 12, - 1.2, - 15, - 3, - 18, - 13 - ] - } - }, - { - "id": "roads_major_casing_early", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "maxzoom": 12, - "filter": [ - "all", - [ - "==", - "pmap:level", - 0 - ], - [ - "==", - "pmap:kind", - "major_road" - ] - ], - "paint": { - "line-color": "#e0e0e0", - "line-gap-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 7, - 0, - 7.5, - 0.5, - 18, - 13 - ], - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 9, - 0, - 9.5, - 1 - ] - } - }, - { - "id": "roads_major", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "filter": [ - "all", - [ - "==", - "pmap:level", - 0 - ], - [ - "==", - "pmap:kind", - "major_road" - ] - ], - "paint": { - "line-color": "#ffffff", - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 6, - 0, - 12, - 1.6, - 15, - 3, - 18, - 13 - ] - } - }, - { - "id": "roads_highway_casing_early", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "maxzoom": 12, - "filter": [ - "all", - [ - "==", - "pmap:level", - 0 - ], - [ - "==", - "pmap:kind", - "highway" - ], - [ - "!=", - "pmap:link", - 1 - ] - ], - "paint": { - "line-color": "#e0e0e0", - "line-gap-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 3, - 0, - 3.5, - 0.5, - 18, - 15 - ], - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 7, - 0, - 7.5, - 1 - ] - } - }, - { - "id": "roads_highway", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "filter": [ - "all", - [ - "==", - "pmap:level", - 0 - ], - [ - "==", - "pmap:kind", - "highway" - ], - [ - "!=", - "pmap:link", - 1 - ] - ], - "paint": { - "line-color": "#ffffff", - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 3, - 0, - 6, - 1.1, - 12, - 1.6, - 15, - 5, - 18, - 15 - ] - } - }, - { - "id": "transit_railway", - "type": "line", - "source": "protomaps", - "source-layer": "transit", - "filter": [ - "all", - [ - "==", - "pmap:kind", - "rail" - ] - ], - "paint": { - "line-dasharray": [ - 0.3, - 0.75 - ], - "line-opacity": 0.5, - "line-color": "#a7b1b3", - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 3, - 0, - 6, - 0.15, - 18, - 9 - ] - } - }, - { - "id": "boundaries_country", - "type": "line", - "source": "protomaps", - "source-layer": "boundaries", - "filter": [ - "<=", - "pmap:min_admin_level", - 2 - ], - "paint": { - "line-color": "#adadad", - "line-width": 1, - "line-dasharray": [ - 3, - 2 - ] - } - }, - { - "id": "boundaries", - "type": "line", - "source": "protomaps", - "source-layer": "boundaries", - "filter": [ - ">", - "pmap:min_admin_level", - 2 - ], - "paint": { - "line-color": "#adadad", - "line-width": 0.5, - "line-dasharray": [ - 3, - 2 - ] - } - }, - { - "id": "roads_bridges_other_casing", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "minzoom": 12, - "filter": [ - "all", - [ - ">", - "pmap:level", - 0 - ], - [ - "in", - "pmap:kind", - "other", - "path" - ] - ], - "paint": { - "line-color": "#e0e0e0", - "line-gap-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 14, - 0, - 20, - 7 - ] - } - }, - { - "id": "roads_bridges_link_casing", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "minzoom": 12, - "filter": [ - "all", - [ - ">", - "pmap:level", - 0 - ], - [ - "==", - "pmap:link", - 1 - ] - ], - "paint": { - "line-color": "#e0e0e0", - "line-gap-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 13, - 0, - 13.5, - 1, - 18, - 11 - ], - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 12, - 0, - 12.5, - 1.5 - ] - } - }, - { - "id": "roads_bridges_minor_casing", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "minzoom": 12, - "filter": [ - "all", - [ - ">", - "pmap:level", - 0 - ], - [ - "==", - "pmap:kind", - "minor_road" - ] - ], - "paint": { - "line-color": "#e0e0e0", - "line-gap-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 11, - 0, - 12.5, - 0.5, - 15, - 2, - 18, - 11 - ], - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 13, - 0, - 13.5, - 0.8 - ] - } - }, - { - "id": "roads_bridges_medium_casing", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "minzoom": 12, - "filter": [ - "all", - [ - ">", - "pmap:level", - 0 - ], - [ - "==", - "pmap:kind", - "medium_road" - ] - ], - "paint": { - "line-color": "#e0e0e0", - "line-gap-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 7, - 0, - 12, - 1.2, - 15, - 3, - 18, - 13 - ], - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 10, - 0, - 10.5, - 1.5 - ] - } - }, - { - "id": "roads_bridges_major_casing", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "minzoom": 12, - "filter": [ - "all", - [ - ">", - "pmap:level", - 0 - ], - [ - "==", - "pmap:kind", - "major_road" - ] - ], - "paint": { - "line-color": "#e0e0e0", - "line-gap-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 7, - 0, - 7.5, - 0.5, - 18, - 10 - ], - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 9, - 0, - 9.5, - 1.5 - ] - } - }, - { - "id": "roads_bridges_other", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "minzoom": 12, - "filter": [ - "all", - [ - ">", - "pmap:level", - 0 - ], - [ - "in", - "pmap:kind", - "other", - "path" - ] - ], - "paint": { - "line-color": "#ebebeb", - "line-dasharray": [ - 2, - 1 - ], - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 14, - 0, - 20, - 7 - ] - } - }, - { - "id": "roads_bridges_minor", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "minzoom": 12, - "filter": [ - "all", - [ - ">", - "pmap:level", - 0 - ], - [ - "==", - "pmap:kind", - "minor_road" - ] - ], - "paint": { - "line-color": "#ffffff", - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 11, - 0, - 12.5, - 0.5, - 15, - 2, - 18, - 11 - ] - } - }, - { - "id": "roads_bridges_link", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "minzoom": 12, - "filter": [ - "all", - [ - ">", - "pmap:level", - 0 - ], - [ - "==", - "pmap:link", - 1 - ] - ], - "paint": { - "line-color": "#ffffff", - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 13, - 0, - 13.5, - 1, - 18, - 11 - ] - } - }, - { - "id": "roads_bridges_medium", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "minzoom": 12, - "filter": [ - "all", - [ - ">", - "pmap:level", - 0 - ], - [ - "==", - "pmap:kind", - "medium_road" - ] - ], - "paint": { - "line-color": "#f0eded", - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 7, - 0, - 12, - 1.2, - 15, - 3, - 18, - 13 - ] - } - }, - { - "id": "roads_bridges_major", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "minzoom": 12, - "filter": [ - "all", - [ - ">", - "pmap:level", - 0 - ], - [ - "==", - "pmap:kind", - "major_road" - ] - ], - "paint": { - "line-color": "#f5f5f5", - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 6, - 0, - 12, - 1.6, - 15, - 3, - 18, - 13 - ] - } - }, - { - "id": "roads_bridges_highway_casing", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "minzoom": 12, - "filter": [ - "all", - [ - ">", - "pmap:level", - 0 - ], - [ - "==", - "pmap:kind", - "highway" - ], - [ - "!=", - "pmap:link", - 1 - ] - ], - "paint": { - "line-color": "#e0e0e0", - "line-gap-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 3, - 0, - 3.5, - 0.5, - 18, - 15 - ], - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 7, - 0, - 7.5, - 1, - 20, - 15 - ] - } - }, - { - "id": "roads_bridges_highway", - "type": "line", - "source": "protomaps", - "source-layer": "roads", - "filter": [ - "all", - [ - ">", - "pmap:level", - 0 - ], - [ - "==", - "pmap:kind", - "highway" - ], - [ - "!=", - "pmap:link", - 1 - ] - ], - "paint": { - "line-color": "#ffffff", - "line-width": [ - "interpolate", - [ - "exponential", - 1.6 - ], - [ - "zoom" - ], - 3, - 0, - 6, - 1.1, - 12, - 1.6, - 15, - 5, - 18, - 15 - ] - } - }, - { - "id": "physical_line_waterway_label", - "type": "symbol", - "source": "protomaps", - "source-layer": "physical_line", - "minzoom": 13, - "filter": [ - "all", - [ - "in", - "pmap:kind", - "river", - "stream" - ] - ], - "layout": { - "symbol-placement": "line", - "text-font": [ - "Noto Sans Regular" - ], - "text-field": [ - "get", - "name" - ], - "text-size": 12, - "text-letter-spacing": 0.3 - }, - "paint": { - "text-color": "#ffffff" - } - }, - { - "id": "physical_point_peak", - "type": "symbol", - "source": "protomaps", - "source-layer": "physical_point", - "filter": [ - "any", - [ - "==", - "pmap:kind", - "peak" - ] - ], - "layout": { - "text-font": [ - "Noto Sans Italic" - ], - "text-field": [ - "get", - "name" - ], - "text-size": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 10, - 8, - 16, - 12 - ], - "text-letter-spacing": 0.1, - "text-max-width": 9 - }, - "paint": { - "text-color": "#7e9aa0", - "text-halo-width": 1.5 - } - }, - { - "id": "roads_labels_minor", - "type": "symbol", - "source": "protomaps", - "source-layer": "roads", - "minzoom": 15, - "filter": [ - "any", - [ - "in", - "pmap:kind", - "minor_road", - "other", - "path" - ] - ], - "layout": { - "symbol-sort-key": [ - "get", - "pmap:min_zoom" - ], - "symbol-placement": "line", - "text-font": [ - "Noto Sans Regular" - ], - "text-field": [ - "get", - "name" - ], - "text-size": 12 - }, - "paint": { - "text-color": "#91888b", - "text-halo-color": "#ffffff", - "text-halo-width": 2 - } - }, - { - "id": "physical_point_ocean", - "type": "symbol", - "source": "protomaps", - "source-layer": "physical_point", - "filter": [ - "any", - [ - "in", - "pmap:kind", - "sea", - "ocean", - "lake", - "water", - "bay", - "strait", - "fjord" - ] - ], - "layout": { - "text-font": [ - "Noto Sans Medium" - ], - "text-field": [ - "get", - "name" - ], - "text-size": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 3, - 10, - 10, - 12 - ], - "text-letter-spacing": 0.1, - "text-max-width": 9, - "text-transform": "uppercase" - }, - "paint": { - "text-color": "#ffffff" - } - }, - { - "id": "physical_point_lakes", - "type": "symbol", - "source": "protomaps", - "source-layer": "physical_point", - "filter": [ - "any", - [ - "in", - "pmap:kind", - "lake", - "water" - ] - ], - "layout": { - "text-font": [ - "Noto Sans Medium" - ], - "text-field": [ - "get", - "name" - ], - "text-size": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 3, - 0, - 6, - 12, - 10, - 12 - ], - "text-letter-spacing": 0.1, - "text-max-width": 9 - }, - "paint": { - "text-color": "#ffffff" - } - }, - { - "id": "roads_labels_major", - "type": "symbol", - "source": "protomaps", - "source-layer": "roads", - "minzoom": 11, - "filter": [ - "any", - [ - "in", - "pmap:kind", - "highway", - "major_road", - "medium_road" - ] - ], - "layout": { - "symbol-sort-key": [ - "get", - "pmap:min_zoom" - ], - "symbol-placement": "line", - "text-font": [ - "Noto Sans Regular" - ], - "text-field": [ - "get", - "name" - ], - "text-size": 12 - }, - "paint": { - "text-color": "#938a8d", - "text-halo-color": "#ffffff", - "text-halo-width": 2 - } - }, - { - "id": "places_subplace", - "type": "symbol", - "source": "protomaps", - "source-layer": "places", - "filter": [ - "==", - "pmap:kind", - "neighbourhood" - ], - "layout": { - "symbol-sort-key": [ - "get", - "pmap:min_zoom" - ], - "text-field": "{name}", - "text-font": [ - "Noto Sans Regular" - ], - "text-max-width": 7, - "text-letter-spacing": 0.1, - "text-padding": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 5, - 2, - 8, - 4, - 12, - 18, - 15, - 20 - ], - "text-size": [ - "interpolate", - [ - "exponential", - 1.2 - ], - [ - "zoom" - ], - 11, - 8, - 14, - 14, - 18, - 24 - ], - "text-transform": "uppercase" - }, - "paint": { - "text-color": "#8f8f8f", - "text-halo-color": "#e0e0e0", - "text-halo-width": 1.5 - } - }, - { - "id": "places_locality", - "type": "symbol", - "source": "protomaps", - "source-layer": "places", - "filter": [ - "==", - "pmap:kind", - "locality" - ], - "layout": { - "icon-image": [ - "step", - [ - "zoom" - ], - "townspot", - 8, - "" - ], - "icon-size": 0.7, - "text-field": "{name}", - "text-font": [ - "case", - [ - "<=", - [ - "get", - "pmap:min_zoom" - ], - 5 - ], - [ - "literal", - [ - "Noto Sans Medium" - ] - ], - [ - "literal", - [ - "Noto Sans Regular" - ] - ] - ], - "text-padding": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 5, - 3, - 8, - 7, - 12, - 11 - ], - "text-size": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 2, - [ - "case", - [ - "<", - [ - "get", - "pmap:population_rank" - ], - 13 - ], - 8, - [ - ">=", - [ - "get", - "pmap:population_rank" - ], - 13 - ], - 13, - 0 - ], - 4, - [ - "case", - [ - "<", - [ - "get", - "pmap:population_rank" - ], - 13 - ], - 10, - [ - ">=", - [ - "get", - "pmap:population_rank" - ], - 13 - ], - 15, - 0 - ], - 6, - [ - "case", - [ - "<", - [ - "get", - "pmap:population_rank" - ], - 12 - ], - 11, - [ - ">=", - [ - "get", - "pmap:population_rank" - ], - 12 - ], - 17, - 0 - ], - 8, - [ - "case", - [ - "<", - [ - "get", - "pmap:population_rank" - ], - 11 - ], - 11, - [ - ">=", - [ - "get", - "pmap:population_rank" - ], - 11 - ], - 18, - 0 - ], - 10, - [ - "case", - [ - "<", - [ - "get", - "pmap:population_rank" - ], - 9 - ], - 12, - [ - ">=", - [ - "get", - "pmap:population_rank" - ], - 9 - ], - 20, - 0 - ], - 15, - [ - "case", - [ - "<", - [ - "get", - "pmap:population_rank" - ], - 8 - ], - 12, - [ - ">=", - [ - "get", - "pmap:population_rank" - ], - 8 - ], - 22, - 0 - ] - ], - "icon-padding": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 0, - 0, - 8, - 4, - 10, - 8, - 12, - 6, - 22, - 2 - ], - "text-anchor": [ - "step", - [ - "zoom" - ], - "left", - 8, - "center" - ], - "text-radial-offset": 0.4 - }, - "paint": { - "text-color": "#5c5c5c", - "text-halo-color": "#e0e0e0", - "text-halo-width": 1 - } - }, - { - "id": "places_region", - "type": "symbol", - "source": "protomaps", - "source-layer": "places", - "filter": [ - "==", - "pmap:kind", - "region" - ], - "layout": { - "symbol-sort-key": [ - "get", - "pmap:min_zoom" - ], - "text-field": [ - "step", - [ - "zoom" - ], - [ - "get", - "name:short" - ], - 6, - [ - "get", - "name" - ] - ], - "text-font": [ - "Noto Sans Regular" - ], - "text-size": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 3, - 11, - 7, - 16 - ], - "text-radial-offset": 0.2, - "text-anchor": "center", - "text-transform": "uppercase" - }, - "paint": { - "text-color": "#b3b3b3", - "text-halo-color": "#e0e0e0", - "text-halo-width": 2 - } - }, - { - "id": "places_country", - "type": "symbol", - "source": "protomaps", - "source-layer": "places", - "filter": [ - "==", - "pmap:kind", - "country" - ], - "layout": { - "symbol-sort-key": [ - "get", - "pmap:min_zoom" - ], - "text-field": "{name}", - "text-font": [ - "Noto Sans Medium" - ], - "text-size": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 2, - [ - "case", - [ - "<", - [ - "get", - "pmap:population_rank" - ], - 10 - ], - 8, - [ - ">=", - [ - "get", - "pmap:population_rank" - ], - 10 - ], - 12, - 0 - ], - 6, - [ - "case", - [ - "<", - [ - "get", - "pmap:population_rank" - ], - 8 - ], - 10, - [ - ">=", - [ - "get", - "pmap:population_rank" - ], - 8 - ], - 18, - 0 - ], - 8, - [ - "case", - [ - "<", - [ - "get", - "pmap:population_rank" - ], - 7 - ], - 11, - [ - ">=", - [ - "get", - "pmap:population_rank" - ], - 7 - ], - 20, - 0 - ] - ], - "icon-padding": [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 0, - 2, - 14, - 2, - 16, - 20, - 17, - 2, - 22, - 2 - ], - "text-transform": "uppercase" - }, - "paint": { - "text-color": "#a3a3a3" - } - } - ], - "sprite": "https://static.immich.cloud/tiles/sprites/v1/light", - "glyphs": "https://static.immich.cloud/tiles/fonts/{fontstack}/{range}.pbf" -} diff --git a/server/src/app.common.ts b/server/src/app.common.ts index 934c13343f..2159721932 100644 --- a/server/src/app.common.ts +++ b/server/src/app.common.ts @@ -2,9 +2,10 @@ import { NestExpressApplication } from '@nestjs/platform-express'; import { json } from 'body-parser'; import compression from 'compression'; import cookieParser from 'cookie-parser'; +import helmetMiddleware from 'helmet'; import { existsSync } from 'node:fs'; import sirv from 'sirv'; -import { excludePaths, serverVersion } from 'src/constants'; +import { IMMICH_SERVER_START, excludePaths, serverVersion } from 'src/constants'; import { MaintenanceWorkerService } from 'src/maintenance/maintenance-worker.service'; import { WebSocketAdapter } from 'src/middleware/websocket.adapter'; import { ConfigRepository } from 'src/repositories/config.repository'; @@ -39,7 +40,7 @@ export async function configureExpress( }, ) { const configRepository = app.get(ConfigRepository); - const { environment, host, port, resourcePaths, network } = configRepository.getEnv(); + const { environment, host, port, helmet, resourcePaths, network } = configRepository.getEnv(); const logger = await app.resolve(LoggingRepository); logger.setContext('Bootstrap'); @@ -47,6 +48,12 @@ export async function configureExpress( app.set('trust proxy', ['loopback', ...network.trustedProxies]); app.set('etag', 'strong'); + + if (helmet.config) { + app.use(helmetMiddleware(helmet.config)); + logger.log('Initialized helmet middleware'); + } + app.use(cookieParser()); app.use(json({ limit: '10mb' })); @@ -83,5 +90,5 @@ export async function configureExpress( const server = await (host ? app.listen(port, host) : app.listen(port)); server.requestTimeout = 24 * 60 * 60 * 1000; - logger.log(`Immich Server is listening on ${await app.getUrl()} [v${serverVersion}] [${environment}] `); + logger.log(`${IMMICH_SERVER_START} on ${await app.getUrl()} [v${serverVersion}] [${environment}] `); } diff --git a/server/src/app.module.ts b/server/src/app.module.ts index 49b779ca18..b59317577f 100644 --- a/server/src/app.module.ts +++ b/server/src/app.module.ts @@ -29,6 +29,7 @@ import { ProcessRepository } from 'src/repositories/process.repository'; import { StorageRepository } from 'src/repositories/storage.repository'; import { SystemMetadataRepository } from 'src/repositories/system-metadata.repository'; import { teardownTelemetry, TelemetryRepository } from 'src/repositories/telemetry.repository'; +import { UserRepository } from 'src/repositories/user.repository'; import { WebsocketRepository } from 'src/repositories/websocket.repository'; import { services } from 'src/services'; import { AuthService } from 'src/services/auth.service'; @@ -111,6 +112,7 @@ export class ApiModule extends BaseModule {} StorageRepository, ProcessRepository, DatabaseRepository, + UserRepository, SystemMetadataRepository, AppRepository, MaintenanceHealthRepository, diff --git a/server/src/constants.ts b/server/src/constants.ts index e24057beba..4f8d9342c7 100644 --- a/server/src/constants.ts +++ b/server/src/constants.ts @@ -4,6 +4,8 @@ import { dirname, join } from 'node:path'; import { SemVer } from 'semver'; import { ApiTag, AudioCodec, DatabaseExtension, ExifOrientation, VectorIndex } from 'src/enum'; +export const IMMICH_SERVER_START = 'Immich Server is listening'; + export const ErrorMessages = { InconsistentMediaLocation: 'Detected an inconsistent media location. For more information, see https://docs.immich.app/errors#inconsistent-media-location', diff --git a/server/src/database.ts b/server/src/database.ts index 3e3192c21a..f4878b2cee 100644 --- a/server/src/database.ts +++ b/server/src/database.ts @@ -169,6 +169,7 @@ export type AuthSharedLink = { id: string; expiresAt: Date | null; userId: string; + albumId: string | null; showExif: boolean; allowUpload: boolean; allowDownload: boolean; @@ -344,6 +345,7 @@ export const columns = { 'asset.type', 'asset.width', 'asset.height', + 'asset.isEdited', ], assetFiles: ['asset_file.id', 'asset_file.path', 'asset_file.type', 'asset_file.isEdited'], assetFilesForThumbnail: [ @@ -357,15 +359,6 @@ export const columns = { authUser: ['user.id', 'user.name', 'user.email', 'user.isAdmin', 'user.quotaUsageInBytes', 'user.quotaSizeInBytes'], authApiKey: ['api_key.id', 'api_key.permissions'], authSession: ['session.id', 'session.updatedAt', 'session.pinExpiresAt', 'session.appVersion'], - authSharedLink: [ - 'shared_link.id', - 'shared_link.userId', - 'shared_link.expiresAt', - 'shared_link.showExif', - 'shared_link.allowUpload', - 'shared_link.allowDownload', - 'shared_link.password', - ], user: userColumns, userWithPrefix: userWithPrefixColumns, userAdmin: [ diff --git a/server/src/dtos/env.dto.ts b/server/src/dtos/env.dto.ts index b04366c273..bdcf3614fd 100644 --- a/server/src/dtos/env.dto.ts +++ b/server/src/dtos/env.dto.ts @@ -42,6 +42,10 @@ export class EnvDto { @Optional() IMMICH_CONFIG_FILE?: string; + @IsString() + @Optional() + IMMICH_HELMET_FILE?: string; + @IsEnum(ImmichEnvironment) @Optional() IMMICH_ENV?: ImmichEnvironment; diff --git a/server/src/dtos/search.dto.ts b/server/src/dtos/search.dto.ts index f72ecdf8b6..196e72c37e 100644 --- a/server/src/dtos/search.dto.ts +++ b/server/src/dtos/search.dto.ts @@ -146,7 +146,7 @@ export class RandomSearchDto extends BaseSearchWithResultsDto { @ValidateBoolean({ optional: true, description: 'Include stacked assets' }) withStacked?: boolean; - @ValidateBoolean({ optional: true, description: 'Include assets with people' }) + @ValidateBoolean({ optional: true, description: 'Include people data in response' }) withPeople?: boolean; } diff --git a/server/src/maintenance/maintenance-health.repository.ts b/server/src/maintenance/maintenance-health.repository.ts index aeef93ec51..6eab265677 100644 --- a/server/src/maintenance/maintenance-health.repository.ts +++ b/server/src/maintenance/maintenance-health.repository.ts @@ -1,6 +1,7 @@ import { Injectable } from '@nestjs/common'; import { fork } from 'node:child_process'; import { dirname, join } from 'node:path'; +import { IMMICH_SERVER_START } from 'src/constants'; @Injectable() export class MaintenanceHealthRepository { @@ -20,45 +21,27 @@ export class MaintenanceHealthRepository { stdio: ['ignore', 'pipe', 'ignore', 'ipc'], }); - async function checkHealth() { - try { - const response = await fetch('http://127.0.0.1:33001/api/server/config'); - const { isOnboarded } = await response.json(); - if (isOnboarded) { - resolve(); - } else { - reject(new Error('Server health check failed, no admin exists.')); - } - } catch (error) { - reject(error); - } finally { - if (worker.exitCode === null) { - worker.kill('SIGTERM'); - } - } - } - - let output = '', - alive = false; + let output = ''; worker.stdout?.on('data', (data) => { - if (alive) { + if (worker.exitCode !== null) { return; } output += data; - if (output.includes('Immich Server is listening')) { - alive = true; - void checkHealth(); + if (output.includes(IMMICH_SERVER_START)) { + resolve(); + worker.kill('SIGTERM'); } }); - worker.on('exit', reject); - worker.on('error', reject); + worker.on('exit', (code, signal) => reject(`Server health check failed, server exited with ${signal ?? code}`)); + worker.on('error', (error) => reject(`Server health check failed, process threw: ${error}`)); setTimeout(() => { if (worker.exitCode === null) { + reject('Server health check failed, took too long to start.'); worker.kill('SIGTERM'); } }, 20_000); diff --git a/server/src/queries/asset.job.repository.sql b/server/src/queries/asset.job.repository.sql index cebb9fe95e..cf5b8f02dc 100644 --- a/server/src/queries/asset.job.repository.sql +++ b/server/src/queries/asset.job.repository.sql @@ -264,6 +264,7 @@ select "asset"."type", "asset"."width", "asset"."height", + "asset"."isEdited", ( select coalesce(json_agg(agg), '[]') diff --git a/server/src/queries/search.repository.sql b/server/src/queries/search.repository.sql index ef5fbe09be..099b7f4ee2 100644 --- a/server/src/queries/search.repository.sql +++ b/server/src/queries/search.repository.sql @@ -254,6 +254,7 @@ where and "visibility" = $2 and "deletedAt" is null and "state" is not null + and "state" != $3 -- SearchRepository.getCities select distinct @@ -266,6 +267,7 @@ where and "visibility" = $2 and "deletedAt" is null and "city" is not null + and "city" != $3 -- SearchRepository.getCameraMakes select distinct @@ -278,6 +280,7 @@ where and "visibility" = $2 and "deletedAt" is null and "make" is not null + and "make" != $3 -- SearchRepository.getCameraModels select distinct @@ -290,6 +293,7 @@ where and "visibility" = $2 and "deletedAt" is null and "model" is not null + and "model" != $3 -- SearchRepository.getCameraLensModels select distinct @@ -302,3 +306,4 @@ where and "visibility" = $2 and "deletedAt" is null and "lensModel" is not null + and "lensModel" != $3 diff --git a/server/src/queries/shared.link.repository.sql b/server/src/queries/shared.link.repository.sql index 2630e384fc..e1177bba28 100644 --- a/server/src/queries/shared.link.repository.sql +++ b/server/src/queries/shared.link.repository.sql @@ -3,37 +3,64 @@ -- SharedLinkRepository.get select "shared_link".*, - coalesce( - json_agg("a") filter ( - where - "a"."id" is not null - ), - '[]' + ( + select + coalesce(json_agg(agg), '[]') + from + ( + select + "asset".*, + to_json("exifInfo") as "exifInfo" + from + "shared_link_asset" + inner join "asset" on "asset"."id" = "shared_link_asset"."assetId" + inner join lateral ( + select + "asset_exif"."assetId", + "asset_exif"."autoStackId", + "asset_exif"."bitsPerSample", + "asset_exif"."city", + "asset_exif"."colorspace", + "asset_exif"."country", + "asset_exif"."dateTimeOriginal", + "asset_exif"."description", + "asset_exif"."exifImageHeight", + "asset_exif"."exifImageWidth", + "asset_exif"."exposureTime", + "asset_exif"."fileSizeInByte", + "asset_exif"."fNumber", + "asset_exif"."focalLength", + "asset_exif"."fps", + "asset_exif"."iso", + "asset_exif"."latitude", + "asset_exif"."lensModel", + "asset_exif"."livePhotoCID", + "asset_exif"."longitude", + "asset_exif"."make", + "asset_exif"."model", + "asset_exif"."modifyDate", + "asset_exif"."orientation", + "asset_exif"."profileDescription", + "asset_exif"."projectionType", + "asset_exif"."rating", + "asset_exif"."state", + "asset_exif"."tags", + "asset_exif"."timeZone" + from + "asset_exif" + where + "asset_exif"."assetId" = "asset"."id" + ) as "exifInfo" on true + where + "shared_link"."id" = "shared_link_asset"."sharedLinkId" + and "asset"."deletedAt" is null + order by + "asset"."fileCreatedAt" asc + ) as agg ) as "assets", to_json("album") as "album" from "shared_link" - left join lateral ( - select - "asset".*, - to_json("exifInfo") as "exifInfo" - from - "shared_link_asset" - inner join "asset" on "asset"."id" = "shared_link_asset"."assetId" - inner join lateral ( - select - "asset_exif".* - from - "asset_exif" - where - "asset_exif"."assetId" = "asset"."id" - ) as "exifInfo" on true - where - "shared_link"."id" = "shared_link_asset"."sharedLinkId" - and "asset"."deletedAt" is null - order by - "asset"."fileCreatedAt" asc - ) as "a" on true left join lateral ( select "album".*, @@ -60,7 +87,36 @@ from "asset" inner join lateral ( select - "asset_exif".* + "asset_exif"."assetId", + "asset_exif"."autoStackId", + "asset_exif"."bitsPerSample", + "asset_exif"."city", + "asset_exif"."colorspace", + "asset_exif"."country", + "asset_exif"."dateTimeOriginal", + "asset_exif"."description", + "asset_exif"."exifImageHeight", + "asset_exif"."exifImageWidth", + "asset_exif"."exposureTime", + "asset_exif"."fileSizeInByte", + "asset_exif"."fNumber", + "asset_exif"."focalLength", + "asset_exif"."fps", + "asset_exif"."iso", + "asset_exif"."latitude", + "asset_exif"."lensModel", + "asset_exif"."livePhotoCID", + "asset_exif"."longitude", + "asset_exif"."make", + "asset_exif"."model", + "asset_exif"."modifyDate", + "asset_exif"."orientation", + "asset_exif"."profileDescription", + "asset_exif"."projectionType", + "asset_exif"."rating", + "asset_exif"."state", + "asset_exif"."tags", + "asset_exif"."timeZone" from "asset_exif" where @@ -74,7 +130,12 @@ from ) as "assets" on true inner join lateral ( select - "user".* + "id", + "name", + "email", + "avatarColor", + "profileImagePath", + "profileChangedAt" from "user" where @@ -95,9 +156,6 @@ where "shared_link"."type" = $3 or "album"."id" is not null ) -group by - "shared_link"."id", - "album".* order by "shared_link"."createdAt" desc @@ -134,21 +192,12 @@ from "album" inner join lateral ( select - "user"."id", - "user"."email", - "user"."createdAt", - "user"."profileImagePath", - "user"."isAdmin", - "user"."shouldChangePassword", - "user"."deletedAt", - "user"."oauthId", - "user"."updatedAt", - "user"."storageLabel", - "user"."name", - "user"."quotaSizeInBytes", - "user"."quotaUsageInBytes", - "user"."status", - "user"."profileChangedAt" + "id", + "name", + "email", + "avatarColor", + "profileImagePath", + "profileChangedAt" from "user" where @@ -173,6 +222,7 @@ order by select "shared_link"."id", "shared_link"."userId", + "shared_link"."albumId", "shared_link"."expiresAt", "shared_link"."showExif", "shared_link"."allowUpload", @@ -211,6 +261,7 @@ where select "shared_link"."id", "shared_link"."userId", + "shared_link"."albumId", "shared_link"."expiresAt", "shared_link"."showExif", "shared_link"."allowUpload", @@ -265,7 +316,36 @@ from "asset" inner join lateral ( select - * + "asset_exif"."assetId", + "asset_exif"."autoStackId", + "asset_exif"."bitsPerSample", + "asset_exif"."city", + "asset_exif"."colorspace", + "asset_exif"."country", + "asset_exif"."dateTimeOriginal", + "asset_exif"."description", + "asset_exif"."exifImageHeight", + "asset_exif"."exifImageWidth", + "asset_exif"."exposureTime", + "asset_exif"."fileSizeInByte", + "asset_exif"."fNumber", + "asset_exif"."focalLength", + "asset_exif"."fps", + "asset_exif"."iso", + "asset_exif"."latitude", + "asset_exif"."lensModel", + "asset_exif"."livePhotoCID", + "asset_exif"."longitude", + "asset_exif"."make", + "asset_exif"."model", + "asset_exif"."modifyDate", + "asset_exif"."orientation", + "asset_exif"."profileDescription", + "asset_exif"."projectionType", + "asset_exif"."rating", + "asset_exif"."state", + "asset_exif"."tags", + "asset_exif"."timeZone" from "asset_exif" where diff --git a/server/src/queries/sync.repository.sql b/server/src/queries/sync.repository.sql index 43c6a380bf..a4acc95e29 100644 --- a/server/src/queries/sync.repository.sql +++ b/server/src/queries/sync.repository.sql @@ -582,7 +582,6 @@ where "asset_face"."updateId" < $1 and "asset_face"."updateId" > $2 and "asset"."ownerId" = $3 - and "asset_face"."isVisible" = $4 order by "asset_face"."updateId" asc diff --git a/server/src/repositories/album.repository.ts b/server/src/repositories/album.repository.ts index 9a76b379ed..f74356c924 100644 --- a/server/src/repositories/album.repository.ts +++ b/server/src/repositories/album.repository.ts @@ -330,6 +330,7 @@ export class AlbumRepository { await db .insertInto('album_asset') .values(assetIds.map((assetId) => ({ albumId, assetId }))) + .onConflict((oc) => oc.doNothing()) .execute(); } diff --git a/server/src/repositories/config.repository.ts b/server/src/repositories/config.repository.ts index 7e8082a582..1864733f87 100644 --- a/server/src/repositories/config.repository.ts +++ b/server/src/repositories/config.repository.ts @@ -5,9 +5,11 @@ import { QueueOptions } from 'bullmq'; import { plainToInstance } from 'class-transformer'; import { validateSync } from 'class-validator'; import { Request, Response } from 'express'; +import { HelmetOptions } from 'helmet'; import { RedisOptions } from 'ioredis'; import { CLS_ID, ClsModuleOptions } from 'nestjs-cls'; import { OpenTelemetryModuleOptions } from 'nestjs-otel/lib/interfaces'; +import { readFileSync } from 'node:fs'; import { join } from 'node:path'; import { citiesFile, excludePaths, IWorker } from 'src/constants'; import { Telemetry } from 'src/decorators'; @@ -58,6 +60,10 @@ export interface EnvData { config: ClsModuleOptions; }; + helmet: { + config?: HelmetOptions; + }; + database: { config: DatabaseConnectionParams; skipMigrations: boolean; @@ -143,6 +149,25 @@ const asSet = (value: string | undefined, defaults: T[]) => { return new Set(values.length === 0 ? defaults : (values as T[])); }; +const resolveHelmetFile = (helmetFile: 'true' | 'false' | string | undefined) => { + // default is off + if (!helmetFile || helmetFile === 'false') { + return; + } + + helmetFile = + helmetFile === 'true' + ? // eslint-disable-next-line unicorn/prefer-module + join(__dirname, '..', '..', 'helmet.json') + : helmetFile; + + try { + return JSON.parse(readFileSync(helmetFile).toString()) as HelmetOptions; + } catch (error) { + throw new Error(`Failed to read helmet file: ${helmetFile}`, { cause: error }); + } +}; + const getEnv = (): EnvData => { const dto = plainToInstance(EnvDto, process.env); const errors = validateSync(dto); @@ -289,6 +314,10 @@ const getEnv = (): EnvData => { vectorExtension, }, + helmet: { + config: resolveHelmetFile(dto.IMMICH_HELMET_FILE), + }, + licensePublicKey: isProd ? productionKeys : stagingKeys, network: { diff --git a/server/src/repositories/search.repository.ts b/server/src/repositories/search.repository.ts index 13ac254654..ba72a70fdb 100644 --- a/server/src/repositories/search.repository.ts +++ b/server/src/repositories/search.repository.ts @@ -502,10 +502,7 @@ export class SearchRepository { return res.map((row) => row.lensModel!); } - private getExifField( - field: K, - userIds: string[], - ) { + private getExifField(field: 'city' | 'state' | 'country' | 'make' | 'model' | 'lensModel', userIds: string[]) { return this.db .selectFrom('asset_exif') .select(field) @@ -514,6 +511,7 @@ export class SearchRepository { .where('ownerId', '=', anyUuid(userIds)) .where('visibility', '=', AssetVisibility.Timeline) .where('deletedAt', 'is', null) - .where(field, 'is not', null); + .where(field, 'is not', null) + .where(field, '!=', ''); } } diff --git a/server/src/repositories/shared-link.repository.ts b/server/src/repositories/shared-link.repository.ts index bc81e75c81..ddfe37ef35 100644 --- a/server/src/repositories/shared-link.repository.ts +++ b/server/src/repositories/shared-link.repository.ts @@ -1,5 +1,5 @@ import { Injectable } from '@nestjs/common'; -import { Insertable, Kysely, Selectable, ShallowDehydrateObject, sql, Updateable } from 'kysely'; +import { ExpressionBuilder, Insertable, Kysely, Selectable, ShallowDehydrateObject, sql, Updateable } from 'kysely'; import { jsonArrayFrom, jsonObjectFrom } from 'kysely/helpers/postgres'; import _ from 'lodash'; import { InjectKysely } from 'nestjs-kysely'; @@ -17,6 +17,41 @@ export type SharedLinkSearchOptions = { albumId?: string; }; +const withSharedAssets = (eb: ExpressionBuilder) => { + return eb + .selectFrom('shared_link_asset') + .whereRef('shared_link.id', '=', 'shared_link_asset.sharedLinkId') + .innerJoin('asset', 'asset.id', 'shared_link_asset.assetId') + .where('asset.deletedAt', 'is', null) + .selectAll('asset') + .orderBy('asset.fileCreatedAt', 'asc'); +}; + +export const withExifInfo = (eb: ExpressionBuilder) => { + return eb + .selectFrom('asset_exif') + .select(columns.exif) + .whereRef('asset_exif.assetId', '=', 'asset.id') + .as('exifInfo'); +}; + +const withAlbumOwner = (eb: ExpressionBuilder) => { + return eb + .selectFrom('user') + .select(columns.user) + .whereRef('user.id', '=', 'album.ownerId') + .where('user.deletedAt', 'is', null) + .as('owner'); +}; + +const withSharedLinkAlbum = (eb: ExpressionBuilder) => { + return eb + .selectFrom('album') + .selectAll('album') + .whereRef('album.id', '=', 'shared_link.albumId') + .where('album.deletedAt', 'is', null); +}; + @Injectable() export class SharedLinkRepository { constructor(@InjectKysely() private db: Kysely) {} @@ -26,35 +61,16 @@ export class SharedLinkRepository { return this.db .selectFrom('shared_link') .selectAll('shared_link') - .leftJoinLateral( - (eb) => - eb - .selectFrom('shared_link_asset') - .whereRef('shared_link.id', '=', 'shared_link_asset.sharedLinkId') - .innerJoin('asset', 'asset.id', 'shared_link_asset.assetId') - .where('asset.deletedAt', 'is', null) - .selectAll('asset') - .innerJoinLateral( - (eb) => - eb - .selectFrom('asset_exif') - .selectAll('asset_exif') - .whereRef('asset_exif.assetId', '=', 'asset.id') - .as('exifInfo'), - (join) => join.onTrue(), - ) - .select((eb) => eb.fn.toJson('exifInfo').as('exifInfo')) - .orderBy('asset.fileCreatedAt', 'asc') - .as('a'), - (join) => join.onTrue(), + .select((eb) => + jsonArrayFrom( + withSharedAssets(eb) + .innerJoinLateral(withExifInfo, (join) => join.onTrue()) + .select((eb) => eb.fn.toJson('exifInfo').as('exifInfo')), + ).as('assets'), ) .leftJoinLateral( (eb) => - eb - .selectFrom('album') - .selectAll('album') - .whereRef('album.id', '=', 'shared_link.albumId') - .where('album.deletedAt', 'is', null) + withSharedLinkAlbum(eb) .leftJoin('album_asset', 'album_asset.albumId', 'album.id') .leftJoinLateral( (eb) => @@ -63,30 +79,13 @@ export class SharedLinkRepository { .selectAll('asset') .whereRef('album_asset.assetId', '=', 'asset.id') .where('asset.deletedAt', 'is', null) - .innerJoinLateral( - (eb) => - eb - .selectFrom('asset_exif') - .selectAll('asset_exif') - .whereRef('asset_exif.assetId', '=', 'asset.id') - .as('exifInfo'), - (join) => join.onTrue(), - ) + .innerJoinLateral(withExifInfo, (join) => join.onTrue()) .select((eb) => eb.fn.toJson(eb.table('exifInfo')).as('exifInfo')) .orderBy('asset.fileCreatedAt', 'asc') .as('assets'), (join) => join.onTrue(), ) - .innerJoinLateral( - (eb) => - eb - .selectFrom('user') - .selectAll('user') - .whereRef('user.id', '=', 'album.ownerId') - .where('user.deletedAt', 'is', null) - .as('owner'), - (join) => join.onTrue(), - ) + .innerJoinLateral(withAlbumOwner, (join) => join.onTrue()) .select((eb) => eb.fn .coalesce( @@ -104,17 +103,6 @@ export class SharedLinkRepository { .as('album'), (join) => join.onTrue(), ) - .select((eb) => - eb.fn - .coalesce(eb.fn.jsonAgg('a').filterWhere('a.id', 'is not', null), sql`'[]'`) - .$castTo< - (ShallowDehydrateObject> & { - exifInfo: ShallowDehydrateObject>; - })[] - >() - .as('assets'), - ) - .groupBy(['shared_link.id', sql`"album".*`]) .select((eb) => eb.fn.toJson(eb.table('album')).$castTo | null>().as('album')) .where('shared_link.id', '=', id) .where('shared_link.userId', '=', userId) @@ -128,53 +116,13 @@ export class SharedLinkRepository { return this.db .selectFrom('shared_link') .selectAll('shared_link') + .select((eb) => jsonArrayFrom(withSharedAssets(eb).limit(1)).as('assets')) .where('shared_link.userId', '=', userId) - .select((eb) => - jsonArrayFrom( - eb - .selectFrom('shared_link_asset') - .whereRef('shared_link.id', '=', 'shared_link_asset.sharedLinkId') - .innerJoin('asset', 'asset.id', 'shared_link_asset.assetId') - .where('asset.deletedAt', 'is', null) - .selectAll('asset') - .orderBy('asset.fileCreatedAt', 'asc') - .limit(1), - ).as('assets'), - ) .leftJoinLateral( (eb) => - eb - .selectFrom('album') - .selectAll('album') - .whereRef('album.id', '=', 'shared_link.albumId') - .innerJoinLateral( - (eb) => - eb - .selectFrom('user') - .select([ - 'user.id', - 'user.email', - 'user.createdAt', - 'user.profileImagePath', - 'user.isAdmin', - 'user.shouldChangePassword', - 'user.deletedAt', - 'user.oauthId', - 'user.updatedAt', - 'user.storageLabel', - 'user.name', - 'user.quotaSizeInBytes', - 'user.quotaUsageInBytes', - 'user.status', - 'user.profileChangedAt', - ]) - .whereRef('user.id', '=', 'album.ownerId') - .where('user.deletedAt', 'is', null) - .as('owner'), - (join) => join.onTrue(), - ) + withSharedLinkAlbum(eb) + .innerJoinLateral(withAlbumOwner, (join) => join.onTrue()) .select((eb) => eb.fn.toJson('owner').as('owner')) - .where('album.deletedAt', 'is', null) .as('album'), (join) => join.onTrue(), ) @@ -202,7 +150,14 @@ export class SharedLinkRepository { .leftJoin('album', 'album.id', 'shared_link.albumId') .where('album.deletedAt', 'is', null) .select((eb) => [ - ...columns.authSharedLink, + 'shared_link.id', + 'shared_link.userId', + 'shared_link.albumId', + 'shared_link.expiresAt', + 'shared_link.showExif', + 'shared_link.allowUpload', + 'shared_link.allowDownload', + 'shared_link.password', jsonObjectFrom( eb.selectFrom('user').select(columns.authUser).whereRef('user.id', '=', 'shared_link.userId'), ).as('user'), @@ -276,11 +231,7 @@ export class SharedLinkRepository { .selectFrom('asset') .whereRef('asset.id', '=', 'shared_link_asset.assetId') .selectAll('asset') - .innerJoinLateral( - (eb) => - eb.selectFrom('asset_exif').whereRef('asset_exif.assetId', '=', 'asset.id').selectAll().as('exifInfo'), - (join) => join.onTrue(), - ) + .innerJoinLateral(withExifInfo, (join) => join.onTrue()) .as('assets'), (join) => join.onTrue(), ) diff --git a/server/src/repositories/sync.repository.ts b/server/src/repositories/sync.repository.ts index b2fa144ca4..486bf15163 100644 --- a/server/src/repositories/sync.repository.ts +++ b/server/src/repositories/sync.repository.ts @@ -487,7 +487,6 @@ class AssetFaceSync extends BaseSync { ]) .leftJoin('asset', 'asset.id', 'asset_face.assetId') .where('asset.ownerId', '=', options.userId) - .where('asset_face.isVisible', '=', true) .stream(); } } diff --git a/server/src/schema/migrations/1773956345315-DuplicateSharedLinkAssets.ts b/server/src/schema/migrations/1773956345315-DuplicateSharedLinkAssets.ts new file mode 100644 index 0000000000..d3a83d53dc --- /dev/null +++ b/server/src/schema/migrations/1773956345315-DuplicateSharedLinkAssets.ts @@ -0,0 +1,13 @@ +import { Kysely, sql } from 'kysely'; + +export async function up(db: Kysely): Promise { + await sql` + DELETE FROM "shared_link_asset" + USING "shared_link" + WHERE "shared_link_asset"."sharedLinkId" = "shared_link"."id" AND "shared_link"."type" = 'ALBUM'; +`.execute(db); +} + +export async function down(): Promise { + // noop +} diff --git a/server/src/schema/migrations/1774393726320-AssetFaceSyncReset.ts b/server/src/schema/migrations/1774393726320-AssetFaceSyncReset.ts new file mode 100644 index 0000000000..8dcd238bc0 --- /dev/null +++ b/server/src/schema/migrations/1774393726320-AssetFaceSyncReset.ts @@ -0,0 +1,10 @@ +import { Kysely, sql } from 'kysely'; + +export async function up(db: Kysely): Promise { + // Sync query for faces was incorrect on server <=2.6.2 + await sql`DELETE FROM session_sync_checkpoint WHERE type in ('AssetFaceV1', 'AssetFaceV2')`.execute(db); +} + +export async function down(): Promise { + // Not implemented +} diff --git a/server/src/services/album.service.ts b/server/src/services/album.service.ts index 24b9b165c9..547ec63bf8 100644 --- a/server/src/services/album.service.ts +++ b/server/src/services/album.service.ts @@ -165,6 +165,12 @@ export class AlbumService extends BaseService { } async addAssets(auth: AuthDto, id: string, dto: BulkIdsDto): Promise { + if (auth.sharedLink) { + this.logger.deprecate( + 'Assets uploaded to a shared link are automatically added and calling this endpoint is no longer necessary. It will be removed in the next major release.', + ); + } + const album = await this.findOrFail(id, { withAssets: false }); await this.requireAccess({ auth, permission: Permission.AlbumAssetCreate, ids: [id] }); @@ -195,6 +201,12 @@ export class AlbumService extends BaseService { } async addAssetsToAlbums(auth: AuthDto, dto: AlbumsAddAssetsDto): Promise { + if (auth.sharedLink) { + this.logger.deprecate( + 'Assets uploaded to a shared link are automatically added and calling this endpoint is no longer necessary. It will be removed in the next major release.', + ); + } + const results: AlbumsAddAssetsResponseDto = { success: false, error: BulkIdErrorReason.DUPLICATE, diff --git a/server/src/services/asset-media.service.ts b/server/src/services/asset-media.service.ts index 3c981ea61e..03677054ec 100644 --- a/server/src/services/asset-media.service.ts +++ b/server/src/services/asset-media.service.ts @@ -2,7 +2,7 @@ import { BadRequestException, Injectable, InternalServerErrorException, NotFound import { extname } from 'node:path'; import sanitize from 'sanitize-filename'; import { StorageCore } from 'src/cores/storage.core'; -import { Asset } from 'src/database'; +import { Asset, AuthSharedLink } from 'src/database'; import { AssetBulkUploadCheckResponseDto, AssetMediaResponseDto, @@ -152,7 +152,7 @@ export class AssetMediaService extends BaseService { const asset = await this.create(auth.user.id, dto, file, sidecarFile); if (auth.sharedLink) { - await this.sharedLinkRepository.addAssets(auth.sharedLink.id, [asset.id]); + await this.addToSharedLink(auth.sharedLink, asset.id); } await this.userRepository.updateUsage(auth.user.id, file.size); @@ -326,6 +326,12 @@ export class AssetMediaService extends BaseService { }; } + private async addToSharedLink(sharedLink: AuthSharedLink, assetId: string) { + await (sharedLink.albumId + ? this.albumRepository.addAssetIds(sharedLink.albumId, [assetId]) + : this.sharedLinkRepository.addAssets(sharedLink.id, [assetId])); + } + private async handleUploadError( error: any, auth: AuthDto, @@ -347,9 +353,10 @@ export class AssetMediaService extends BaseService { } if (auth.sharedLink) { - await this.sharedLinkRepository.addAssets(auth.sharedLink.id, [duplicateId]); + await this.addToSharedLink(auth.sharedLink, duplicateId); } + this.logger.debug(`Duplicate asset upload rejected: existing asset ${duplicateId}`); return { status: AssetMediaStatus.DUPLICATE, id: duplicateId }; } diff --git a/server/src/services/database-backup.service.spec.ts b/server/src/services/database-backup.service.spec.ts index 429e60aede..37964e7b6f 100644 --- a/server/src/services/database-backup.service.spec.ts +++ b/server/src/services/database-backup.service.spec.ts @@ -27,6 +27,7 @@ describe(DatabaseBackupService.name, () => { mocks.systemMetadata as never, mocks.process, mocks.database as never, + mocks.user as never, mocks.cron as never, mocks.job as never, maintenanceHealthRepositoryMock as never, @@ -187,6 +188,7 @@ describe(DatabaseBackupService.name, () => { mocks.systemMetadata as never, mocks.process, mocks.database as never, + mocks.user as never, mocks.cron as never, mocks.job as never, void 0 as never, @@ -400,6 +402,7 @@ describe(DatabaseBackupService.name, () => { mocks.systemMetadata as never, mocks.process, mocks.database as never, + mocks.user as never, mocks.cron as never, mocks.job as never, void 0 as never, @@ -474,6 +477,7 @@ describe(DatabaseBackupService.name, () => { mocks.systemMetadata as never, mocks.process, mocks.database as never, + mocks.user as never, mocks.cron as never, mocks.job as never, void 0 as never, @@ -536,6 +540,7 @@ describe(DatabaseBackupService.name, () => { mocks.systemMetadata as never, mocks.process, mocks.database as never, + mocks.user as never, mocks.cron as never, mocks.job as never, void 0 as never, @@ -663,6 +668,7 @@ describe(DatabaseBackupService.name, () => { mocks.systemMetadata as never, mocks.process, mocks.database as never, + mocks.user as never, mocks.cron as never, mocks.job as never, maintenanceHealthRepositoryMock, @@ -678,6 +684,8 @@ describe(DatabaseBackupService.name, () => { it('should successfully restore a backup', async () => { let writtenToPsql = ''; + mocks.user.hasAdmin.mockResolvedValue(true); + mocks.process.spawnDuplexStream.mockImplementationOnce(() => mockDuplex()('command', 0, 'data', '')); mocks.process.spawnDuplexStream.mockImplementationOnce(() => mockDuplex()('command', 0, 'data', '')); mocks.process.spawnDuplexStream.mockImplementationOnce(() => { @@ -740,6 +748,8 @@ describe(DatabaseBackupService.name, () => { it('should generate pg_dumpall specific SQL instructions', async () => { let writtenToPsql = ''; + mocks.user.hasAdmin.mockResolvedValue(true); + mocks.process.spawnDuplexStream.mockImplementationOnce(() => mockDuplex()('command', 0, 'data', '')); mocks.process.spawnDuplexStream.mockImplementationOnce(() => mockDuplex()('command', 0, 'data', '')); mocks.process.spawnDuplexStream.mockImplementationOnce(() => { @@ -834,7 +844,24 @@ describe(DatabaseBackupService.name, () => { expect(mocks.process.spawnDuplexStream).toHaveBeenCalledTimes(4); }); + it('should rollback if there is no admin user', async () => { + mocks.user.hasAdmin.mockResolvedValue(false); + + const progress = vitest.fn(); + await expect( + sut.restoreDatabaseBackup('development-filename.sql', progress), + ).rejects.toThrowErrorMatchingInlineSnapshot(`[Error: Server health check failed, no admin exists.]`); + + expect(progress).toHaveBeenCalledWith('backup', 0.05); + expect(progress).toHaveBeenCalledWith('migrations', 0.9); + expect(progress).toHaveBeenCalledWith('rollback', 0); + + expect(mocks.user.hasAdmin).toHaveBeenCalled(); + expect(mocks.process.spawnDuplexStream).toHaveBeenCalledTimes(4); + }); + it('should rollback if API healthcheck fails', async () => { + mocks.user.hasAdmin.mockResolvedValue(true); maintenanceHealthRepositoryMock.checkApiHealth.mockRejectedValue(new Error('Health Error')); const progress = vitest.fn(); @@ -846,6 +873,7 @@ describe(DatabaseBackupService.name, () => { expect(progress).toHaveBeenCalledWith('migrations', 0.9); expect(progress).toHaveBeenCalledWith('rollback', 0); + expect(mocks.user.hasAdmin).toHaveBeenCalled(); expect(maintenanceHealthRepositoryMock.checkApiHealth).toHaveBeenCalled(); expect(mocks.process.spawnDuplexStream).toHaveBeenCalledTimes(4); }); diff --git a/server/src/services/database-backup.service.ts b/server/src/services/database-backup.service.ts index 3c964c950c..666ddcff0a 100644 --- a/server/src/services/database-backup.service.ts +++ b/server/src/services/database-backup.service.ts @@ -20,6 +20,7 @@ import { LoggingRepository } from 'src/repositories/logging.repository'; import { ProcessRepository } from 'src/repositories/process.repository'; import { StorageRepository } from 'src/repositories/storage.repository'; import { SystemMetadataRepository } from 'src/repositories/system-metadata.repository'; +import { UserRepository } from 'src/repositories/user.repository'; import { getConfig } from 'src/utils/config'; import { findDatabaseBackupVersion, @@ -40,6 +41,7 @@ export class DatabaseBackupService { private readonly systemMetadataRepository: SystemMetadataRepository, private readonly processRepository: ProcessRepository, private readonly databaseRepository: DatabaseRepository, + private readonly userRepository: UserRepository, @Optional() private readonly cronRepository: CronRepository, @Optional() @@ -405,7 +407,14 @@ export class DatabaseBackupService { try { progressCb?.('migrations', 0.9); + await this.databaseRepository.runMigrations(); + + const hasAdmin = await this.userRepository.hasAdmin(); + if (!hasAdmin) { + throw new Error('Server health check failed, no admin exists.'); + } + await this.maintenanceHealthRepository.checkApiHealth(); } catch (error) { progressCb?.('rollback', 0); diff --git a/server/src/services/metadata.service.spec.ts b/server/src/services/metadata.service.spec.ts index 7cb42990ea..cb35e21d0a 100644 --- a/server/src/services/metadata.service.spec.ts +++ b/server/src/services/metadata.service.spec.ts @@ -1641,12 +1641,32 @@ describe(MetadataService.name, () => { ); }); - it('should not overwrite existing width/height if they already exist', async () => { - const asset = AssetFactory.create({ width: 1920, height: 1080 }); + it('should overwrite existing width/height for unedited assets', async () => { + const asset = AssetFactory.create({ width: 1920, height: 1080, isEdited: false }); mocks.assetJob.getForMetadataExtraction.mockResolvedValue(getForMetadataExtraction(asset)); mockReadTags({ ImageWidth: 1280, ImageHeight: 720 }); await sut.handleMetadataExtraction({ id: asset.id }); + expect(mocks.asset.update).toHaveBeenCalledWith( + expect.objectContaining({ + width: 1280, + height: 720, + }), + ); + }); + + it('should not overwrite existing width/height for edited assets', async () => { + const asset = AssetFactory.create({ width: 1920, height: 1080, isEdited: true }); + mocks.assetJob.getForMetadataExtraction.mockResolvedValue(getForMetadataExtraction(asset)); + mockReadTags({ ImageWidth: 1280, ImageHeight: 720 }); + + await sut.handleMetadataExtraction({ id: asset.id }); + expect(mocks.asset.update).toHaveBeenCalledWith( + expect.objectContaining({ + width: undefined, + height: undefined, + }), + ); expect(mocks.asset.update).not.toHaveBeenCalledWith( expect.objectContaining({ width: 1280, diff --git a/server/src/services/metadata.service.ts b/server/src/services/metadata.service.ts index 7b87ea06a6..bfbcb413c0 100644 --- a/server/src/services/metadata.service.ts +++ b/server/src/services/metadata.service.ts @@ -327,10 +327,9 @@ export class MetadataService extends BaseService { fileCreatedAt: dates.dateTimeOriginal ?? undefined, fileModifiedAt: stats.mtime, - // only update the dimensions if they don't already exist - // we don't want to overwrite width/height that are modified by edits - width: asset.width == null ? assetWidth : undefined, - height: asset.height == null ? assetHeight : undefined, + // Keep unedited assets in sync with the file on disk, but don't overwrite edited dimensions. + width: !asset.isEdited || asset.width == null ? assetWidth : undefined, + height: !asset.isEdited || asset.height == null ? assetHeight : undefined, }), async () => { await this.assetRepository.upsertExif(exifData, { lockedPropertiesBehavior: 'skip' }); diff --git a/server/src/services/version.service.spec.ts b/server/src/services/version.service.spec.ts index 7872f720a9..eacae928eb 100644 --- a/server/src/services/version.service.spec.ts +++ b/server/src/services/version.service.spec.ts @@ -1,5 +1,6 @@ import { DateTime } from 'luxon'; import { SemVer } from 'semver'; +import { defaults } from 'src/config'; import { serverVersion } from 'src/constants'; import { ImmichEnvironment, JobName, JobStatus, SystemMetadataKey } from 'src/enum'; import { VersionService } from 'src/services/version.service'; @@ -130,6 +131,32 @@ describe(VersionService.name, () => { }); }); + describe('onConfigUpdate', () => { + it('should queue a version check job when newVersionCheck is enabled', async () => { + await sut.onConfigUpdate({ + oldConfig: { ...defaults, newVersionCheck: { enabled: false } }, + newConfig: { ...defaults, newVersionCheck: { enabled: true } }, + }); + expect(mocks.job.queue).toHaveBeenCalledWith({ name: JobName.VersionCheck, data: {} }); + }); + + it('should not queue a version check job when newVersionCheck is disabled', async () => { + await sut.onConfigUpdate({ + oldConfig: { ...defaults, newVersionCheck: { enabled: true } }, + newConfig: { ...defaults, newVersionCheck: { enabled: false } }, + }); + expect(mocks.job.queue).not.toHaveBeenCalled(); + }); + + it('should not queue a version check job when newVersionCheck was already enabled', async () => { + await sut.onConfigUpdate({ + oldConfig: { ...defaults, newVersionCheck: { enabled: true } }, + newConfig: { ...defaults, newVersionCheck: { enabled: true } }, + }); + expect(mocks.job.queue).not.toHaveBeenCalled(); + }); + }); + describe('onWebsocketConnection', () => { it('should send on_server_version client event', async () => { await sut.onWebsocketConnection({ userId: '42' }); diff --git a/server/src/services/version.service.ts b/server/src/services/version.service.ts index fd51fa9adf..fc51481cad 100644 --- a/server/src/services/version.service.ts +++ b/server/src/services/version.service.ts @@ -55,6 +55,13 @@ export class VersionService extends BaseService { return this.versionRepository.getAll(); } + @OnEvent({ name: 'ConfigUpdate' }) + async onConfigUpdate({ oldConfig, newConfig }: ArgOf<'ConfigUpdate'>) { + if (!oldConfig.newVersionCheck.enabled && newConfig.newVersionCheck.enabled) { + await this.handleQueueVersionCheck(); + } + } + async handleQueueVersionCheck() { await this.jobRepository.queue({ name: JobName.VersionCheck, data: {} }); } diff --git a/server/src/utils/access.ts b/server/src/utils/access.ts index 7431cb3293..2e0f7d10d0 100644 --- a/server/src/utils/access.ts +++ b/server/src/utils/access.ts @@ -190,7 +190,13 @@ const checkOtherAccess = async (access: AccessRepository, request: OtherAccessRe } case Permission.AlbumUpdate: { - return await access.album.checkOwnerAccess(auth.user.id, ids); + const isOwner = await access.album.checkOwnerAccess(auth.user.id, ids); + const isShared = await access.album.checkSharedAlbumAccess( + auth.user.id, + setDifference(ids, isOwner), + AlbumUserRole.Editor, + ); + return setUnion(isOwner, isShared); } case Permission.AlbumDelete: { @@ -198,7 +204,13 @@ const checkOtherAccess = async (access: AccessRepository, request: OtherAccessRe } case Permission.AlbumShare: { - return await access.album.checkOwnerAccess(auth.user.id, ids); + const isOwner = await access.album.checkOwnerAccess(auth.user.id, ids); + const isShared = await access.album.checkSharedAlbumAccess( + auth.user.id, + setDifference(ids, isOwner), + AlbumUserRole.Editor, + ); + return setUnion(isOwner, isShared); } case Permission.AlbumDownload: { diff --git a/server/test/fixtures/auth.stub.ts b/server/test/fixtures/auth.stub.ts index 3e5825c0cc..85d52f14a1 100644 --- a/server/test/fixtures/auth.stub.ts +++ b/server/test/fixtures/auth.stub.ts @@ -48,6 +48,7 @@ export const authStub = { showExif: true, allowDownload: true, allowUpload: true, + albumId: null, expiresAt: null, password: null, userId: '42', diff --git a/server/test/mappers.ts b/server/test/mappers.ts index 7f324663be..2f3b248576 100644 --- a/server/test/mappers.ts +++ b/server/test/mappers.ts @@ -138,6 +138,7 @@ export const getForMetadataExtraction = (asset: ReturnType getDehydrated(face)), diff --git a/server/test/medium.factory.ts b/server/test/medium.factory.ts index 53bf78b5b8..a8aa00c2a3 100644 --- a/server/test/medium.factory.ts +++ b/server/test/medium.factory.ts @@ -220,9 +220,9 @@ export class MediumTestContext { return { result }; } - async newAlbum(dto: Insertable) { + async newAlbum(dto: Insertable, assetIds?: string[]) { const album = mediumFactory.albumInsert(dto); - const result = await this.get(AlbumRepository).create(album, [], []); + const result = await this.get(AlbumRepository).create(album, assetIds ?? [], []); return { album, result }; } diff --git a/server/test/medium/specs/services/asset-media.service.spec.ts b/server/test/medium/specs/services/asset-media.service.spec.ts index cdd47e3dc4..f10844ca4a 100644 --- a/server/test/medium/specs/services/asset-media.service.spec.ts +++ b/server/test/medium/specs/services/asset-media.service.spec.ts @@ -1,12 +1,15 @@ import { Kysely } from 'kysely'; +import { randomBytes } from 'node:crypto'; import { AssetMediaStatus } from 'src/dtos/asset-media-response.dto'; import { AssetMediaSize } from 'src/dtos/asset-media.dto'; -import { AssetFileType } from 'src/enum'; +import { AssetFileType, SharedLinkType } from 'src/enum'; import { AccessRepository } from 'src/repositories/access.repository'; +import { AlbumRepository } from 'src/repositories/album.repository'; import { AssetRepository } from 'src/repositories/asset.repository'; import { EventRepository } from 'src/repositories/event.repository'; import { JobRepository } from 'src/repositories/job.repository'; import { LoggingRepository } from 'src/repositories/logging.repository'; +import { SharedLinkRepository } from 'src/repositories/shared-link.repository'; import { StorageRepository } from 'src/repositories/storage.repository'; import { UserRepository } from 'src/repositories/user.repository'; import { DB } from 'src/schema'; @@ -22,7 +25,7 @@ let defaultDatabase: Kysely; const setup = (db?: Kysely) => { return newMediumService(AssetMediaService, { database: db || defaultDatabase, - real: [AccessRepository, AssetRepository, UserRepository], + real: [AccessRepository, AlbumRepository, AssetRepository, SharedLinkRepository, UserRepository], mock: [EventRepository, LoggingRepository, JobRepository, StorageRepository], }); }; @@ -44,7 +47,6 @@ describe(AssetService.name, () => { const { asset } = await ctx.newAsset({ ownerId: user.id }); await ctx.newExif({ assetId: asset.id, fileSizeInByte: 12_345 }); const auth = factory.auth({ user: { id: user.id } }); - const file = mediumFactory.uploadFile(); await expect( sut.uploadAsset( @@ -56,7 +58,7 @@ describe(AssetService.name, () => { fileCreatedAt: new Date(), assetData: Buffer.from('some data'), }, - file, + mediumFactory.uploadFile(), ), ).resolves.toEqual({ id: expect.any(String), @@ -99,6 +101,168 @@ describe(AssetService.name, () => { status: AssetMediaStatus.CREATED, }); }); + + it('should add to a shared link', async () => { + const { sut, ctx } = setup(); + + const sharedLinkRepo = ctx.get(SharedLinkRepository); + + ctx.getMock(StorageRepository).utimes.mockResolvedValue(); + ctx.getMock(EventRepository).emit.mockResolvedValue(); + ctx.getMock(JobRepository).queue.mockResolvedValue(); + + const { user } = await ctx.newUser(); + + const sharedLink = await sharedLinkRepo.create({ + key: randomBytes(50), + type: SharedLinkType.Individual, + description: 'Shared link description', + userId: user.id, + allowDownload: true, + allowUpload: true, + }); + + const auth = factory.auth({ user: { id: user.id }, sharedLink }); + const file = mediumFactory.uploadFile(); + const uploadDto = { + deviceId: 'some-id', + deviceAssetId: 'some-id', + fileModifiedAt: new Date(), + fileCreatedAt: new Date(), + assetData: Buffer.from('some data'), + }; + + const response = await sut.uploadAsset(auth, uploadDto, file); + expect(response).toEqual({ id: expect.any(String), status: AssetMediaStatus.CREATED }); + + const update = await sharedLinkRepo.get(user.id, sharedLink.id); + const assets = update!.assets; + expect(assets).toHaveLength(1); + expect(assets[0]).toMatchObject({ id: response.id }); + }); + + it('should handle adding a duplicate asset to a shared link', async () => { + const { sut, ctx } = setup(); + + ctx.getMock(StorageRepository).utimes.mockResolvedValue(); + ctx.getMock(EventRepository).emit.mockResolvedValue(); + ctx.getMock(JobRepository).queue.mockResolvedValue(); + + const sharedLinkRepo = ctx.get(SharedLinkRepository); + + const { user } = await ctx.newUser(); + const { asset } = await ctx.newAsset({ ownerId: user.id }); + await ctx.newExif({ assetId: asset.id, fileSizeInByte: 12_345 }); + + const sharedLink = await sharedLinkRepo.create({ + key: randomBytes(50), + type: SharedLinkType.Individual, + description: 'Shared link description', + userId: user.id, + allowDownload: true, + allowUpload: true, + assetIds: [asset.id], + }); + + const auth = factory.auth({ user: { id: user.id }, sharedLink }); + const uploadDto = { + deviceId: 'some-id', + deviceAssetId: 'some-id', + fileModifiedAt: new Date(), + fileCreatedAt: new Date(), + assetData: Buffer.from('some data'), + }; + + const response = await sut.uploadAsset(auth, uploadDto, mediumFactory.uploadFile({ checksum: asset.checksum })); + expect(response).toEqual({ id: expect.any(String), status: AssetMediaStatus.DUPLICATE }); + + const update = await sharedLinkRepo.get(user.id, sharedLink.id); + const assets = update!.assets; + expect(assets).toHaveLength(1); + expect(assets[0]).toMatchObject({ id: response.id }); + }); + + it('should add to an album shared link', async () => { + const { sut, ctx } = setup(); + + const sharedLinkRepo = ctx.get(SharedLinkRepository); + + ctx.getMock(StorageRepository).utimes.mockResolvedValue(); + ctx.getMock(EventRepository).emit.mockResolvedValue(); + ctx.getMock(JobRepository).queue.mockResolvedValue(); + + const { user } = await ctx.newUser(); + const { album } = await ctx.newAlbum({ ownerId: user.id }); + + const sharedLink = await sharedLinkRepo.create({ + key: randomBytes(50), + type: SharedLinkType.Album, + albumId: album.id, + description: 'Shared link description', + userId: user.id, + allowDownload: true, + allowUpload: true, + }); + + const auth = factory.auth({ user: { id: user.id }, sharedLink }); + const uploadDto = { + deviceId: 'some-id', + deviceAssetId: 'some-id', + fileModifiedAt: new Date(), + fileCreatedAt: new Date(), + assetData: Buffer.from('some data'), + }; + + const response = await sut.uploadAsset(auth, uploadDto, mediumFactory.uploadFile()); + expect(response).toEqual({ id: expect.any(String), status: AssetMediaStatus.CREATED }); + + const result = await ctx.get(AlbumRepository).getAssetIds(album.id, [response.id]); + const assets = [...result]; + expect(assets).toHaveLength(1); + expect(assets[0]).toEqual(response.id); + }); + + it('should handle adding a duplicate asset to an album shared link', async () => { + const { sut, ctx } = setup(); + + const sharedLinkRepo = ctx.get(SharedLinkRepository); + + ctx.getMock(StorageRepository).utimes.mockResolvedValue(); + ctx.getMock(EventRepository).emit.mockResolvedValue(); + ctx.getMock(JobRepository).queue.mockResolvedValue(); + + const { user } = await ctx.newUser(); + const { asset } = await ctx.newAsset({ ownerId: user.id }); + const { album } = await ctx.newAlbum({ ownerId: user.id }, [asset.id]); + // await ctx.newExif({ assetId: asset.id, fileSizeInByte: 12_345 }); + + const sharedLink = await sharedLinkRepo.create({ + key: randomBytes(50), + type: SharedLinkType.Album, + albumId: album.id, + description: 'Shared link description', + userId: user.id, + allowDownload: true, + allowUpload: true, + }); + + const auth = factory.auth({ user: { id: user.id }, sharedLink }); + const uploadDto = { + deviceId: 'some-id', + deviceAssetId: 'some-id', + fileModifiedAt: new Date(), + fileCreatedAt: new Date(), + assetData: Buffer.from('some data'), + }; + + const response = await sut.uploadAsset(auth, uploadDto, mediumFactory.uploadFile({ checksum: asset.checksum })); + expect(response).toEqual({ id: expect.any(String), status: AssetMediaStatus.DUPLICATE }); + + const result = await ctx.get(AlbumRepository).getAssetIds(album.id, [response.id]); + const assets = [...result]; + expect(assets).toHaveLength(1); + expect(assets[0]).toEqual(response.id); + }); }); describe('viewThumbnail', () => { diff --git a/server/test/medium/specs/services/search.service.spec.ts b/server/test/medium/specs/services/search.service.spec.ts index c20b64ca7c..18e03b2e48 100644 --- a/server/test/medium/specs/services/search.service.spec.ts +++ b/server/test/medium/specs/services/search.service.spec.ts @@ -1,4 +1,5 @@ import { Kysely } from 'kysely'; +import { SearchSuggestionType } from 'src/dtos/search.dto'; import { AccessRepository } from 'src/repositories/access.repository'; import { AssetRepository } from 'src/repositories/asset.repository'; import { DatabaseRepository } from 'src/repositories/database.repository'; @@ -108,4 +109,25 @@ describe(SearchService.name, () => { expect(response.assets.items[0].id).toBe(unstackedAsset.id); }); }); + + describe('getSearchSuggestions', () => { + it('should filter out empty search suggestions', async () => { + const { sut, ctx } = setup(); + const { user } = await ctx.newUser(); + + const { asset } = await ctx.newAsset({ ownerId: user.id }); + await ctx.newExif({ assetId: asset.id, make: 'Canon' }); + + const { asset: assetWithEmptyMake } = await ctx.newAsset({ ownerId: user.id }); + await ctx.newExif({ assetId: assetWithEmptyMake.id, make: '' }); + + const auth = factory.auth({ user: { id: user.id } }); + const suggestions = await sut.getSearchSuggestions(auth, { + type: SearchSuggestionType.CAMERA_MAKE, + includeNull: true, + }); + + expect(suggestions).toEqual(['Canon', null]); + }); + }); }); diff --git a/server/test/medium/specs/services/shared-link.service.spec.ts b/server/test/medium/specs/services/shared-link.service.spec.ts index 5873d469a5..347e2e9506 100644 --- a/server/test/medium/specs/services/shared-link.service.spec.ts +++ b/server/test/medium/specs/services/shared-link.service.spec.ts @@ -372,6 +372,43 @@ describe(SharedLinkService.name, () => { }); describe('get', () => { + it('should return an album shared link with assets', async () => { + const { sut, ctx } = setup(); + const { user } = await ctx.newUser(); + const auth = factory.auth({ user }); + const { album } = await ctx.newAlbum({ ownerId: user.id }); + + const [{ asset: asset1 }, { asset: asset2 }] = await Promise.all([ + ctx.newAsset({ ownerId: user.id }), + ctx.newAsset({ ownerId: user.id }), + ]); + await Promise.all([ + ctx.newExif({ assetId: asset1.id, make: 'Canon' }), + ctx.newExif({ assetId: asset2.id, make: 'Canon' }), + ]); + + const sharedLinkRepo = ctx.get(SharedLinkRepository); + const sharedLink = await sharedLinkRepo.create({ + key: randomBytes(16), + id: factory.uuid(), + userId: user.id, + albumId: album.id, + allowUpload: true, + type: SharedLinkType.Album, + }); + + await sharedLinkRepo.addAssets(sharedLink.id, [asset1.id, asset2.id]); + const result = await sut.get(auth, sharedLink.id); + const assetIds = result.assets.map((asset) => asset.id); + + expect(result).toMatchObject({ + id: sharedLink.id, + album: expect.objectContaining({ id: album.id }), + }); + expect(assetIds).toHaveLength(2); + expect(assetIds).toEqual(expect.arrayContaining([asset1.id, asset2.id])); + }); + it('should not return trashed assets for an individual shared link', async () => { const { sut, ctx } = setup(); const { user } = await ctx.newUser(); diff --git a/server/test/repositories/config.repository.mock.ts b/server/test/repositories/config.repository.mock.ts index 62e498372e..b5ab6e2054 100644 --- a/server/test/repositories/config.repository.mock.ts +++ b/server/test/repositories/config.repository.mock.ts @@ -35,6 +35,10 @@ const envData: EnvData = { vectorExtension: DatabaseExtension.Vectors, }, + helmet: { + config: {}, + }, + licensePublicKey: { client: 'client-public-key', server: 'server-public-key', diff --git a/server/test/small.factory.ts b/server/test/small.factory.ts index 57098e01ee..e4001d18ab 100644 --- a/server/test/small.factory.ts +++ b/server/test/small.factory.ts @@ -63,12 +63,22 @@ const authSharedLinkFactory = (sharedLink: Partial = {}) => { expiresAt = null, userId = newUuid(), showExif = true, + albumId = null, allowUpload = false, allowDownload = true, password = null, } = sharedLink; - return { id, expiresAt, userId, showExif, allowUpload, allowDownload, password }; + return { + id, + albumId, + expiresAt, + userId, + showExif, + allowUpload, + allowDownload, + password, + }; }; const authApiKeyFactory = (apiKey: Partial = {}) => ({ diff --git a/web/.nvmrc b/web/.nvmrc index 32f8c50de0..d845d9d88d 100644 --- a/web/.nvmrc +++ b/web/.nvmrc @@ -1 +1 @@ -24.13.1 +24.14.0 diff --git a/web/package.json b/web/package.json index ef0310f6be..8007bc5d9d 100644 --- a/web/package.json +++ b/web/package.json @@ -1,6 +1,6 @@ { "name": "immich-web", - "version": "2.6.1", + "version": "2.6.3", "license": "GNU Affero General Public License version 3", "type": "module", "scripts": { @@ -27,7 +27,7 @@ "@formatjs/icu-messageformat-parser": "^3.0.0", "@immich/justified-layout-wasm": "^0.4.3", "@immich/sdk": "workspace:*", - "@immich/ui": "^0.65.3", + "@immich/ui": "^0.69.0", "@mapbox/mapbox-gl-rtl-text": "0.3.0", "@mdi/js": "^7.4.47", "@photo-sphere-viewer/core": "^5.14.0", @@ -72,10 +72,10 @@ "@koddsson/eslint-plugin-tscompat": "^0.2.0", "@socket.io/component-emitter": "^3.1.0", "@sveltejs/adapter-static": "^3.0.8", - "@sveltejs/enhanced-img": "^0.10.0", + "@sveltejs/enhanced-img": "^0.10.4", "@sveltejs/kit": "^2.27.1", - "@sveltejs/vite-plugin-svelte": "6.2.4", - "@tailwindcss/vite": "^4.1.7", + "@sveltejs/vite-plugin-svelte": "7.0.0", + "@tailwindcss/vite": "^4.2.2", "@testing-library/jest-dom": "^6.4.2", "@testing-library/svelte": "^5.2.8", "@testing-library/user-event": "^14.5.2", @@ -100,16 +100,16 @@ "prettier-plugin-sort-json": "^4.1.1", "prettier-plugin-svelte": "^3.3.3", "rollup-plugin-visualizer": "^6.0.0", - "svelte": "5.53.7", + "svelte": "5.54.1", "svelte-check": "^4.1.5", "svelte-eslint-parser": "^1.3.3", - "tailwindcss": "^4.1.7", + "tailwindcss": "^4.2.2", "typescript": "^5.8.3", "typescript-eslint": "^8.45.0", - "vite": "^7.1.2", + "vite": "^8.0.0", "vitest": "^4.0.0" }, "volta": { - "node": "24.13.1" + "node": "24.14.0" } } diff --git a/web/src/lib/components/ToastAction.svelte b/web/src/lib/components/ToastAction.svelte deleted file mode 100644 index 5dc430f323..0000000000 --- a/web/src/lib/components/ToastAction.svelte +++ /dev/null @@ -1,33 +0,0 @@ - - - - - {#if button} -
- -
- {/if} -
-
diff --git a/web/src/lib/components/album-page/album-map.svelte b/web/src/lib/components/album-page/album-map.svelte index c161bac552..623ac48ded 100644 --- a/web/src/lib/components/album-page/album-map.svelte +++ b/web/src/lib/components/album-page/album-map.svelte @@ -1,7 +1,8 @@ diff --git a/web/src/lib/components/album-page/album-viewer.svelte b/web/src/lib/components/album-page/album-viewer.svelte index 19634d5aa4..13ac213b1b 100644 --- a/web/src/lib/components/album-page/album-viewer.svelte +++ b/web/src/lib/components/album-page/album-viewer.svelte @@ -5,12 +5,12 @@ import SelectAllAssets from '$lib/components/timeline/actions/SelectAllAction.svelte'; import AssetSelectControlBar from '$lib/components/timeline/AssetSelectControlBar.svelte'; import Timeline from '$lib/components/timeline/Timeline.svelte'; + import { assetViewerManager } from '$lib/managers/asset-viewer-manager.svelte'; import { featureFlagsManager } from '$lib/managers/feature-flags-manager.svelte'; import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte'; import { handleDownloadAlbum } from '$lib/services/album.service'; import { getGlobalActions } from '$lib/services/app.service'; import { AssetInteraction } from '$lib/stores/asset-interaction.svelte'; - import { assetViewingStore } from '$lib/stores/asset-viewing.store'; import { dragAndDropFilesStore } from '$lib/stores/drag-and-drop-files.store'; import { mediaQueryManager } from '$lib/stores/media-query-manager.svelte'; import { SlideshowNavigation, SlideshowState, slideshowStore } from '$lib/stores/slideshow.store'; @@ -34,7 +34,6 @@ const album = sharedLink.album as AlbumResponseDto; - let { isViewing: showAssetViewer, setAssetId } = assetViewingStore; let { slideshowState, slideshowNavigation } = slideshowStore; const options = $derived({ albumId: album.id, order: album.order }); @@ -55,7 +54,9 @@ ? await timelineManager.getRandomAsset() : timelineManager.months[0]?.dayGroups[0]?.viewerAssets[0]?.asset; if (asset) { - handlePromiseError(setAssetId(asset.id).then(() => ($slideshowState = SlideshowState.PlaySlideshow))); + handlePromiseError( + assetViewerManager.setAssetId(asset.id).then(() => ($slideshowState = SlideshowState.PlaySlideshow)), + ); } }; @@ -66,7 +67,7 @@ use:shortcut={{ shortcut: { key: 'Escape' }, onShortcut: () => { - if (!$showAssetViewer && assetInteraction.selectionActive) { + if (!assetViewerManager.isViewing && assetInteraction.selectionActive) { cancelMultiselect(assetInteraction); } }, diff --git a/web/src/lib/components/asset-viewer/asset-viewer-nav-bar.svelte b/web/src/lib/components/asset-viewer/asset-viewer-nav-bar.svelte index eee2dc325c..00e845e8ec 100644 --- a/web/src/lib/components/asset-viewer/asset-viewer-nav-bar.svelte +++ b/web/src/lib/components/asset-viewer/asset-viewer-nav-bar.svelte @@ -8,6 +8,7 @@ import KeepThisDeleteOthersAction from '$lib/components/asset-viewer/actions/keep-this-delete-others.svelte'; import RatingAction from '$lib/components/asset-viewer/actions/rating-action.svelte'; import RemoveAssetFromStack from '$lib/components/asset-viewer/actions/remove-asset-from-stack.svelte'; + import RemoveFromAlbumAction from '$lib/components/timeline/actions/RemoveFromAlbumAction.svelte'; import RestoreAction from '$lib/components/asset-viewer/actions/restore-action.svelte'; import SetAlbumCoverAction from '$lib/components/asset-viewer/actions/set-album-cover-action.svelte'; import SetFeaturedPhotoAction from '$lib/components/asset-viewer/actions/set-person-featured-action.svelte'; @@ -15,8 +16,10 @@ import SetStackPrimaryAsset from '$lib/components/asset-viewer/actions/set-stack-primary-asset.svelte'; import SetVisibilityAction from '$lib/components/asset-viewer/actions/set-visibility-action.svelte'; import UnstackAction from '$lib/components/asset-viewer/actions/unstack-action.svelte'; + import LoadingDots from '$lib/components/LoadingDots.svelte'; import ButtonContextMenu from '$lib/components/shared-components/context-menu/button-context-menu.svelte'; import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte'; + import { assetViewerManager } from '$lib/managers/asset-viewer-manager.svelte'; import { featureFlagsManager } from '$lib/managers/feature-flags-manager.svelte'; import { languageManager } from '$lib/managers/language-manager.svelte'; import { Route } from '$lib/route'; @@ -36,8 +39,6 @@ type StackResponseDto, } from '@immich/sdk'; import { ActionButton, CommandPaletteDefaultProvider, Tooltip, type ActionItem } from '@immich/ui'; - import LoadingDots from '$lib/components/LoadingDots.svelte'; - import { assetViewerManager } from '$lib/managers/asset-viewer-manager.svelte'; import { mdiArrowLeft, mdiArrowRight, @@ -60,6 +61,7 @@ onUndoDelete?: OnUndoDelete; onPlaySlideshow: () => void; onClose?: () => void; + onRemoveFromAlbum?: (assetIds: string[]) => void; playOriginalVideo: boolean; setPlayOriginalVideo: (value: boolean) => void; } @@ -75,11 +77,13 @@ onUndoDelete = undefined, onPlaySlideshow, onClose, + onRemoveFromAlbum, playOriginalVideo = false, setPlayOriginalVideo, }: Props = $props(); const isOwner = $derived($user && asset.ownerId === $user?.id); + const isAlbumOwner = $derived($user && album?.ownerId === $user?.id); const isLocked = $derived(asset.visibility === AssetVisibility.Locked); const smartSearchEnabled = $derived(featureFlagsManager.value.smartSearch); @@ -120,10 +124,10 @@ - - + + @@ -154,6 +158,9 @@ {/if} + {#if album && (isOwner || isAlbumOwner)} + + {/if} {#if isOwner} diff --git a/web/src/lib/components/asset-viewer/asset-viewer.spec.ts b/web/src/lib/components/asset-viewer/asset-viewer.spec.ts index a1f50da86a..acb1d03714 100644 --- a/web/src/lib/components/asset-viewer/asset-viewer.spec.ts +++ b/web/src/lib/components/asset-viewer/asset-viewer.spec.ts @@ -1,5 +1,6 @@ import { getAnimateMock } from '$lib/__mocks__/animate.mock'; import { getResizeObserverMock } from '$lib/__mocks__/resize-observer.mock'; +import { SlideshowState, slideshowStore } from '$lib/stores/slideshow.store'; import { preferences as preferencesStore, resetSavedUser, user as userStore } from '$lib/stores/user.store'; import { renderWithTooltips } from '$tests/helpers'; import { updateAsset } from '@immich/sdk'; @@ -41,6 +42,7 @@ describe('AssetViewer', () => { }); afterEach(() => { + slideshowStore.slideshowState.set(SlideshowState.None); resetSavedUser(); vi.clearAllMocks(); }); diff --git a/web/src/lib/components/asset-viewer/asset-viewer.svelte b/web/src/lib/components/asset-viewer/asset-viewer.svelte index 3f7b048c8f..e2981e2e55 100644 --- a/web/src/lib/components/asset-viewer/asset-viewer.svelte +++ b/web/src/lib/components/asset-viewer/asset-viewer.svelte @@ -14,7 +14,6 @@ import { editManager, EditToolType } from '$lib/managers/edit/edit-manager.svelte'; import { eventManager } from '$lib/managers/event-manager.svelte'; import { getAssetActions } from '$lib/services/asset.service'; - import { assetViewingStore } from '$lib/stores/asset-viewing.store'; import { isFaceEditMode } from '$lib/stores/face-edit.svelte'; import { ocrManager } from '$lib/stores/ocr.svelte'; import { alwaysLoadOriginalVideo } from '$lib/stores/preferences.store'; @@ -71,6 +70,7 @@ onAction?: OnAction; onUndoDelete?: OnUndoDelete; onClose?: (asset: AssetResponseDto) => void; + onRemoveFromAlbum?: (assetIds: string[]) => void; onRandom?: () => Promise<{ id: string } | undefined>; } @@ -86,10 +86,10 @@ onAction, onUndoDelete, onClose, + onRemoveFromAlbum, onRandom, }: Props = $props(); - const { setAssetId } = assetViewingStore; const { restartProgress: restartSlideshowProgress, stopProgress: stopSlideshowProgress, @@ -188,7 +188,7 @@ if (editManager.hasAppliedEdits) { const refreshedAsset = await getAssetInfo({ id: asset.id }); onAssetChange?.(refreshedAsset); - assetViewingStore.setAsset(refreshedAsset); + assetViewerManager.setAsset(refreshedAsset); } assetViewerManager.closeEditor(); }; @@ -239,7 +239,7 @@ } if ($slideshowRepeat && slideshowStartAssetId) { - await setAssetId(slideshowStartAssetId); + await assetViewerManager.setAssetId(slideshowStartAssetId); $restartSlideshowProgress = true; return; } @@ -255,7 +255,7 @@ let assetViewerHtmlElement = $state(); const slideshowHistory = new SlideshowHistory((asset) => { - handlePromiseError(setAssetId(asset.id).then(() => ($restartSlideshowProgress = true))); + handlePromiseError(assetViewerManager.setAssetId(asset.id).then(() => ($restartSlideshowProgress = true))); }); const handleVideoStarted = () => { @@ -478,6 +478,7 @@ {onUndoDelete} onPlaySlideshow={() => ($slideshowState = SlideshowState.PlaySlideshow)} onClose={onClose ? () => onClose(asset) : undefined} + {onRemoveFromAlbum} {playOriginalVideo} {setPlayOriginalVideo} /> @@ -485,7 +486,7 @@ {/if} {#if $slideshowState != SlideshowState.None} -
+
{#if showDetailPanel} -
- -
+ {:else if assetViewerManager.isShowEditor} -
- -
+ {/if}
{/if} diff --git a/web/src/lib/components/asset-viewer/detail-panel-location.svelte b/web/src/lib/components/asset-viewer/detail-panel-location.svelte index 1a3779f528..15ea4d94ca 100644 --- a/web/src/lib/components/asset-viewer/detail-panel-location.svelte +++ b/web/src/lib/components/asset-viewer/detail-panel-location.svelte @@ -1,24 +1,20 @@ - +
{$t('select_person_to_tag')}

- +
diff --git a/web/src/lib/components/faces-page/person-side-panel.svelte b/web/src/lib/components/faces-page/person-side-panel.svelte index cad29706a4..d1556af0f5 100644 --- a/web/src/lib/components/faces-page/person-side-panel.svelte +++ b/web/src/lib/components/faces-page/person-side-panel.svelte @@ -3,7 +3,6 @@ import { timeBeforeShowLoadingSpinner } from '$lib/constants'; import { assetViewerManager } from '$lib/managers/asset-viewer-manager.svelte'; import { eventManager } from '$lib/managers/event-manager.svelte'; - import { assetViewingStore } from '$lib/stores/asset-viewing.store'; import { boundingBoxesArray } from '$lib/stores/people.store'; import { getPeopleThumbnailUrl, handlePromiseError } from '$lib/utils'; import { handleError } from '$lib/utils/handle-error'; @@ -179,7 +178,7 @@ peopleWithFaces = peopleWithFaces.filter((f) => f.id !== face.id); - await assetViewingStore.setAssetId(assetId); + await assetViewerManager.setAssetId(assetId); } catch (error) { handleError(error, $t('error_delete_face')); } diff --git a/web/src/lib/components/memory-page/memory-viewer.svelte b/web/src/lib/components/memory-page/memory-viewer.svelte index c86385b8d9..ab3256df49 100644 --- a/web/src/lib/components/memory-page/memory-viewer.svelte +++ b/web/src/lib/components/memory-page/memory-viewer.svelte @@ -19,13 +19,13 @@ import TagAction from '$lib/components/timeline/actions/TagAction.svelte'; import AssetSelectControlBar from '$lib/components/timeline/AssetSelectControlBar.svelte'; import { QueryParameter } from '$lib/constants'; + import { assetViewerManager } from '$lib/managers/asset-viewer-manager.svelte'; import { authManager } from '$lib/managers/auth-manager.svelte'; + import { memoryManager, type MemoryAsset } from '$lib/managers/memory-manager.svelte'; import type { TimelineAsset, Viewport } from '$lib/managers/timeline-manager/types'; import { Route } from '$lib/route'; import { getAssetBulkActions } from '$lib/services/asset.service'; import { AssetInteraction } from '$lib/stores/asset-interaction.svelte'; - import { assetViewingStore } from '$lib/stores/asset-viewing.store'; - import { memoryStore, type MemoryAsset } from '$lib/stores/memory.store.svelte'; import { locale, videoViewerMuted, videoViewerVolume } from '$lib/stores/preferences.store'; import { preferences } from '$lib/stores/user.store'; import { getAssetMediaUrl, handlePromiseError, memoryLaneTitle } from '$lib/utils'; @@ -77,7 +77,6 @@ let isSaved = $derived(current?.memory.isSaved); let viewerHeight = $state(0); - const { isViewing } = assetViewingStore; const viewport: Viewport = $state({ width: 0, height: 0 }); // need to include padding in the viewport for gallery const galleryViewport: Viewport = $derived({ height: viewport.height, width: viewport.width - 32 }); @@ -87,7 +86,7 @@ const asHref = (asset: { id: string }) => `?${QueryParameter.ID}=${asset.id}`; const handleNavigate = async (asset?: { id: string }) => { - if ($isViewing) { + if (assetViewerManager.isViewing) { return asset; } @@ -187,7 +186,7 @@ if (!current) { return; } - memoryStore.hideAssetsFromMemory(ids); + memoryManager.hideAssetsFromMemory(ids); init(page); }; @@ -196,7 +195,7 @@ return; } - await memoryStore.deleteAssetFromMemory(current.asset.id); + await memoryManager.deleteAssetFromMemory(current.asset.id); init(page); }; @@ -205,7 +204,7 @@ return; } - await memoryStore.deleteMemory(current.memory.id); + await memoryManager.deleteMemory(current.memory.id); toastManager.primary($t('removed_memory')); init(page); }; @@ -216,7 +215,7 @@ } const newSavedState = !current.memory.isSaved; - await memoryStore.updateMemorySaved(current.memory.id, newSavedState); + await memoryManager.updateMemorySaved(current.memory.id, newSavedState); toastManager.primary(newSavedState ? $t('added_to_favorites') : $t('removed_from_favorites')); init(page); }; @@ -254,11 +253,11 @@ const loadFromParams = (page: Page | NavigationTarget | null) => { const assetId = page?.params?.assetId ?? page?.url.searchParams.get(QueryParameter.ID) ?? undefined; - return memoryStore.getMemoryAsset(assetId); + return memoryManager.getMemoryAsset(assetId); }; const init = (target: Page | NavigationTarget | null) => { - if (memoryStore.memories.length === 0) { + if (memoryManager.memories.length === 0) { return handlePromiseError(goto(Route.photos())); } @@ -281,7 +280,7 @@ if (playerInitialized || isVideoAssetButPlayerHasNotLoadedYet) { return; } - if ($isViewing) { + if (assetViewerManager.isViewing) { handlePromiseError(handleAction('initPlayer[AssetViewOpen]', 'pause')); } else if (isVideo) { // Image assets will start playing when the image is loaded. Only autostart video assets. @@ -291,7 +290,7 @@ }; afterNavigate(({ from, to }) => { - memoryStore.ready().then( + memoryManager.ready().then( () => { let target; if (to?.params?.assetId) { @@ -326,7 +325,7 @@ handleNextAsset() }, diff --git a/web/src/lib/components/pages/SharedLinkPage.svelte b/web/src/lib/components/pages/SharedLinkPage.svelte index c6270d2de3..01a97fffe7 100644 --- a/web/src/lib/components/pages/SharedLinkPage.svelte +++ b/web/src/lib/components/pages/SharedLinkPage.svelte @@ -3,7 +3,7 @@ import IndividualSharedViewer from '$lib/components/share-page/individual-shared-viewer.svelte'; import ControlAppBar from '$lib/components/shared-components/control-app-bar.svelte'; import ThemeButton from '$lib/components/shared-components/theme-button.svelte'; - import { assetViewingStore } from '$lib/stores/asset-viewing.store'; + import { assetViewerManager } from '$lib/managers/asset-viewer-manager.svelte'; import { user } from '$lib/stores/user.store'; import { setSharedLink } from '$lib/utils'; import { handleError } from '$lib/utils/handle-error'; @@ -31,7 +31,6 @@ const { data }: Props = $props(); - let { gridScrollTarget } = assetViewingStore; let { sharedLink, passwordRequired, key, slug, meta } = $state(data); let { title, description } = $state(meta); let isOwned = $derived($user ? $user.id === sharedLink?.userId : false); @@ -48,7 +47,7 @@ $t('shared_photos_and_videos_count', { values: { assetCount: sharedLink.assets.length } }); await tick(); await navigate( - { targetRoute: 'current', assetId: null, assetGridRouteSearchParams: $gridScrollTarget }, + { targetRoute: 'current', assetId: null, assetGridRouteSearchParams: assetViewerManager.gridScrollTarget }, { forceNavigate: true, replaceState: true }, ); } catch (error) { diff --git a/web/src/lib/components/shared-components/combobox.svelte b/web/src/lib/components/shared-components/combobox.svelte index 4721357012..803087feef 100644 --- a/web/src/lib/components/shared-components/combobox.svelte +++ b/web/src/lib/components/shared-components/combobox.svelte @@ -212,12 +212,12 @@ bottom: `${rootHeight - top}px`, left: `${left}px`, width: `${boundary.width}px`, - maxHeight: maxHeight(top - dropdownOffset), + maxHeight: maxHeight(boundary.top - dropdownOffset), }; } - const viewportHeight = visualViewport?.height || rootHeight; - const availableHeight = modalBounds ? rootHeight - bottom : viewportHeight - boundary.bottom; + const viewportHeight = visualViewport?.height || window.innerHeight; + const availableHeight = viewportHeight - boundary.bottom; return { top: `${bottom}px`, left: `${left}px`, diff --git a/web/src/lib/components/shared-components/gallery-viewer/gallery-viewer.svelte b/web/src/lib/components/shared-components/gallery-viewer/gallery-viewer.svelte index fc233c755e..df4439065d 100644 --- a/web/src/lib/components/shared-components/gallery-viewer/gallery-viewer.svelte +++ b/web/src/lib/components/shared-components/gallery-viewer/gallery-viewer.svelte @@ -2,16 +2,17 @@ import { goto } from '$app/navigation'; import { shortcuts, type ShortcutOptions } from '$lib/actions/shortcut'; import type { Action } from '$lib/components/asset-viewer/actions/action'; + import type { AssetCursor } from '$lib/components/asset-viewer/asset-viewer.svelte'; import Thumbnail from '$lib/components/assets/thumbnail/thumbnail.svelte'; import { AssetAction } from '$lib/constants'; import Portal from '$lib/elements/Portal.svelte'; + import { assetViewerManager } from '$lib/managers/asset-viewer-manager.svelte'; import { featureFlagsManager } from '$lib/managers/feature-flags-manager.svelte'; import type { TimelineAsset, Viewport } from '$lib/managers/timeline-manager/types'; import AssetDeleteConfirmModal from '$lib/modals/AssetDeleteConfirmModal.svelte'; import ShortcutsModal from '$lib/modals/ShortcutsModal.svelte'; import { Route } from '$lib/route'; import type { AssetInteraction } from '$lib/stores/asset-interaction.svelte'; - import { assetViewingStore } from '$lib/stores/asset-viewing.store'; import { showDeleteModal } from '$lib/stores/preferences.store'; import { handlePromiseError } from '$lib/utils'; import { deleteAssets } from '$lib/utils/actions'; @@ -64,7 +65,6 @@ allowDeletion = true, }: Props = $props(); - let { isViewing: isViewerOpen, asset: viewingAsset } = assetViewingStore; const navigationAssets = $derived(viewerAssets ?? assets); const geometry = $derived( @@ -258,7 +258,7 @@ const shortcutList = $derived( (() => { - if ($isViewerOpen) { + if (assetViewerManager.isViewing) { return []; } @@ -353,10 +353,10 @@ } }); - const assetCursor = $derived({ - current: $viewingAsset, - nextAsset: getNextAsset(navigationAssets, $viewingAsset), - previousAsset: getPreviousAsset(navigationAssets, $viewingAsset), + const assetCursor = $derived({ + current: assetViewerManager.asset!, + nextAsset: getNextAsset(navigationAssets, assetViewerManager.asset), + previousAsset: getPreviousAsset(navigationAssets, assetViewerManager.asset), }); @@ -410,7 +410,7 @@ {/if} -{#if $isViewerOpen} +{#if assetViewerManager.isViewing} {#await import('$lib/components/asset-viewer/asset-viewer.svelte') then { default: AssetViewer }} { - assetViewingStore.showAssetViewer(false); + assetViewerManager.showAssetViewer(false); handlePromiseError(navigate({ targetRoute: 'current', assetId: null })); }} /> diff --git a/web/src/lib/components/timeline/Timeline.svelte b/web/src/lib/components/timeline/Timeline.svelte index d6ce722c96..0ebc4800ea 100644 --- a/web/src/lib/components/timeline/Timeline.svelte +++ b/web/src/lib/components/timeline/Timeline.svelte @@ -11,6 +11,7 @@ import HotModuleReload from '$lib/elements/HotModuleReload.svelte'; import Portal from '$lib/elements/Portal.svelte'; import Skeleton from '$lib/elements/Skeleton.svelte'; + import { assetViewerManager } from '$lib/managers/asset-viewer-manager.svelte'; import type { DayGroup } from '$lib/managers/timeline-manager/day-group.svelte'; import { isIntersecting } from '$lib/managers/timeline-manager/internal/intersection-support.svelte'; import type { MonthGroup } from '$lib/managers/timeline-manager/month-group.svelte'; @@ -18,7 +19,6 @@ import type { TimelineAsset, TimelineManagerOptions, ViewportTopMonth } from '$lib/managers/timeline-manager/types'; import { assetsSnapshot } from '$lib/managers/timeline-manager/utils.svelte'; import type { AssetInteraction } from '$lib/stores/asset-interaction.svelte'; - import { assetViewingStore } from '$lib/stores/asset-viewing.store'; import { mediaQueryManager } from '$lib/stores/media-query-manager.svelte'; import { isAssetViewerRoute, navigate } from '$lib/utils/navigation'; import { getTimes, type ScrubberListener } from '$lib/utils/timeline-util'; @@ -88,10 +88,7 @@ onDestroy(() => timelineManager.destroy()); $effect(() => options && void timelineManager.updateOptions(options)); - let { isViewing: showAssetViewer, asset: viewingAsset, gridScrollTarget } = assetViewingStore; - let scrollableElement: HTMLElement | undefined = $state(); - let timelineElement: HTMLElement | undefined = $state(); let invisible = $state(true); // The percentage of scroll through the month that is currently intersecting the top boundary of the viewport. @@ -209,7 +206,7 @@ timelineManager.viewportWidth = rect.width; } } - const scrollTarget = $gridScrollTarget?.at; + const scrollTarget = assetViewerManager.gridScrollTarget?.at; let scrolled = false; if (scrollTarget) { scrolled = await scrollAndLoadAsset(scrollTarget); @@ -518,8 +515,8 @@ }); $effect(() => { - if ($showAssetViewer) { - const { localDateTime } = getTimes($viewingAsset.fileCreatedAt, DateTime.local().offset / 60); + if (assetViewerManager.asset && assetViewerManager.isViewing) { + const { localDateTime } = getTimes(assetViewerManager.asset.fileCreatedAt, DateTime.local().offset / 60); void timelineManager.loadMonthGroup({ year: localDateTime.year, month: localDateTime.month }); } }); @@ -565,7 +562,7 @@ onAfterUpdate={() => { const asset = page.url.searchParams.get('at'); if (asset) { - $gridScrollTarget = { at: asset }; + assetViewerManager.gridScrollTarget = { at: asset }; } void scrollAfterNavigate(); }} @@ -722,7 +719,7 @@ - {#if $showAssetViewer} + {#if assetViewerManager.isViewing} {/if} diff --git a/web/src/lib/components/timeline/TimelineAssetViewer.svelte b/web/src/lib/components/timeline/TimelineAssetViewer.svelte index bd4ead6def..47144dcca9 100644 --- a/web/src/lib/components/timeline/TimelineAssetViewer.svelte +++ b/web/src/lib/components/timeline/TimelineAssetViewer.svelte @@ -2,11 +2,11 @@ import type { Action } from '$lib/components/asset-viewer/actions/action'; import type { AssetCursor } from '$lib/components/asset-viewer/asset-viewer.svelte'; import { AssetAction } from '$lib/constants'; + import { assetViewerManager } from '$lib/managers/asset-viewer-manager.svelte'; import { assetCacheManager } from '$lib/managers/AssetCacheManager.svelte'; import { authManager } from '$lib/managers/auth-manager.svelte'; import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte'; import type { TimelineAsset } from '$lib/managers/timeline-manager/types'; - import { assetViewingStore } from '$lib/stores/asset-viewing.store'; import { websocketEvents } from '$lib/stores/websocket'; import { handlePromiseError } from '$lib/utils'; import { updateStackedAssetInTimeline, updateUnstackedAssetInTimeline } from '$lib/utils/actions'; @@ -18,8 +18,6 @@ import { onDestroy, onMount, untrack } from 'svelte'; import { t } from 'svelte-i18n'; - let { asset: viewingAsset, gridScrollTarget } = assetViewingStore; - interface Props { timelineManager: TimelineManager; invisible: boolean; @@ -65,7 +63,7 @@ }; let assetCursor = $state({ - current: $viewingAsset, + current: assetViewerManager.asset!, previousAsset: undefined, nextAsset: undefined, }); @@ -82,9 +80,10 @@ //TODO: replace this with async derived in svelte 6 $effect(() => { - // eslint-disable-next-line @typescript-eslint/no-unused-expressions - $viewingAsset; - untrack(() => handlePromiseError(loadCloseAssets($viewingAsset))); + const asset = assetViewerManager.asset; + if (asset) { + untrack(() => handlePromiseError(loadCloseAssets(asset))); + } }); const handleRandom = async () => { @@ -99,8 +98,26 @@ const handleClose = async (asset: { id: string }) => { invisible = true; - $gridScrollTarget = { at: asset.id }; - await navigate({ targetRoute: 'current', assetId: null, assetGridRouteSearchParams: $gridScrollTarget }); + assetViewerManager.gridScrollTarget = { at: asset.id }; + await navigate({ + targetRoute: 'current', + assetId: null, + assetGridRouteSearchParams: assetViewerManager.gridScrollTarget, + }); + }; + + const handleRemoveFromAlbum = async (assetIds: string[]) => { + timelineManager.removeAssets(assetIds); + + if (!assetIds.includes(assetCursor.current.id)) { + return; + } + + // keep the cleanup workflow in viewer by moving to adjacent asset first + // eslint-disable-next-line @typescript-eslint/no-unused-expressions + (await navigateToAsset(assetCursor?.nextAsset)) || + (await navigateToAsset(assetCursor?.previousAsset)) || + (await handleClose(assetCursor.current)); }; const handlePreAction = async (action: Action) => { @@ -188,7 +205,7 @@ const restoredAsset = assets[0]; const asset = await getAssetInfo({ ...authManager.params, id: restoredAsset.id }); - assetViewingStore.setAsset(asset); + assetViewerManager.setAsset(asset); await navigate({ targetRoute: 'current', assetId: restoredAsset.id }); }; @@ -232,6 +249,7 @@ }} onUndoDelete={handleUndoDelete} onRandom={handleRandom} + onRemoveFromAlbum={handleRemoveFromAlbum} onClose={handleClose} /> {/await} diff --git a/web/src/lib/components/timeline/actions/ChangeLocationAction.svelte b/web/src/lib/components/timeline/actions/ChangeLocationAction.svelte index 08d27bf793..537d38586b 100644 --- a/web/src/lib/components/timeline/actions/ChangeLocationAction.svelte +++ b/web/src/lib/components/timeline/actions/ChangeLocationAction.svelte @@ -1,26 +1,24 @@ {#if menuItem} - (isShowChangeLocation = true)} - /> -{/if} -{#if isShowChangeLocation} - + {/if} diff --git a/web/src/lib/components/timeline/actions/RemoveFromAlbumAction.svelte b/web/src/lib/components/timeline/actions/RemoveFromAlbumAction.svelte index ea2a8d4c2d..5d4943be0f 100644 --- a/web/src/lib/components/timeline/actions/RemoveFromAlbumAction.svelte +++ b/web/src/lib/components/timeline/actions/RemoveFromAlbumAction.svelte @@ -10,16 +10,19 @@ interface Props { album: AlbumResponseDto; onRemove: ((assetIds: string[]) => void) | undefined; + assetIds?: string[]; menuItem?: boolean; } - let { album = $bindable(), onRemove, menuItem = false }: Props = $props(); + let { album = $bindable(), onRemove, assetIds, menuItem = false }: Props = $props(); - const { getAssets, clearSelect } = getAssetControlContext(); + const context = getAssetControlContext(); const removeFromAlbum = async () => { + const ids = assetIds ?? context?.getAssets().map(({ id }) => id) ?? []; + const isConfirmed = await modalManager.showDialog({ - prompt: $t('remove_assets_album_confirmation', { values: { count: getAssets().length } }), + prompt: $t('remove_assets_album_confirmation', { values: { count: ids.length } }), }); if (!isConfirmed) { @@ -27,7 +30,6 @@ } try { - const ids = [...getAssets()].map((a) => a.id); const results = await removeAssetFromAlbum({ id: album.id, bulkIdsDto: { ids }, @@ -40,7 +42,7 @@ const count = results.filter(({ success }) => success).length; toastManager.primary($t('assets_removed_count', { values: { count } })); - clearSelect(); + context?.clearSelect(); } catch (error) { handleError(error, $t('errors.error_removing_assets_from_album')); } diff --git a/web/src/lib/components/timeline/actions/TimelineKeyboardActions.svelte b/web/src/lib/components/timeline/actions/TimelineKeyboardActions.svelte index 4fa96ef7d5..70041f4e33 100644 --- a/web/src/lib/components/timeline/actions/TimelineKeyboardActions.svelte +++ b/web/src/lib/components/timeline/actions/TimelineKeyboardActions.svelte @@ -5,6 +5,7 @@ setFocusToAsset as setFocusAssetInit, setFocusTo as setFocusToInit, } from '$lib/components/timeline/actions/focus-actions'; + import { assetViewerManager } from '$lib/managers/asset-viewer-manager.svelte'; import { eventManager } from '$lib/managers/event-manager.svelte'; import { featureFlagsManager } from '$lib/managers/feature-flags-manager.svelte'; import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte'; @@ -14,7 +15,6 @@ import ShortcutsModal from '$lib/modals/ShortcutsModal.svelte'; import { Route } from '$lib/route'; import type { AssetInteraction } from '$lib/stores/asset-interaction.svelte'; - import { assetViewingStore } from '$lib/stores/asset-viewing.store'; import { showDeleteModal } from '$lib/stores/preferences.store'; import { searchStore } from '$lib/stores/search.svelte'; import { handlePromiseError } from '$lib/utils'; @@ -32,8 +32,6 @@ let { timelineManager = $bindable(), assetInteraction, onEscape, scrollToAsset }: Props = $props(); - const { isViewing: showAssetViewer } = assetViewingStore; - const trashOrDelete = async (forceRequested?: boolean) => { const force = forceRequested || !featureFlagsManager.value.trash; const selectedAssets = assetInteraction.selectedAssets; @@ -144,7 +142,7 @@ }; const shortcutList = $derived.by(() => { - if (searchStore.isSearchEnabled || $showAssetViewer || isModalOpen()) { + if (searchStore.isSearchEnabled || assetViewerManager.isViewing || isModalOpen()) { return []; } diff --git a/web/src/lib/components/utilities-page/duplicates/duplicates-compare-control.svelte b/web/src/lib/components/utilities-page/duplicates/duplicates-compare-control.svelte index aba2dc01f4..ab19f12079 100644 --- a/web/src/lib/components/utilities-page/duplicates/duplicates-compare-control.svelte +++ b/web/src/lib/components/utilities-page/duplicates/duplicates-compare-control.svelte @@ -2,8 +2,8 @@ import { shortcuts } from '$lib/actions/shortcut'; import DuplicateAsset from '$lib/components/utilities-page/duplicates/duplicate-asset.svelte'; import Portal from '$lib/elements/Portal.svelte'; + import { assetViewerManager } from '$lib/managers/asset-viewer-manager.svelte'; import { authManager } from '$lib/managers/auth-manager.svelte'; - import { assetViewingStore } from '$lib/stores/asset-viewing.store'; import { handlePromiseError } from '$lib/utils'; import { getNextAsset, getPreviousAsset } from '$lib/utils/asset-utils'; import { suggestDuplicate } from '$lib/utils/duplicate-utils'; @@ -22,8 +22,6 @@ } let { assets, onResolve, onStack }: Props = $props(); - const { isViewing: showAssetViewer, asset: viewingAsset, setAsset } = assetViewingStore; - // eslint-disable-next-line svelte/no-unnecessary-state-wrap let selectedAssetIds = $state(new SvelteSet()); let trashCount = $derived(assets.length - selectedAssetIds.size); @@ -40,7 +38,7 @@ }); onDestroy(() => { - assetViewingStore.showAssetViewer(false); + assetViewerManager.showAssetViewer(false); }); const onRandom = async () => { @@ -71,7 +69,7 @@ const onViewAsset = async ({ id }: AssetResponseDto) => { const asset = await getAssetInfo({ ...authManager.params, id }); - setAsset(asset); + assetViewerManager.setAsset(asset); await navigate({ targetRoute: 'current', assetId: asset.id }); }; @@ -86,9 +84,9 @@ }; const assetCursor = $derived({ - current: $viewingAsset, - nextAsset: getNextAsset(assets, $viewingAsset), - previousAsset: getPreviousAsset(assets, $viewingAsset), + current: assetViewerManager.asset!, + nextAsset: getNextAsset(assets, assetViewerManager.asset), + previousAsset: getPreviousAsset(assets, assetViewerManager.asset), }); @@ -166,7 +164,7 @@
-{#if $showAssetViewer} +{#if assetViewerManager.isViewing} {#await import('$lib/components/asset-viewer/asset-viewer.svelte') then { default: AssetViewer }} 1} {onRandom} onClose={() => { - assetViewingStore.showAssetViewer(false); + assetViewerManager.showAssetViewer(false); handlePromiseError(navigate({ targetRoute: 'current', assetId: null })); }} /> diff --git a/web/src/lib/index.spec.ts b/web/src/lib/index.spec.ts index bda5a9e722..20f1244d50 100644 --- a/web/src/lib/index.spec.ts +++ b/web/src/lib/index.spec.ts @@ -1,4 +1,4 @@ -import { cleanClass } from '$lib'; +import { cleanClass, isDefined } from '$lib'; describe('cleanClass', () => { it('should return a string of class names', () => { @@ -13,3 +13,19 @@ describe('cleanClass', () => { expect(cleanClass('class1', ['class2', 'class3'])).toBe('class1 class2 class3'); }); }); + +describe('isDefined', () => { + it('should return false for null', () => { + expect(isDefined(null)).toBe(false); + }); + + it('should return false for undefined', () => { + expect(isDefined(undefined)).toBe(false); + }); + + it('should return true for everything else', () => { + for (const value of [0, 1, 2, true, false, {}, 'foo', 'bar', []]) { + expect(isDefined(value)).toBe(true); + } + }); +}); diff --git a/web/src/lib/index.ts b/web/src/lib/index.ts index b4fc195626..e659dadd46 100644 --- a/web/src/lib/index.ts +++ b/web/src/lib/index.ts @@ -14,3 +14,5 @@ export const cleanClass = (...classNames: unknown[]) => { .join(' '), ); }; + +export const isDefined = (value: T): value is NonNullable => value !== null && value !== undefined; diff --git a/web/src/lib/managers/asset-viewer-manager.svelte.ts b/web/src/lib/managers/asset-viewer-manager.svelte.ts index 0bab3aff80..f46be6b698 100644 --- a/web/src/lib/managers/asset-viewer-manager.svelte.ts +++ b/web/src/lib/managers/asset-viewer-manager.svelte.ts @@ -1,7 +1,10 @@ +import { authManager } from '$lib/managers/auth-manager.svelte'; import type { ImageLoaderStatus } from '$lib/utils/adaptive-image-loader.svelte'; import { canCopyImageToClipboard } from '$lib/utils/asset-utils'; import { BaseEventManager } from '$lib/utils/base-event-manager.svelte'; +import type { AssetGridRouteSearchParams } from '$lib/utils/navigation'; import { PersistedLocalStorage } from '$lib/utils/persisted'; +import { getAssetInfo, type AssetResponseDto } from '@immich/sdk'; import type { ZoomImageWheelState } from '@zoom-image/core'; import { cubicOut } from 'svelte/easing'; @@ -21,7 +24,7 @@ export type Events = { Copy: []; }; -export class AssetViewerManager extends BaseEventManager { +class AssetViewerManager extends BaseEventManager { #zoomState = $state(createDefaultZoomState()); #animationFrameId: number | null = null; @@ -40,6 +43,18 @@ export class AssetViewerManager extends BaseEventManager { isPlayingMotionPhoto = $state(false); isShowEditor = $state(false); + #viewingAssetStoreState = $state(); + #viewState = $state(false); + gridScrollTarget = $state(); + + get asset() { + return this.#viewingAssetStoreState; + } + + get isViewing() { + return this.#viewState; + } + get isImageLoading() { return this.#isImageLoading; } @@ -145,6 +160,21 @@ export class AssetViewerManager extends BaseEventManager { closeEditor() { this.isShowEditor = false; } + + setAsset(asset: AssetResponseDto) { + this.#viewingAssetStoreState = asset; + this.#viewState = true; + } + + async setAssetId(id: string): Promise { + const asset = await getAssetInfo({ ...authManager.params, id }); + this.setAsset(asset); + return asset; + } + + showAssetViewer(show: boolean) { + this.#viewState = show; + } } export const assetViewerManager = new AssetViewerManager(); diff --git a/web/src/lib/managers/geolocation.manager.svelte.ts b/web/src/lib/managers/geolocation.manager.svelte.ts new file mode 100644 index 0000000000..d5b2c43912 --- /dev/null +++ b/web/src/lib/managers/geolocation.manager.svelte.ts @@ -0,0 +1,15 @@ +import type { LatLng } from '$lib/types'; + +class GeolocationManager { + #lastPoint = $state(); + + get lastPoint() { + return this.#lastPoint; + } + + onSelected(point: LatLng) { + this.#lastPoint = point; + } +} + +export const geolocationManager = new GeolocationManager(); diff --git a/web/src/lib/stores/memory.store.svelte.ts b/web/src/lib/managers/memory-manager.svelte.ts similarity index 98% rename from web/src/lib/stores/memory.store.svelte.ts rename to web/src/lib/managers/memory-manager.svelte.ts index cdd6af9606..9e34ff2d0e 100644 --- a/web/src/lib/stores/memory.store.svelte.ts +++ b/web/src/lib/managers/memory-manager.svelte.ts @@ -21,7 +21,7 @@ export type MemoryAsset = MemoryIndex & { nextMemory?: MemoryResponseDto; }; -class MemoryStoreSvelte { +class MemoryManager { #loading: Promise | undefined; constructor() { @@ -135,4 +135,4 @@ class MemoryStoreSvelte { } } -export const memoryStore = new MemoryStoreSvelte(); +export const memoryManager = new MemoryManager(); diff --git a/web/src/lib/modals/AlbumPickerModal.svelte b/web/src/lib/modals/AlbumPickerModal.svelte index 081c7f49d7..ed0066f9f3 100644 --- a/web/src/lib/modals/AlbumPickerModal.svelte +++ b/web/src/lib/modals/AlbumPickerModal.svelte @@ -28,7 +28,10 @@ let { onClose }: Props = $props(); onMount(async () => { - albums = await getAllAlbums({}); + // TODO the server should *really* just return all albums (paginated ideally) + const ownedAlbums = await getAllAlbums({ shared: false }); + ownedAlbums.push.apply(ownedAlbums, await getAllAlbums({ shared: true })); + albums = ownedAlbums; recentAlbums = albums.sort((a, b) => (new Date(a.updatedAt) > new Date(b.updatedAt) ? -1 : 1)).slice(0, 3); loading = false; }); diff --git a/web/src/lib/modals/AssetChangeDateModal.spec.ts b/web/src/lib/modals/AssetChangeDateModal.spec.ts new file mode 100644 index 0000000000..fc23f75651 --- /dev/null +++ b/web/src/lib/modals/AssetChangeDateModal.spec.ts @@ -0,0 +1,67 @@ +import { getAnimateMock } from '$lib/__mocks__/animate.mock'; +import { getIntersectionObserverMock } from '$lib/__mocks__/intersection-observer.mock'; +import { getVisualViewportMock } from '$lib/__mocks__/visual-viewport.mock'; +import { fireEvent, render, screen, waitFor } from '@testing-library/svelte'; +import { DateTime } from 'luxon'; +import { afterAll, beforeEach, describe, expect, test, vi } from 'vitest'; +import AssetChangeDateModal from './AssetChangeDateModal.svelte'; + +describe('AssetChangeDateModal component', () => { + const initialDate = DateTime.fromISO('2026-03-19T23:31:30.112'); + const initialTimeZone = 'Europe/Lisbon'; + const onClose = vi.fn(); + + const getDateInput = async () => (await screen.findByDisplayValue('2026-03-19T23:31:30.112')) as HTMLInputElement; + const getTimeZoneInput = () => screen.getByRole('combobox', { name: /timezone/i }) as HTMLInputElement; + + beforeEach(() => { + vi.stubGlobal('IntersectionObserver', getIntersectionObserverMock()); + vi.stubGlobal('visualViewport', getVisualViewportMock()); + vi.resetAllMocks(); + Element.prototype.animate = getAnimateMock(); + }); + + afterAll(async () => { + await waitFor(() => { + expect(document.body.style.pointerEvents).not.toBe('none'); + }); + }); + + test('preserves the selected timezone when changing the datetime', async () => { + render(AssetChangeDateModal, { + props: { + initialDate, + initialTimeZone, + timezoneInput: true, + asset: { id: 'asset-id' } as never, + onClose, + }, + }); + + const timezoneInput = getTimeZoneInput(); + const datetimeInput = await getDateInput(); + + const initialTimezoneValue = timezoneInput.value; + + await fireEvent.focus(timezoneInput); + await fireEvent.input(timezoneInput, { target: { value: 'Pacific/Pitcairn' } }); + + const option = await screen.findByText(/Pacific\/Pitcairn/i); + await fireEvent.click(option); + + expect(timezoneInput.value).toBe('Pacific/Pitcairn (-08:00)'); + expect(timezoneInput.value).not.toBe(initialTimezoneValue); + + const beforeDatetime = datetimeInput.value; + + await fireEvent.input(datetimeInput, { + target: { value: '2026-03-19T23:31:31.113' }, + }); + await fireEvent.change(datetimeInput, { + target: { value: '2026-03-19T23:31:31.113' }, + }); + + expect(datetimeInput.value).not.toBe(beforeDatetime); + expect(timezoneInput.value).toBe('Pacific/Pitcairn (-08:00)'); + }); +}); diff --git a/web/src/lib/modals/AssetChangeDateModal.svelte b/web/src/lib/modals/AssetChangeDateModal.svelte index ec4cb0f077..fe9d1baf25 100644 --- a/web/src/lib/modals/AssetChangeDateModal.svelte +++ b/web/src/lib/modals/AssetChangeDateModal.svelte @@ -23,10 +23,7 @@ let selectedDate = $state(initialDate.toFormat("yyyy-MM-dd'T'HH:mm:ss.SSS")); const timezones = $derived(getTimezones(selectedDate)); - // svelte-ignore state_referenced_locally - let lastSelectedTimezone = $state(getPreferredTimeZone(initialDate, initialTimeZone, timezones)); - // the offsets (and validity) for time zones may change if the date is changed, which is why we recompute the list - let selectedOption = $derived(getPreferredTimeZone(initialDate, initialTimeZone, timezones, lastSelectedTimezone)); + let selectedOption = $state(getPreferredTimeZone(initialDate, initialTimeZone, getTimezones(selectedDate))); const onSubmit = async () => { if (!date.isValid || !selectedOption) { @@ -45,6 +42,12 @@ } }; + const updateSelectedDate = (value: string) => { + selectedDate = value; + + selectedOption = getPreferredTimeZone(initialDate, initialTimeZone, getTimezones(value), selectedOption); + }; + // when changing the time zone, assume the configured date/time is meant for that time zone (instead of updating it) const date = $derived(DateTime.fromISO(selectedDate, { zone: selectedOption?.value, setZone: true })); @@ -59,7 +62,12 @@ size="small" > - + selectedDate, updateSelectedDate} + /> {#if timezoneInput}
diff --git a/web/src/lib/components/shared-components/change-location.svelte b/web/src/lib/modals/GeolocationPointPickerModal.svelte similarity index 85% rename from web/src/lib/components/shared-components/change-location.svelte rename to web/src/lib/modals/GeolocationPointPickerModal.svelte index 1abb2dacce..87b1df081a 100644 --- a/web/src/lib/components/shared-components/change-location.svelte +++ b/web/src/lib/modals/GeolocationPointPickerModal.svelte @@ -1,30 +1,27 @@ {#snippet prompt()}

{$t('update_location_action_prompt', { values: { count: assetCount } })}

-

- {$t('latitude')}: {location.latitude}

-

- {$t('longitude')}: {location.longitude}

+

- {$t('latitude')}: {point.lat}

+

- {$t('longitude')}: {point.lng}

{/snippet}
diff --git a/web/src/lib/services/album.service.ts b/web/src/lib/services/album.service.ts index 6ccd67584e..3a70d72478 100644 --- a/web/src/lib/services/album.service.ts +++ b/web/src/lib/services/album.service.ts @@ -1,5 +1,4 @@ import { goto } from '$app/navigation'; -import ToastAction from '$lib/components/ToastAction.svelte'; import { authManager } from '$lib/managers/auth-manager.svelte'; import { eventManager } from '$lib/managers/event-manager.svelte'; import type { TimelineAsset } from '$lib/managers/timeline-manager/types'; @@ -138,16 +137,8 @@ const notifyAddToAlbum = ($t: MessageFormatter, albumId: string, assetIds: strin description = $t('assets_were_part_of_album_count', { values: { count: duplicateCount } }); } - toastManager.custom( - { - component: ToastAction, - props: { - title: $t('info'), - color: 'primary', - description, - button: { text: $t('view_album'), color: 'primary', onClick: () => goto(Route.viewAlbum({ id: albumId })) }, - }, - }, + toastManager.primary( + { description, button: { label: $t('view_album'), onclick: () => goto(Route.viewAlbum({ id: albumId })) } }, { timeout: 5000 }, ); }; @@ -229,18 +220,9 @@ export const handleUpdateAlbum = async ({ id }: { id: string }, dto: UpdateAlbum try { const response = await updateAlbumInfo({ id, updateAlbumDto: dto }); eventManager.emit('AlbumUpdate', response); - toastManager.custom({ - component: ToastAction, - props: { - color: 'primary', - title: $t('success'), - description: $t('album_info_updated'), - button: { - text: $t('view_album'), - color: 'primary', - onClick: () => goto(Route.viewAlbum({ id })), - }, - }, + toastManager.primary({ + description: $t('album_info_updated'), + button: { label: $t('view_album'), onclick: () => goto(Route.viewAlbum({ id })) }, }); return true; diff --git a/web/src/lib/services/asset.service.ts b/web/src/lib/services/asset.service.ts index c8614186fd..76ac0b7fc0 100644 --- a/web/src/lib/services/asset.service.ts +++ b/web/src/lib/services/asset.service.ts @@ -8,17 +8,16 @@ import SharedLinkCreateModal from '$lib/modals/SharedLinkCreateModal.svelte'; import { isFaceEditMode } from '$lib/stores/face-edit.svelte'; import { user as authUser, preferences } from '$lib/stores/user.store'; import type { AssetControlContext } from '$lib/types'; -import { getSharedLink, sleep } from '$lib/utils'; +import { getAssetMediaUrl, getSharedLink, sleep } from '$lib/utils'; import { downloadUrl } from '$lib/utils/asset-utils'; import { handleError } from '$lib/utils/handle-error'; import { getFormatter } from '$lib/utils/i18n'; -import { asQueryString } from '$lib/utils/shared-links'; import { AssetJobName, + AssetMediaSize, AssetTypeEnum, AssetVisibility, getAssetInfo, - getBaseUrl, runAssetJobs, updateAsset, type AssetJobsDto, @@ -308,6 +307,7 @@ export const handleDownloadAsset = async (asset: AssetResponseDto, { edited }: { { filename: asset.originalFileName, id: asset.id, + cacheKey: asset.thumbhash, }, ]; @@ -321,13 +321,12 @@ export const handleDownloadAsset = async (asset: AssetResponseDto, { edited }: { assets.push({ filename: motionAsset.originalFileName, id: asset.livePhotoVideoId, + cacheKey: motionAsset.thumbhash, }); } } - const queryParams = asQueryString(authManager.params); - - for (const [i, { filename, id }] of assets.entries()) { + for (const [i, { filename, id, cacheKey }] of assets.entries()) { if (i !== 0) { // play nice with Safari await sleep(500); @@ -335,12 +334,7 @@ export const handleDownloadAsset = async (asset: AssetResponseDto, { edited }: { try { toastManager.primary($t('downloading_asset_filename', { values: { filename } })); - downloadUrl( - getBaseUrl() + - `/assets/${id}/original` + - (queryParams ? `?${queryParams}&edited=${edited}` : `?edited=${edited}`), - filename, - ); + downloadUrl(getAssetMediaUrl({ id, size: AssetMediaSize.Original, edited, cacheKey }), filename); } catch (error) { handleError(error, $t('errors.error_downloading', { values: { filename } })); } diff --git a/web/src/lib/stores/album-asset-selection.store.ts b/web/src/lib/stores/album-asset-selection.store.ts deleted file mode 100644 index a99e2baaca..0000000000 --- a/web/src/lib/stores/album-asset-selection.store.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { writable } from 'svelte/store'; - -function createAlbumAssetSelectionStore() { - const isAlbumAssetSelectionOpen = writable(false); - return { - isAlbumAssetSelectionOpen, - }; -} - -export const albumAssetSelectionStore = createAlbumAssetSelectionStore(); diff --git a/web/src/lib/stores/asset-editor.store.ts b/web/src/lib/stores/asset-editor.store.ts deleted file mode 100644 index cc764cf7ad..0000000000 --- a/web/src/lib/stores/asset-editor.store.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { writable } from 'svelte/store'; - -//-----other -export const lastChosenLocation = writable<{ lng: number; lat: number } | null>(null); diff --git a/web/src/lib/stores/asset-viewing.store.ts b/web/src/lib/stores/asset-viewing.store.ts deleted file mode 100644 index 3cd2cd9579..0000000000 --- a/web/src/lib/stores/asset-viewing.store.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { authManager } from '$lib/managers/auth-manager.svelte'; -import { type AssetGridRouteSearchParams } from '$lib/utils/navigation'; -import { getAssetInfo, type AssetResponseDto } from '@immich/sdk'; -import { readonly, writable } from 'svelte/store'; - -function createAssetViewingStore() { - const viewingAssetStoreState = writable(); - const viewState = writable(false); - const gridScrollTarget = writable(); - - const setAsset = (asset: AssetResponseDto) => { - viewingAssetStoreState.set(asset); - viewState.set(true); - }; - - const setAssetId = async (id: string): Promise => { - const asset = await getAssetInfo({ ...authManager.params, id }); - setAsset(asset); - return asset; - }; - - const showAssetViewer = (show: boolean) => { - viewState.set(show); - }; - - return { - asset: readonly(viewingAssetStoreState), - isViewing: viewState, - gridScrollTarget, - setAsset, - setAssetId, - showAssetViewer, - }; -} - -export const assetViewingStore = createAssetViewingStore(); diff --git a/web/src/lib/stores/upload.ts b/web/src/lib/stores/upload.ts index 8e775b7b79..b36a2e5e70 100644 --- a/web/src/lib/stores/upload.ts +++ b/web/src/lib/stores/upload.ts @@ -80,7 +80,34 @@ function createUploadStore() { }; const removeItem = (id: string) => { - uploadAssets.update((uploadingAsset) => uploadingAsset.filter((a) => a.id != id)); + uploadAssets.update((uploadingAsset) => { + const assetToRemove = uploadingAsset.find((a) => a.id === id); + if (assetToRemove) { + stats.update((stats) => { + switch (assetToRemove.state) { + case UploadState.DONE: { + stats.success--; + break; + } + + case UploadState.DUPLICATED: { + stats.duplicates--; + break; + } + + case UploadState.ERROR: { + stats.errors--; + break; + } + } + + stats.total--; + return stats; + }); + } + + return uploadingAsset.filter((a) => a.id != id); + }); }; const dismissErrors = () => diff --git a/web/src/lib/types.ts b/web/src/lib/types.ts index 25524f1eea..619195711a 100644 --- a/web/src/lib/types.ts +++ b/web/src/lib/types.ts @@ -5,6 +5,8 @@ import type { ActionItem } from '@immich/ui'; import type { DateTime } from 'luxon'; import type { SvelteSet } from 'svelte/reactivity'; +export type LatLng = { lng: number; lat: number }; + export interface ReleaseEvent { isAvailable: boolean; /** ISO8601 */ diff --git a/web/src/lib/utils/actions.ts b/web/src/lib/utils/actions.ts index 05de75d3bc..46265a78bb 100644 --- a/web/src/lib/utils/actions.ts +++ b/web/src/lib/utils/actions.ts @@ -1,4 +1,3 @@ -import ToastAction from '$lib/components/ToastAction.svelte'; import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte'; import type { TimelineAsset } from '$lib/managers/timeline-manager/types'; import type { StackResponse } from '$lib/utils/asset-utils'; @@ -32,24 +31,15 @@ export const deleteAssets = async ( await deleteBulk({ assetBulkDeleteDto: { ids, force } }); onAssetDelete(ids); - toastManager.custom( + toastManager.primary( { - component: ToastAction, - props: { - title: $t('success'), - description: force - ? $t('assets_permanently_deleted_count', { values: { count: ids.length } }) - : $t('assets_trashed_count', { values: { count: ids.length } }), - color: 'success', - button: - onUndoDelete && !force - ? { - color: 'secondary', - text: $t('undo'), - onClick: () => undoDeleteAssets(onUndoDelete, assets), - } - : undefined, - }, + description: force + ? $t('assets_permanently_deleted_count', { values: { count: ids.length } }) + : $t('assets_trashed_count', { values: { count: ids.length } }), + button: + onUndoDelete && !force + ? { label: $t('undo'), color: 'secondary', onclick: () => undoDeleteAssets(onUndoDelete, assets) } + : undefined, }, { timeout: 5000 }, ); diff --git a/web/src/lib/utils/asset-utils.ts b/web/src/lib/utils/asset-utils.ts index 8605b7ffd0..79b5c207fa 100644 --- a/web/src/lib/utils/asset-utils.ts +++ b/web/src/lib/utils/asset-utils.ts @@ -1,4 +1,3 @@ -import ToastAction from '$lib/components/ToastAction.svelte'; import { authManager } from '$lib/managers/auth-manager.svelte'; import { downloadManager } from '$lib/managers/download-manager.svelte'; import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte'; @@ -326,16 +325,11 @@ export const stackAssets = async (assets: { id: string }[], showNotification = t try { const stack = await createStack({ stackCreateDto: { assetIds: assets.map(({ id }) => id) } }); if (showNotification) { - toastManager.custom({ - component: ToastAction, - props: { - title: $t('success'), - description: $t('stacked_assets_count', { values: { count: stack.assets.length } }), - color: 'success', - button: { - text: $t('view_stack'), - onClick: () => navigate({ targetRoute: 'current', assetId: stack.primaryAssetId }), - }, + toastManager.primary({ + description: $t('stacked_assets_count', { values: { count: stack.assets.length } }), + button: { + label: $t('view_stack'), + onclick: () => navigate({ targetRoute: 'current', assetId: stack.primaryAssetId }), }, }); } diff --git a/web/src/lib/utils/file-uploader.ts b/web/src/lib/utils/file-uploader.ts index f2a4cdec4f..2950563a85 100644 --- a/web/src/lib/utils/file-uploader.ts +++ b/web/src/lib/utils/file-uploader.ts @@ -216,7 +216,7 @@ async function fileUploader({ uploadAssetsStore.track('success'); } - if (albumId) { + if (albumId && !authManager.isSharedLink) { uploadAssetsStore.updateItem(deviceAssetId, { message: $t('asset_adding_to_album') }); await addAssetsToAlbums([albumId], [responseData.id], { notify: false }); uploadAssetsStore.updateItem(deviceAssetId, { message: $t('asset_added_to_album') }); diff --git a/web/src/routes/(user)/+layout.svelte b/web/src/routes/(user)/+layout.svelte index e6e349fe91..983d25eced 100644 --- a/web/src/routes/(user)/+layout.svelte +++ b/web/src/routes/(user)/+layout.svelte @@ -1,30 +1,28 @@ -
+
{@render children?.()}
diff --git a/web/src/routes/(user)/albums/[albumId=id]/[[photos=photos]]/[[assetId=id]]/+page.svelte b/web/src/routes/(user)/albums/[albumId=id]/[[photos=photos]]/[[assetId=id]]/+page.svelte index 2e911d8330..9010efe535 100644 --- a/web/src/routes/(user)/albums/[albumId=id]/[[photos=photos]]/[[assetId=id]]/+page.svelte +++ b/web/src/routes/(user)/albums/[albumId=id]/[[photos=photos]]/[[assetId=id]]/+page.svelte @@ -46,7 +46,6 @@ import { getGlobalActions } from '$lib/services/app.service'; import { getAssetBulkActions } from '$lib/services/asset.service'; import { AssetInteraction } from '$lib/stores/asset-interaction.svelte'; - import { assetViewingStore } from '$lib/stores/asset-viewing.store'; import { SlideshowNavigation, SlideshowState, slideshowStore } from '$lib/stores/slideshow.store'; import { preferences, user } from '$lib/stores/user.store'; import { handlePromiseError } from '$lib/utils'; @@ -86,14 +85,9 @@ } let { data = $bindable() }: Props = $props(); - - let { isViewing: showAssetViewer, setAssetId, gridScrollTarget } = assetViewingStore; let { slideshowState, slideshowNavigation } = slideshowStore; - let oldAt: AssetGridRouteSearchParams | null | undefined = $state(); - let viewMode: AlbumPageViewMode = $state(AlbumPageViewMode.VIEW); - let timelineManager = $state() as TimelineManager; let showAlbumUsers = $derived(timelineManager?.showAssetOwners ?? false); @@ -114,7 +108,9 @@ ? await timelineManager.getRandomAsset() : timelineManager.months[0]?.dayGroups[0]?.viewerAssets[0]?.asset; if (asset) { - handlePromiseError(setAssetId(asset.id).then(() => ($slideshowState = SlideshowState.PlaySlideshow))); + handlePromiseError( + assetViewerManager.setAssetId(asset.id).then(() => ($slideshowState = SlideshowState.PlaySlideshow)), + ); } }; @@ -128,7 +124,7 @@ await handleCloseSelectAssets(); return; } - if ($showAssetViewer) { + if (assetViewerManager.isViewing) { return; } if (assetInteraction.selectionActive) { @@ -240,7 +236,7 @@ const isShared = $derived(viewMode === AlbumPageViewMode.SELECT_ASSETS ? false : album.albumUsers.length > 0); $effect(() => { - if ($showAssetViewer || !isShared) { + if (assetViewerManager.isViewing || !isShared) { return; } @@ -252,7 +248,9 @@ let isOwned = $derived($user.id == album.ownerId); let showActivityStatus = $derived( - album.albumUsers.length > 0 && !$showAssetViewer && (album.isActivityEnabled || activityManager.commentCount > 0), + album.albumUsers.length > 0 && + !assetViewerManager.isViewing && + (album.isActivityEnabled || activityManager.commentCount > 0), ); let isEditor = $derived( album.albumUsers.find(({ user: { id } }) => id === $user.id)?.role === AlbumUserRole.Editor || @@ -287,7 +285,11 @@ } }; - const onAlbumAddAssets = async () => { + const onAlbumAddAssets = async ({ albumIds }: { albumIds: string[] }) => { + if (!albumIds.includes(album.id)) { + return; + } + await refreshAlbum(); timelineInteraction.clearMultiselect(); await setModeToView(); @@ -318,7 +320,7 @@ type: $t('command'), icon: mdiArrowLeft, onAction: handleEscape, - $if: () => !$showAssetViewer, + $if: () => !assetViewerManager.isViewing, shortcuts: { key: 'Escape' }, }); @@ -472,13 +474,6 @@ - {#if assetInteraction.selectedAssets.length === 1} - updateThumbnailUsingCurrentSelection()} - /> - {/if} {/if} + {#if assetInteraction.selectedAssets.length === 1} + updateThumbnailUsingCurrentSelection()} + /> + {/if} {#if $preferences.tags.enabled && assetInteraction.isAllUserOwned} @@ -514,7 +516,7 @@ onclick={async () => { timelineManager.suspendTransitions = true; viewMode = AlbumPageViewMode.SELECT_ASSETS; - oldAt = { at: $gridScrollTarget?.at }; + oldAt = { at: assetViewerManager.gridScrollTarget?.at }; await navigate( { targetRoute: 'current', assetId: null, assetGridRouteSearchParams: { at: null } }, { replaceState: true }, @@ -617,7 +619,7 @@ {/if} {/if}
- {#if album.albumUsers.length > 0 && album && assetViewerManager.isShowActivityPanel && $user && !$showAssetViewer} + {#if album.albumUsers.length > 0 && album && assetViewerManager.isShowActivityPanel && $user && !assetViewerManager.isViewing}
()); let selectedClusterBBox = $state.raw(); let isTimelinePanelVisible = $state(false); @@ -34,7 +31,7 @@ } onDestroy(() => { - assetViewingStore.showAssetViewer(false); + assetViewerManager.showAssetViewer(false); }); if (!featureFlagsManager.value.map) { @@ -42,7 +39,7 @@ } async function onViewAssets(assetIds: string[]) { - await setAssetId(assetIds[0]); + await assetViewerManager.setAssetId(assetIds[0]); closeTimelinePanel(); } @@ -50,7 +47,7 @@ selectedClusterIds = new Set(assetIds); selectedClusterBBox = bbox; isTimelinePanelVisible = true; - assetViewingStore.showAssetViewer(false); + assetViewerManager.showAssetViewer(false); handlePromiseError(navigate({ targetRoute: 'current', assetId: null })); } @@ -89,13 +86,13 @@
- {#if $showAssetViewer} + {#if assetViewerManager.isViewing} {#await import('$lib/components/asset-viewer/asset-viewer.svelte') then { default: AssetViewer }} { - assetViewingStore.showAssetViewer(false); + assetViewerManager.showAssetViewer(false); handlePromiseError(navigate({ targetRoute: 'current', assetId: null })); }} isShared={false} diff --git a/web/src/routes/(user)/photos/[[assetId=id]]/+page.svelte b/web/src/routes/(user)/photos/[[assetId=id]]/+page.svelte index 31a991fa8f..21f51a8f49 100644 --- a/web/src/routes/(user)/photos/[[assetId=id]]/+page.svelte +++ b/web/src/routes/(user)/photos/[[assetId=id]]/+page.svelte @@ -20,13 +20,13 @@ import AssetSelectControlBar from '$lib/components/timeline/AssetSelectControlBar.svelte'; import Timeline from '$lib/components/timeline/Timeline.svelte'; import { AssetAction } from '$lib/constants'; + import { assetViewerManager } from '$lib/managers/asset-viewer-manager.svelte'; + import { memoryManager } from '$lib/managers/memory-manager.svelte'; import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte'; import { Route } from '$lib/route'; import { getAssetBulkActions } from '$lib/services/asset.service'; import { AssetInteraction } from '$lib/stores/asset-interaction.svelte'; - import { assetViewingStore } from '$lib/stores/asset-viewing.store'; import { isFaceEditMode } from '$lib/stores/face-edit.svelte'; - import { memoryStore } from '$lib/stores/memory.store.svelte'; import { preferences, user } from '$lib/stores/user.store'; import { getAssetMediaUrl, memoryLaneTitle } from '$lib/utils'; import { @@ -43,7 +43,6 @@ import { mdiDotsVertical } from '@mdi/js'; import { t } from 'svelte-i18n'; - let { isViewing: showAssetViewer } = assetViewingStore; let timelineManager = $state() as TimelineManager; const options = { visibility: AssetVisibility.Timeline, withStacked: true, withPartners: true }; @@ -62,7 +61,7 @@ }); const handleEscape = () => { - if ($showAssetViewer) { + if (assetViewerManager.isViewing) { return; } if (assetInteraction.selectionActive) { @@ -91,7 +90,7 @@ }); const items = $derived( - memoryStore.memories.map((memory) => ({ + memoryManager.memories.map((memory) => ({ id: memory.id, title: $memoryLaneTitle(memory), href: Route.memories({ id: memory.assets[0].id }), diff --git a/web/src/routes/(user)/utilities/duplicates/[[photos=photos]]/[[assetId=id]]/+page.svelte b/web/src/routes/(user)/utilities/duplicates/[[photos=photos]]/[[assetId=id]]/+page.svelte index f1b9ca7614..c7d30febc7 100644 --- a/web/src/routes/(user)/utilities/duplicates/[[photos=photos]]/[[assetId=id]]/+page.svelte +++ b/web/src/routes/(user)/utilities/duplicates/[[photos=photos]]/[[assetId=id]]/+page.svelte @@ -4,11 +4,11 @@ import { shortcuts } from '$lib/actions/shortcut'; import UserPageLayout from '$lib/components/layouts/user-page-layout.svelte'; import DuplicatesCompareControl from '$lib/components/utilities-page/duplicates/duplicates-compare-control.svelte'; + import { assetViewerManager } from '$lib/managers/asset-viewer-manager.svelte'; import { featureFlagsManager } from '$lib/managers/feature-flags-manager.svelte'; import DuplicatesInformationModal from '$lib/modals/DuplicatesInformationModal.svelte'; import ShortcutsModal from '$lib/modals/ShortcutsModal.svelte'; import { Route } from '$lib/route'; - import { assetViewingStore } from '$lib/stores/asset-viewing.store'; import { locale } from '$lib/stores/preferences.store'; import { stackAssets } from '$lib/utils/asset-utils'; import { suggestDuplicate } from '$lib/utils/duplicate-utils'; @@ -57,7 +57,6 @@ }; let duplicates = $state(data.duplicates); - const { isViewing: showAssetViewer } = assetViewingStore; const correctDuplicatesIndex = (index: number) => { return Math.max(0, Math.min(index, duplicates.length - 1)); @@ -178,19 +177,7 @@ const handleFirst = () => navigateToIndex(0); const handlePrevious = () => navigateToIndex(Math.max(duplicatesIndex - 1, 0)); - const handlePreviousShortcut = async () => { - if ($showAssetViewer) { - return; - } - await handlePrevious(); - }; const handleNext = async () => navigateToIndex(Math.min(duplicatesIndex + 1, duplicates.length - 1)); - const handleNextShortcut = async () => { - if ($showAssetViewer) { - return; - } - await handleNext(); - }; const handleLast = () => navigateToIndex(duplicates.length - 1); const navigateToIndex = async (index: number) => @@ -198,10 +185,12 @@ diff --git a/web/src/routes/(user)/utilities/geolocation/+page.svelte b/web/src/routes/(user)/utilities/geolocation/+page.svelte index 9c8ad035f4..d8cd0c3850 100644 --- a/web/src/routes/(user)/utilities/geolocation/+page.svelte +++ b/web/src/routes/(user)/utilities/geolocation/+page.svelte @@ -1,6 +1,6 @@ @@ -68,7 +68,7 @@
-{#if $showAssetViewer} +{#if assetViewerManager.isViewing} {#await import('$lib/components/asset-viewer/asset-viewer.svelte') then { default: AssetViewer }} { - assetViewingStore.showAssetViewer(false); + assetViewerManager.showAssetViewer(false); handlePromiseError(navigate({ targetRoute: 'current', assetId: null })); }} /> diff --git a/web/src/routes/+layout.svelte b/web/src/routes/+layout.svelte index 046d5ce068..71bd66641c 100644 --- a/web/src/routes/+layout.svelte +++ b/web/src/routes/+layout.svelte @@ -52,7 +52,7 @@ prompt_default: $t('are_you_sure_to_do_this'), show_password: $t('show_password'), hide_password: $t('hide_password'), - dark_theme: $t('dark_theme'), + dark_theme: themeManager.isDark ? $t('light_theme') : $t('dark_theme'), open_menu: $t('open'), command_palette_prompt_default: $t('command_palette_prompt'), command_palette_to_select: $t('command_palette_to_select'),