From 0d907a2db23d4dac73774e6f1b3c2cf9f0285956 Mon Sep 17 00:00:00 2001 From: oscarlund121 Date: Mon, 8 Dec 2025 09:01:45 +0100 Subject: [PATCH 01/15] Diff sidebar (#607) Add diff sidebar Shows changes to OpenAPI spec between two branches using the oasdiff tool. --------- Co-authored-by: Ulrik Andersen --- .env.example | 1 + .github/workflows/check-changes-to-env.yml | 2 +- Dockerfile | 7 + README.md | 11 + __test__/diff/OasDiffCalculator.test.ts | 142 ++++++++++ package-lock.json | 246 ++++++++++++++---- package.json | 2 +- .../[owner]/[repository]/[...path]/route.ts | 45 ++++ src/common/github/GitHubClient.ts | 13 + src/common/github/IGitHubClient.ts | 12 + .../OAuthTokenRefreshingGitHubClient.ts | 10 +- .../github/RepoRestrictedGitHubClient.ts | 31 ++- src/common/ui/HighlightText.tsx | 2 +- src/common/ui/SpacedList.tsx | 26 +- src/composition.ts | 6 +- src/features/diff/data/IOasDiffCalculator.ts | 19 ++ src/features/diff/data/OasDiffCalculator.ts | 119 +++++++++ src/features/diff/domain/DiffChange.ts | 14 + .../projects/data/GitHubProjectDataSource.ts | 38 ++- .../data/GitHubRepositoryDataSource.ts | 104 +++++++- .../domain/IGitHubRepositoryDataSource.ts | 5 +- .../projects/domain/OpenApiSpecification.ts | 4 + .../projects/domain/ProjectNavigator.ts | 19 +- src/features/projects/domain/Version.ts | 2 +- .../view/toolbar/TrailingToolbarItem.tsx | 3 +- src/features/sidebar/data/index.ts | 1 + src/features/sidebar/data/useDiff.ts | 83 ++++++ src/features/sidebar/data/useDiffbarOpen.ts | 5 + src/features/sidebar/data/useSidebarOpen.ts | 2 +- .../sidebar/view/SecondarySplitHeader.tsx | 81 +++++- src/features/sidebar/view/SplitView.tsx | 3 +- .../sidebar/view/internal/ClientSplitView.tsx | 37 ++- .../view/internal/diffbar/DiffContent.tsx | 119 +++++++++ .../diffbar/components/DiffDialog.tsx | 120 +++++++++ .../internal/diffbar/components/DiffList.tsx | 49 ++++ .../diffbar/components/DiffListItem.tsx | 108 ++++++++ .../diffbar/components/MonoQuotedText.tsx | 29 +++ .../diffbar/components/PopulatedDiffList.tsx | 39 +++ .../diffbar/components/levelConfig.ts | 13 + .../view/internal/secondary/Container.tsx | 44 +++- .../view/internal/tertiary/RightContainer.tsx | 87 +++++++ 41 files changed, 1582 insertions(+), 121 deletions(-) create mode 100644 __test__/diff/OasDiffCalculator.test.ts create mode 100644 src/app/api/diff/[owner]/[repository]/[...path]/route.ts create mode 100644 src/features/diff/data/IOasDiffCalculator.ts create mode 100644 src/features/diff/data/OasDiffCalculator.ts create mode 100644 src/features/diff/domain/DiffChange.ts create mode 100644 src/features/sidebar/data/useDiff.ts create mode 100644 src/features/sidebar/data/useDiffbarOpen.ts create mode 100644 src/features/sidebar/view/internal/diffbar/DiffContent.tsx create mode 100644 src/features/sidebar/view/internal/diffbar/components/DiffDialog.tsx create mode 100644 src/features/sidebar/view/internal/diffbar/components/DiffList.tsx create mode 100644 src/features/sidebar/view/internal/diffbar/components/DiffListItem.tsx create mode 100644 src/features/sidebar/view/internal/diffbar/components/MonoQuotedText.tsx create mode 100644 src/features/sidebar/view/internal/diffbar/components/PopulatedDiffList.tsx create mode 100644 src/features/sidebar/view/internal/diffbar/components/levelConfig.ts create mode 100644 src/features/sidebar/view/internal/tertiary/RightContainer.tsx diff --git a/.env.example b/.env.example index 239f191a..3e2770b5 100644 --- a/.env.example +++ b/.env.example @@ -24,3 +24,4 @@ GITHUB_APP_ID=123456 GITHUB_PRIVATE_KEY_BASE_64=base 64 encoded version of the private key - see README.md for more info ENCRYPTION_PUBLIC_KEY_BASE_64=base 64 encoded version of the public key ENCRYPTION_PRIVATE_KEY_BASE_64=base 64 encoded version of the private key +NEXT_PUBLIC_ENABLE_DIFF_SIDEBAR=true diff --git a/.github/workflows/check-changes-to-env.yml b/.github/workflows/check-changes-to-env.yml index 61d982b9..bc67d682 100644 --- a/.github/workflows/check-changes-to-env.yml +++ b/.github/workflows/check-changes-to-env.yml @@ -1,7 +1,7 @@ name: Check Changes to Env permissions: contents: read - pull-requests: read + pull-requests: write issues: write on: pull_request: diff --git a/Dockerfile b/Dockerfile index b24c6764..671b45aa 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,11 @@ FROM node:24-alpine AS base +FROM base AS oasdiff +ARG OASDIFF_VERSION=2.10.0 +RUN apk add --no-cache curl tar ca-certificates +RUN curl -fsSL https://raw.githubusercontent.com/oasdiff/oasdiff/main/install.sh \ + | sh -s -- -b /usr/local/bin "v${OASDIFF_VERSION}" + # Install dependencies only when needed FROM base AS deps # Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed. @@ -46,6 +52,7 @@ RUN addgroup --system --gid 1001 nodejs RUN adduser --system --uid 1001 nextjs COPY --from=builder /app/public ./public +COPY --from=oasdiff /usr/local/bin/oasdiff /usr/local/bin/oasdiff # Set the correct permission for prerender cache RUN mkdir .next diff --git a/README.md b/README.md index d5695df4..dda1ecea 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,17 @@ Please refer to the following articles in [the wiki](https://github.com/shapehq/ - [Updating Documentation](https://github.com/shapehq/framna-docs/wiki/Updating-Documentation) - [Deploying Framna Docs](https://github.com/shapehq/framna-docs/wiki/Deploying-Framna-Docs) +### Install the OpenAPI diff tool locally + +Framna Docs relies on the [`oasdiff`](https://github.com/oasdiff/oasdiff) CLI when comparing specifications. + +On MacOS you can install with homebrew: + +```bash +brew tap oasdiff/homebrew-oasdiff +brew install oasdiff +``` + ## 👨‍🔧 How does it work? Framna Docs uses [OpenAPI specifications](https://swagger.io) from GitHub repositories. Users log in with their GitHub account to access documentation for projects they have access to. A repository only needs an OpenAPI spec to be recognized by Framna Docs, but customization is possible with a .framna-docs.yml file. Here's an example: diff --git a/__test__/diff/OasDiffCalculator.test.ts b/__test__/diff/OasDiffCalculator.test.ts new file mode 100644 index 00000000..cbe4932f --- /dev/null +++ b/__test__/diff/OasDiffCalculator.test.ts @@ -0,0 +1,142 @@ +import { OasDiffCalculator } from "../../src/features/diff/data/OasDiffCalculator" +import IGitHubClient from "../../src/common/github/IGitHubClient" + +const createMockGitHubClient = ( + baseUrl: string, + headUrl: string, + mergeBaseSha = "abc123" +): IGitHubClient => ({ + async compareCommitsWithBasehead() { + return { mergeBaseSha } + }, + async getRepositoryContent(request) { + if (request.ref === mergeBaseSha) { + return { downloadURL: baseUrl } + } + return { downloadURL: headUrl } + }, + async graphql() { + return {} + }, + async getPullRequestFiles() { + return [] + }, + async getPullRequestComments() { + return [] + }, + async addCommentToPullRequest() {}, + async updatePullRequestComment() {} +}) + +test("It rejects non-GitHub URLs for base spec", async () => { + const mockGitHubClient = createMockGitHubClient( + "https://malicious-site.com/file.yaml", + "https://raw.githubusercontent.com/owner/repo/main/file.yaml" + ) + const calculator = new OasDiffCalculator(mockGitHubClient) + + await expect( + calculator.calculateDiff("owner", "repo", "path.yaml", "base", "head") + ).rejects.toThrow("Invalid URL for base spec") +}) + +test("It rejects invalid URLs", async () => { + const mockGitHubClient = createMockGitHubClient( + "not-a-valid-url", + "https://raw.githubusercontent.com/owner/repo/main/file.yaml" + ) + const calculator = new OasDiffCalculator(mockGitHubClient) + + await expect( + calculator.calculateDiff("owner", "repo", "path.yaml", "base", "head") + ).rejects.toThrow("Invalid URL for base spec") +}) + +test("It accepts raw.githubusercontent.com URLs", async () => { + const mockGitHubClient = createMockGitHubClient( + "https://raw.githubusercontent.com/owner/repo/main/file1.yaml", + "https://raw.githubusercontent.com/owner/repo/main/file2.yaml" + ) + const calculator = new OasDiffCalculator(mockGitHubClient) + + // This will fail when trying to execute oasdiff, but that's expected + // We're only testing that URL validation passes + await expect( + calculator.calculateDiff("owner", "repo", "path.yaml", "base", "head") + ).rejects.toThrow("Failed to execute OpenAPI diff tool") +}) + +test("It accepts github.com URLs", async () => { + const mockGitHubClient = createMockGitHubClient( + "https://github.com/owner/repo/raw/main/file1.yaml", + "https://github.com/owner/repo/raw/main/file2.yaml" + ) + const calculator = new OasDiffCalculator(mockGitHubClient) + + // This will fail when trying to execute oasdiff, but that's expected + // We're only testing that URL validation passes + await expect( + calculator.calculateDiff("owner", "repo", "path.yaml", "base", "head") + ).rejects.toThrow("Failed to execute OpenAPI diff tool") +}) + +test("It accepts api.github.com URLs", async () => { + const mockGitHubClient = createMockGitHubClient( + "https://api.github.com/repos/owner/repo/contents/file1.yaml", + "https://api.github.com/repos/owner/repo/contents/file2.yaml" + ) + const calculator = new OasDiffCalculator(mockGitHubClient) + + // This will fail when trying to execute oasdiff, but that's expected + // We're only testing that URL validation passes + await expect( + calculator.calculateDiff("owner", "repo", "path.yaml", "base", "head") + ).rejects.toThrow("Failed to execute OpenAPI diff tool") +}) + +test("It rejects URLs with GitHub-like subdomains but different domains", async () => { + const mockGitHubClient = createMockGitHubClient( + "https://raw.githubusercontent.com.evil.com/file.yaml", + "https://raw.githubusercontent.com/owner/repo/main/file.yaml" + ) + const calculator = new OasDiffCalculator(mockGitHubClient) + + await expect( + calculator.calculateDiff("owner", "repo", "path.yaml", "base", "head") + ).rejects.toThrow("Invalid URL for base spec") +}) + +test("It validates both base and head URLs", async () => { + const mockGitHubClient = createMockGitHubClient( + "https://raw.githubusercontent.com/owner/repo/main/file1.yaml", + "https://malicious-site.com/file.yaml" + ) + const calculator = new OasDiffCalculator(mockGitHubClient) + + await expect( + calculator.calculateDiff("owner", "repo", "path.yaml", "base", "head") + ).rejects.toThrow("Invalid URL for head spec") +}) + +test("It returns empty changes when comparing same refs", async () => { + const mockGitHubClient = createMockGitHubClient( + "https://raw.githubusercontent.com/owner/repo/main/file1.yaml", + "https://raw.githubusercontent.com/owner/repo/main/file2.yaml", + "abc123" + ) + const calculator = new OasDiffCalculator(mockGitHubClient) + + const result = await calculator.calculateDiff( + "owner", + "repo", + "path.yaml", + "abc123", + "abc123" + ) + + expect(result).toEqual({ + from: "abc123", + to: "abc123", + changes: [] + }) +}) diff --git a/package-lock.json b/package-lock.json index e5b16364..30325963 100644 --- a/package-lock.json +++ b/package-lock.json @@ -154,7 +154,6 @@ "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", @@ -286,6 +285,7 @@ "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=6.9.0" } @@ -353,6 +353,7 @@ "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -366,6 +367,7 @@ "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -379,6 +381,7 @@ "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.12.13" }, @@ -392,6 +395,7 @@ "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" }, @@ -408,6 +412,7 @@ "integrity": "sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, @@ -424,6 +429,7 @@ "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, @@ -437,6 +443,7 @@ "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -450,6 +457,7 @@ "integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, @@ -466,6 +474,7 @@ "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, @@ -479,6 +488,7 @@ "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -492,6 +502,7 @@ "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, @@ -505,6 +516,7 @@ "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -518,6 +530,7 @@ "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -531,6 +544,7 @@ "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -544,6 +558,7 @@ "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" }, @@ -560,6 +575,7 @@ "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" }, @@ -576,6 +592,7 @@ "integrity": "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, @@ -645,7 +662,8 @@ "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@emnapi/core": { "version": "1.7.1", @@ -738,7 +756,6 @@ "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.14.0.tgz", "integrity": "sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==", "license": "MIT", - "peer": true, "dependencies": { "@babel/runtime": "^7.18.3", "@emotion/babel-plugin": "^11.13.5", @@ -782,7 +799,6 @@ "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.14.1.tgz", "integrity": "sha512-qEEJt42DuToa3gurlH4Qqc1kVpNq8wO8cJtDzU46TjlzWjDlsVyevtYCRijVq3SrHsROS+gVQ8Fnea108GnKzw==", "license": "MIT", - "peer": true, "dependencies": { "@babel/runtime": "^7.18.3", "@emotion/babel-plugin": "^11.13.5", @@ -1046,7 +1062,6 @@ "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-7.1.0.tgz", "integrity": "sha512-fNxRUk1KhjSbnbuBxlWSnBLKLBNun52ZBTcs22H/xEEzM6Ap81ZFTQ4bZBxVQGQgVY0xugKGoRcCbaKjLQ3XZA==", "license": "MIT", - "peer": true, "dependencies": { "@fortawesome/fontawesome-common-types": "7.1.0" }, @@ -1632,6 +1647,7 @@ "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", "dev": true, "license": "ISC", + "peer": true, "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", @@ -1650,6 +1666,7 @@ "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", "dev": true, "license": "ISC", + "peer": true, "dependencies": { "camelcase": "^5.3.1", "find-up": "^4.1.0", @@ -1667,6 +1684,7 @@ "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "sprintf-js": "~1.0.2" } @@ -1677,6 +1695,7 @@ "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" @@ -1691,6 +1710,7 @@ "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" @@ -1705,6 +1725,7 @@ "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "p-locate": "^4.1.0" }, @@ -1718,6 +1739,7 @@ "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "p-try": "^2.0.0" }, @@ -1734,6 +1756,7 @@ "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "p-limit": "^2.2.0" }, @@ -1747,6 +1770,7 @@ "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=8" } @@ -1757,6 +1781,7 @@ "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=8" } @@ -1767,6 +1792,7 @@ "integrity": "sha512-+O1ifRjkvYIkBqASKWgLxrpEhQAAE7hY77ALLUufSk5717KfOShg6IbqLmdsLMPdUiFvA2kTs0R7YZy+l0IzZQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", @@ -1785,6 +1811,7 @@ "integrity": "sha512-03W6IhuhjqTlpzh/ojut/pDB2LPRygyWX8ExpgHtQA8H/3K7+1vKmcINx5UzeOX1se6YEsBsOHQ1CRzf3fOwTQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@jest/console": "30.2.0", "@jest/pattern": "30.0.1", @@ -1843,6 +1870,7 @@ "integrity": "sha512-/QPTL7OBJQ5ac09UDRa3EQes4gt1FTEG/8jZ/4v5IVzx+Cv7dLxlVIvfvSVRiiX2drWyXeBjkMSR8hvOWSog5g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@jest/fake-timers": "30.2.0", "@jest/types": "30.2.0", @@ -1859,6 +1887,7 @@ "integrity": "sha512-V9yxQK5erfzx99Sf+7LbhBwNWEZ9eZay8qQ9+JSC0TrMR1pMDHLMY+BnVPacWU6Jamrh252/IKo4F1Xn/zfiqA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "expect": "30.2.0", "jest-snapshot": "30.2.0" @@ -1886,6 +1915,7 @@ "integrity": "sha512-HI3tRLjRxAbBy0VO8dqqm7Hb2mIa8d5bg/NJkyQcOk7V118ObQML8RC5luTF/Zsg4474a+gDvhce7eTnP4GhYw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@jest/types": "30.2.0", "@sinonjs/fake-timers": "^13.0.0", @@ -1914,6 +1944,7 @@ "integrity": "sha512-b63wmnKPaK+6ZZfpYhz9K61oybvbI1aMcIs80++JI1O1rR1vaxHUCNqo3ITu6NU0d4V34yZFoHMn/uoKr/Rwfw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@jest/environment": "30.2.0", "@jest/expect": "30.2.0", @@ -1944,6 +1975,7 @@ "integrity": "sha512-DRyW6baWPqKMa9CzeiBjHwjd8XeAyco2Vt8XbcLFjiwCOEKOvy82GJ8QQnJE9ofsxCMPjH4MfH8fCWIHHDKpAQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@bcoe/v8-coverage": "^0.2.3", "@jest/console": "30.2.0", @@ -2000,6 +2032,7 @@ "integrity": "sha512-0aVxM3RH6DaiLcjj/b0KrIBZhSX1373Xci4l3cW5xiUWPctZ59zQ7jj4rqcJQ/Z8JuN/4wX3FpJSa3RssVvCug==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@jest/types": "30.2.0", "chalk": "^4.1.2", @@ -2016,6 +2049,7 @@ "integrity": "sha512-MIRWMUUR3sdbP36oyNyhbThLHyJ2eEDClPCiHVbrYAe5g3CHRArIVpBw7cdSB5fr+ofSfIb2Tnsw8iEHL0PYQg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@jridgewell/trace-mapping": "^0.3.25", "callsites": "^3.1.0", @@ -2031,6 +2065,7 @@ "integrity": "sha512-RF+Z+0CCHkARz5HT9mcQCBulb1wgCP3FBvl9VFokMX27acKphwyQsNuWH3c+ojd1LeWBLoTYoxF0zm6S/66mjg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@jest/console": "30.2.0", "@jest/types": "30.2.0", @@ -2047,6 +2082,7 @@ "integrity": "sha512-wXKgU/lk8fKXMu/l5Hog1R61bL4q5GCdT6OJvdAFz1P+QrpoFuLU68eoKuVc4RbrTtNnTL5FByhWdLgOPSph+Q==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@jest/test-result": "30.2.0", "graceful-fs": "^4.2.11", @@ -2063,6 +2099,7 @@ "integrity": "sha512-XsauDV82o5qXbhalKxD7p4TZYYdwcaEXC77PPD2HixEFF+6YGppjrAAQurTl2ECWcEomHBMMNS9AH3kcCFx8jA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/core": "^7.27.4", "@jest/types": "30.2.0", @@ -2089,7 +2126,8 @@ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@jest/types": { "version": "30.2.0", @@ -2197,7 +2235,6 @@ "resolved": "https://registry.npmjs.org/@mui/material/-/material-7.3.5.tgz", "integrity": "sha512-8VVxFmp1GIm9PpmnQoCoYo0UWHoOrdA57tDL62vkpzEgvb/d71Wsbv4FRg7r1Gyx7PuSo0tflH34cdl/NvfHNQ==", "license": "MIT", - "peer": true, "dependencies": { "@babel/runtime": "^7.28.4", "@mui/core-downloads-tracker": "^7.3.5", @@ -2706,7 +2743,6 @@ "resolved": "https://registry.npmjs.org/@octokit/core/-/core-7.0.6.tgz", "integrity": "sha512-DhGl4xMVFGVIyMwswXeyzdL4uXD5OGILGX5N8Y+f6W7LhC1Ze2poSNrkF/fedpVDHEEZ+PHFW0vL14I+mm8K3Q==", "license": "MIT", - "peer": true, "dependencies": { "@octokit/auth-token": "^6.0.0", "@octokit/graphql": "^9.0.3", @@ -2953,6 +2989,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "engines": { "node": ">=14" } @@ -2963,6 +3000,7 @@ "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": "^12.20.0 || ^14.18.0 || >=16.0.0" }, @@ -3061,6 +3099,7 @@ "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", "dev": true, "license": "BSD-3-Clause", + "peer": true, "dependencies": { "type-detect": "4.0.8" } @@ -3071,6 +3110,7 @@ "integrity": "sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw==", "dev": true, "license": "BSD-3-Clause", + "peer": true, "dependencies": { "@sinonjs/commons": "^3.0.1" } @@ -3438,6 +3478,7 @@ "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", @@ -3452,6 +3493,7 @@ "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/types": "^7.0.0" } @@ -3462,6 +3504,7 @@ "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/parser": "^7.1.0", "@babel/types": "^7.0.0" @@ -3473,6 +3516,7 @@ "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/types": "^7.28.2" } @@ -3581,7 +3625,6 @@ "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.7.tgz", "integrity": "sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==", "license": "MIT", - "peer": true, "dependencies": { "csstype": "^3.2.2" } @@ -3678,7 +3721,6 @@ "integrity": "sha512-jCzKdm/QK0Kg4V4IK/oMlRZlY+QOcdjv89U2NgKHZk1CYTj82/RVSx1mV/0gqCVMJ/DA+Zf/S4NBWNF8GQ+eqQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.48.0", "@typescript-eslint/types": "8.48.0", @@ -3882,7 +3924,8 @@ "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", "dev": true, - "license": "ISC" + "license": "ISC", + "peer": true }, "node_modules/@unrs/resolver-binding-android-arm-eabi": { "version": "1.11.1", @@ -4159,7 +4202,6 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -4209,6 +4251,7 @@ "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "type-fest": "^0.21.3" }, @@ -4225,6 +4268,7 @@ "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -4253,6 +4297,7 @@ "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, "license": "ISC", + "peer": true, "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -4496,6 +4541,7 @@ "integrity": "sha512-0YiBEOxWqKkSQWL9nNGGEgndoeL0ZpWrbLMNL5u/Kaxrli3Eaxlt3ZtIDktEvXt4L/R9r3ODr2zKwGM/2BjxVw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@jest/transform": "30.2.0", "@types/babel__core": "^7.20.5", @@ -4518,6 +4564,7 @@ "integrity": "sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA==", "dev": true, "license": "BSD-3-Clause", + "peer": true, "workspaces": [ "test/babel-8" ], @@ -4538,6 +4585,7 @@ "integrity": "sha512-ftzhzSGMUnOzcCXd6WHdBGMyuwy15Wnn0iyyWGKgBDLxf9/s5ABuraCSpBX2uG0jUg4rqJnxsLc5+oYBqoxVaA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@types/babel__core": "^7.20.5" }, @@ -4566,6 +4614,7 @@ "integrity": "sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-bigint": "^7.8.3", @@ -4593,6 +4642,7 @@ "integrity": "sha512-US4Z3NOieAQumwFnYdUWKvUKh8+YSnS/gB3t6YBiz0bskpu7Pine8pPCheNxlPEW4wnUkma2a94YuW2q3guvCQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "babel-plugin-jest-hoist": "30.2.0", "babel-preset-current-node-syntax": "^1.2.0" @@ -4674,7 +4724,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "baseline-browser-mapping": "^2.8.25", "caniuse-lite": "^1.0.30001754", @@ -4708,6 +4757,7 @@ "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", "dev": true, "license": "Apache-2.0", + "peer": true, "dependencies": { "node-int64": "^0.4.0" } @@ -4717,7 +4767,8 @@ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/call-bind": { "version": "1.0.8", @@ -4790,6 +4841,7 @@ "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=6" } @@ -4846,6 +4898,7 @@ "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=10" } @@ -4871,7 +4924,8 @@ "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-2.1.1.tgz", "integrity": "sha512-+CmxIZ/L2vNcEfvNtLdU0ZQ6mbq3FZnwAP2PPTiKP+1QOoKwlKlPgb8UKV0Dds7QVaMnHm+FwSft2VB0s/SLjQ==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/classnames": { "version": "2.5.1", @@ -4981,6 +5035,7 @@ "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", "dev": true, "license": "MIT", + "peer": true, "engines": { "iojs": ">= 1.0.0", "node": ">= 0.12.0" @@ -4991,7 +5046,8 @@ "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.3.tgz", "integrity": "sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/color-convert": { "version": "2.0.1", @@ -5036,7 +5092,6 @@ "integrity": "sha512-c3Q2VVkGAUyupsjRnaNX6u8Dq2vAdzm9iuPj5FW0fRxzlxgq9Q39MDq10IvmQSpLgHQNyQzQmOo6bgGHmH3NNg==", "hasInstallScript": true, "license": "MIT", - "peer": true, "funding": { "type": "opencollective", "url": "https://opencollective.com/core-js" @@ -5197,6 +5252,7 @@ "integrity": "sha512-HGFtf8yhuhGhqO07SV79tRp+br4MnbdjeVxotpn1QBl30pcLLCQjX5b2295ll0fv8RKDKsmWYrl05usHM9CewQ==", "dev": true, "license": "MIT", + "peer": true, "peerDependencies": { "babel-plugin-macros": "^3.1.0" }, @@ -5219,6 +5275,7 @@ "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=0.10.0" } @@ -5292,6 +5349,7 @@ "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=8" } @@ -5348,7 +5406,8 @@ "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/electron-to-chromium": { "version": "1.5.254", @@ -5363,6 +5422,7 @@ "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -5382,7 +5442,6 @@ "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", "license": "MIT", - "peer": true, "dependencies": { "iconv-lite": "^0.6.2" } @@ -5620,7 +5679,6 @@ "integrity": "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -5806,7 +5864,6 @@ "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@rtsao/scc": "^1.1.0", "array-includes": "^3.1.9", @@ -6152,6 +6209,7 @@ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true, "license": "BSD-2-Clause", + "peer": true, "bin": { "esparse": "bin/esparse.js", "esvalidate": "bin/esvalidate.js" @@ -6218,6 +6276,7 @@ "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.0", @@ -6241,7 +6300,8 @@ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true, - "license": "ISC" + "license": "ISC", + "peer": true }, "node_modules/exit-x": { "version": "0.2.2", @@ -6249,6 +6309,7 @@ "integrity": "sha512-+I6B/IkJc1o/2tiURyz/ivu/O0nKNEArIUB5O7zBrlDVJr22SCLH3xTeEry428LvFhRzIA1g8izguxJ/gbNcVQ==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">= 0.8.0" } @@ -6393,6 +6454,7 @@ "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", "dev": true, "license": "Apache-2.0", + "peer": true, "dependencies": { "bser": "2.1.1" } @@ -6501,6 +6563,7 @@ "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", "dev": true, "license": "ISC", + "peer": true, "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" @@ -6517,7 +6580,8 @@ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "dev": true, - "license": "ISC" + "license": "ISC", + "peer": true }, "node_modules/fsevents": { "version": "2.3.3", @@ -6530,6 +6594,7 @@ "os": [ "darwin" ], + "peer": true, "engines": { "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } @@ -6634,6 +6699,7 @@ "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=8.0.0" } @@ -6658,6 +6724,7 @@ "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=10" }, @@ -6702,6 +6769,7 @@ "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", "dev": true, "license": "ISC", + "peer": true, "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", @@ -6949,7 +7017,8 @@ "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/http2-client": { "version": "1.3.5", @@ -6976,6 +7045,7 @@ "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "dev": true, "license": "Apache-2.0", + "peer": true, "engines": { "node": ">=10.17.0" } @@ -7024,6 +7094,7 @@ "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "pkg-dir": "^4.2.0", "resolve-cwd": "^3.0.0" @@ -7055,6 +7126,7 @@ "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", "dev": true, "license": "ISC", + "peer": true, "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -7065,7 +7137,8 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true, - "license": "ISC" + "license": "ISC", + "peer": true }, "node_modules/install": { "version": "0.13.0", @@ -7096,7 +7169,6 @@ "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.8.2.tgz", "integrity": "sha512-C6uC+kleiIMmjViJINWk80sOQw5lEzse1ZmvD+S/s8p8CWapftSaC+kocGTx6xrbrJ4WmYQGC08ffHLr6ToR6Q==", "license": "MIT", - "peer": true, "dependencies": { "@ioredis/commands": "1.4.0", "cluster-key-slot": "^1.1.0", @@ -7307,6 +7379,7 @@ "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=6" } @@ -7451,6 +7524,7 @@ "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=8" }, @@ -7575,6 +7649,7 @@ "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", "dev": true, "license": "BSD-3-Clause", + "peer": true, "engines": { "node": ">=8" } @@ -7585,6 +7660,7 @@ "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", "dev": true, "license": "BSD-3-Clause", + "peer": true, "dependencies": { "@babel/core": "^7.23.9", "@babel/parser": "^7.23.9", @@ -7602,6 +7678,7 @@ "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", "dev": true, "license": "BSD-3-Clause", + "peer": true, "dependencies": { "istanbul-lib-coverage": "^3.0.0", "make-dir": "^4.0.0", @@ -7617,6 +7694,7 @@ "integrity": "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==", "dev": true, "license": "BSD-3-Clause", + "peer": true, "dependencies": { "@jridgewell/trace-mapping": "^0.3.23", "debug": "^4.1.1", @@ -7632,6 +7710,7 @@ "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", "dev": true, "license": "BSD-3-Clause", + "peer": true, "dependencies": { "html-escaper": "^2.0.0", "istanbul-lib-report": "^3.0.0" @@ -7664,6 +7743,7 @@ "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", "dev": true, "license": "BlueOak-1.0.0", + "peer": true, "dependencies": { "@isaacs/cliui": "^8.0.2" }, @@ -7708,6 +7788,7 @@ "integrity": "sha512-L8lR1ChrRnSdfeOvTrwZMlnWV8G/LLjQ0nG9MBclwWZidA2N5FviRki0Bvh20WRMOX31/JYvzdqTJrk5oBdydQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "execa": "^5.1.1", "jest-util": "30.2.0", @@ -7723,6 +7804,7 @@ "integrity": "sha512-Fh0096NC3ZkFx05EP2OXCxJAREVxj1BcW/i6EWqqymcgYKWjyyDpral3fMxVcHXg6oZM7iULer9wGRFvfpl+Tg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@jest/environment": "30.2.0", "@jest/expect": "30.2.0", @@ -7755,6 +7837,7 @@ "integrity": "sha512-Os9ukIvADX/A9sLt6Zse3+nmHtHaE6hqOsjQtNiugFTbKRHYIYtZXNGNK9NChseXy7djFPjndX1tL0sCTlfpAA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@jest/core": "30.2.0", "@jest/test-result": "30.2.0", @@ -7788,6 +7871,7 @@ "integrity": "sha512-g4WkyzFQVWHtu6uqGmQR4CQxz/CH3yDSlhzXMWzNjDx843gYjReZnMRanjRCq5XZFuQrGDxgUaiYWE8BRfVckA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/core": "^7.27.4", "@jest/get-type": "30.1.0", @@ -7856,6 +7940,7 @@ "integrity": "sha512-tR/FFgZKS1CXluOQzZvNH3+0z9jXr3ldGSD8bhyuxvlVUwbeLOGynkunvlTMxchC5urrKndYiwCFC0DLVjpOCA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "detect-newline": "^3.1.0" }, @@ -7869,6 +7954,7 @@ "integrity": "sha512-lpWlJlM7bCUf1mfmuqTA8+j2lNURW9eNafOy99knBM01i5CQeY5UH1vZjgT9071nDJac1M4XsbyI44oNOdhlDQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@jest/get-type": "30.1.0", "@jest/types": "30.2.0", @@ -7886,6 +7972,7 @@ "integrity": "sha512-ElU8v92QJ9UrYsKrxDIKCxu6PfNj4Hdcktcn0JX12zqNdqWHB0N+hwOnnBBXvjLd2vApZtuLUGs1QSY+MsXoNA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@jest/environment": "30.2.0", "@jest/fake-timers": "30.2.0", @@ -7905,6 +7992,7 @@ "integrity": "sha512-sQA/jCb9kNt+neM0anSj6eZhLZUIhQgwDt7cPGjumgLM4rXsfb9kpnlacmvZz3Q5tb80nS+oG/if+NBKrHC+Xw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", @@ -7930,6 +8018,7 @@ "integrity": "sha512-M6jKAjyzjHG0SrQgwhgZGy9hFazcudwCNovY/9HPIicmNSBuockPSedAP9vlPK6ONFJ1zfyH/M2/YYJxOz5cdQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@jest/get-type": "30.1.0", "pretty-format": "30.2.0" @@ -7996,6 +8085,7 @@ "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=6" }, @@ -8024,6 +8114,7 @@ "integrity": "sha512-TCrHSxPlx3tBY3hWNtRQKbtgLhsXa1WmbJEqBlTBrGafd5fiQFByy2GNCEoGR+Tns8d15GaL9cxEzKOO3GEb2A==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "chalk": "^4.1.2", "graceful-fs": "^4.2.11", @@ -8044,6 +8135,7 @@ "integrity": "sha512-xTOIGug/0RmIe3mmCqCT95yO0vj6JURrn1TKWlNbhiAefJRWINNPgwVkrVgt/YaerPzY3iItufd80v3lOrFJ2w==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "jest-regex-util": "30.0.1", "jest-snapshot": "30.2.0" @@ -8058,6 +8150,7 @@ "integrity": "sha512-PqvZ2B2XEyPEbclp+gV6KO/F1FIFSbIwewRgmROCMBo/aZ6J1w8Qypoj2pEOcg3G2HzLlaP6VUtvwCI8dM3oqQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@jest/console": "30.2.0", "@jest/environment": "30.2.0", @@ -8092,6 +8185,7 @@ "integrity": "sha512-p1+GVX/PJqTucvsmERPMgCPvQJpFt4hFbM+VN3n8TMo47decMUcJbt+rgzwrEme0MQUA/R+1de2axftTHkKckg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@jest/environment": "30.2.0", "@jest/fake-timers": "30.2.0", @@ -8126,6 +8220,7 @@ "integrity": "sha512-5WEtTy2jXPFypadKNpbNkZ72puZCa6UjSr/7djeecHWOu7iYhSXSnHScT8wBz3Rn8Ena5d5RYRcsyKIeqG1IyA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/core": "^7.27.4", "@babel/generator": "^7.27.5", @@ -8190,6 +8285,7 @@ "integrity": "sha512-FBGWi7dP2hpdi8nBoWxSsLvBFewKAg0+uSQwBaof4Y4DPgBabXgpSYC5/lR7VmnIlSpASmCi/ntRWPbv7089Pw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@jest/get-type": "30.1.0", "@jest/types": "30.2.0", @@ -8208,6 +8304,7 @@ "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=10" }, @@ -8221,6 +8318,7 @@ "integrity": "sha512-PYxa28dxJ9g777pGm/7PrbnMeA0Jr7osHP9bS7eJy9DuAjMgdGtxgf0uKMyoIsTWAkIbUW5hSDdJ3urmgXBqxg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@jest/test-result": "30.2.0", "@jest/types": "30.2.0", @@ -8241,6 +8339,7 @@ "integrity": "sha512-0Q4Uk8WF7BUwqXHuAjc23vmopWJw5WH7w2tqBoUOZpOjW/ZnR44GXXd1r82RvnmI2GZge3ivrYXk/BE2+VtW2g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@types/node": "*", "@ungap/structured-clone": "^1.3.0", @@ -8258,6 +8357,7 @@ "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -8427,6 +8527,7 @@ "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=6" } @@ -8804,6 +8905,7 @@ "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "semver": "^7.5.3" }, @@ -8827,6 +8929,7 @@ "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", "dev": true, "license": "BSD-3-Clause", + "peer": true, "dependencies": { "tmpl": "1.0.5" } @@ -8864,7 +8967,8 @@ "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/merge2": { "version": "1.4.1", @@ -8896,6 +9000,7 @@ "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=6" } @@ -8932,6 +9037,7 @@ "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", "dev": true, "license": "ISC", + "peer": true, "engines": { "node": ">=16 || 14 >=14.17" } @@ -8941,7 +9047,6 @@ "resolved": "https://registry.npmjs.org/mobx/-/mobx-6.15.0.tgz", "integrity": "sha512-UczzB+0nnwGotYSgllfARAqWCJ5e/skuV2K/l+Zyck/H6pJIhLXuBnz+6vn2i211o7DtbE78HQtsYEKICHGI+g==", "license": "MIT", - "peer": true, "funding": { "type": "opencollective", "url": "https://opencollective.com/mobx" @@ -9224,7 +9329,8 @@ "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/node-readfiles": { "version": "0.2.0", @@ -9248,6 +9354,7 @@ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=0.10.0" } @@ -9414,6 +9521,7 @@ "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "path-key": "^3.0.0" }, @@ -11117,7 +11225,6 @@ "version": "4.0.3", "inBundle": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -11500,6 +11607,7 @@ "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "dev": true, "license": "ISC", + "peer": true, "dependencies": { "wrappy": "1" } @@ -11510,6 +11618,7 @@ "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "mimic-fn": "^2.1.0" }, @@ -11605,6 +11714,7 @@ "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=6" } @@ -11614,7 +11724,8 @@ "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", "dev": true, - "license": "BlueOak-1.0.0" + "license": "BlueOak-1.0.0", + "peer": true }, "node_modules/parent-module": { "version": "1.0.1", @@ -11668,6 +11779,7 @@ "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=0.10.0" } @@ -11694,6 +11806,7 @@ "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", "dev": true, "license": "BlueOak-1.0.0", + "peer": true, "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" @@ -11710,7 +11823,8 @@ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", "dev": true, - "license": "ISC" + "license": "ISC", + "peer": true }, "node_modules/path-type": { "version": "4.0.0", @@ -11733,7 +11847,6 @@ "integrity": "sha512-enxc1h0jA/aq5oSDMvqyW3q89ra6XIIDZgCX9vkMrnz5DFTw/Ny3Li2lFQ+pt3L6MCgm/5o2o8HW9hiJji+xvw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "pg-connection-string": "^2.9.1", "pg-pool": "^3.10.1", @@ -11850,6 +11963,7 @@ "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">= 6" } @@ -11860,6 +11974,7 @@ "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "find-up": "^4.0.0" }, @@ -11873,6 +11988,7 @@ "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" @@ -11887,6 +12003,7 @@ "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "p-locate": "^4.1.0" }, @@ -11900,6 +12017,7 @@ "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "p-try": "^2.0.0" }, @@ -11916,6 +12034,7 @@ "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "p-limit": "^2.2.0" }, @@ -12037,7 +12156,6 @@ "resolved": "https://registry.npmjs.org/preact/-/preact-10.24.3.tgz", "integrity": "sha512-Z2dPnBnMUfyQfSQ+GBdsGa16hz35YmLmtTLhM169uW944hYL6xzTYkJjC07j+Wosz733pMWx0fgON3JNw1jJQA==", "license": "MIT", - "peer": true, "funding": { "type": "opencollective", "url": "https://opencollective.com/preact" @@ -12148,7 +12266,8 @@ "url": "https://opencollective.com/fast-check" } ], - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/queue-microtask": { "version": "1.2.3", @@ -12176,7 +12295,6 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz", "integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -12186,7 +12304,6 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz", "integrity": "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==", "license": "MIT", - "peer": true, "dependencies": { "scheduler": "^0.27.0" }, @@ -12407,6 +12524,7 @@ "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "resolve-from": "^5.0.0" }, @@ -12420,6 +12538,7 @@ "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=8" } @@ -12815,6 +12934,7 @@ "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", "dev": true, "license": "ISC", + "peer": true, "engines": { "node": ">=14" }, @@ -12865,6 +12985,7 @@ "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" @@ -12876,6 +12997,7 @@ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, "license": "BSD-3-Clause", + "peer": true, "engines": { "node": ">=0.10.0" } @@ -12895,7 +13017,8 @@ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", "dev": true, - "license": "BSD-3-Clause" + "license": "BSD-3-Clause", + "peer": true }, "node_modules/stable-hash": { "version": "0.0.5", @@ -12958,6 +13081,7 @@ "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "char-regex": "^1.0.2", "strip-ansi": "^6.0.0" @@ -12972,6 +13096,7 @@ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=8" } @@ -12982,6 +13107,7 @@ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -12995,6 +13121,7 @@ "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", @@ -13014,6 +13141,7 @@ "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -13029,6 +13157,7 @@ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=8" } @@ -13038,7 +13167,8 @@ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/string-width-cjs/node_modules/strip-ansi": { "version": "6.0.1", @@ -13046,6 +13176,7 @@ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -13172,6 +13303,7 @@ "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "ansi-regex": "^6.0.1" }, @@ -13189,6 +13321,7 @@ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -13202,6 +13335,7 @@ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=8" } @@ -13212,6 +13346,7 @@ "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=8" } @@ -13222,6 +13357,7 @@ "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=6" } @@ -13256,7 +13392,6 @@ "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-6.1.19.tgz", "integrity": "sha512-1v/e3Dl1BknC37cXMhwGomhO8AkYmN41CqyX9xhUDxry1ns3BFQy2lLDRQXJRdVVWB9OHemv/53xaStimvWyuA==", "license": "MIT", - "peer": true, "dependencies": { "@emotion/is-prop-valid": "1.2.2", "@emotion/unitless": "0.8.1", @@ -13456,6 +13591,7 @@ "integrity": "sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@pkgr/core": "^0.2.9" }, @@ -13493,6 +13629,7 @@ "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", "dev": true, "license": "ISC", + "peer": true, "dependencies": { "@istanbuljs/schema": "^0.1.2", "glob": "^7.1.4", @@ -13508,6 +13645,7 @@ "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -13520,6 +13658,7 @@ "deprecated": "Glob versions prior to v9 are no longer supported", "dev": true, "license": "ISC", + "peer": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -13541,6 +13680,7 @@ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, "license": "ISC", + "peer": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -13589,7 +13729,6 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -13602,7 +13741,8 @@ "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", "dev": true, - "license": "BSD-3-Clause" + "license": "BSD-3-Clause", + "peer": true }, "node_modules/to-regex-range": { "version": "5.0.1", @@ -13772,6 +13912,7 @@ "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=4" } @@ -13782,6 +13923,7 @@ "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", "dev": true, "license": "(MIT OR CC0-1.0)", + "peer": true, "engines": { "node": ">=10" }, @@ -13873,7 +14015,6 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -14070,6 +14211,7 @@ "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", "dev": true, "license": "ISC", + "peer": true, "dependencies": { "@jridgewell/trace-mapping": "^0.3.12", "@types/istanbul-lib-coverage": "^2.0.1", @@ -14084,7 +14226,8 @@ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/walker": { "version": "1.0.8", @@ -14092,6 +14235,7 @@ "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", "dev": true, "license": "Apache-2.0", + "peer": true, "dependencies": { "makeerror": "1.0.12" } @@ -14240,6 +14384,7 @@ "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", @@ -14259,6 +14404,7 @@ "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -14277,6 +14423,7 @@ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=8" } @@ -14286,7 +14433,8 @@ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/wrap-ansi-cjs/node_modules/string-width": { "version": "4.2.3", @@ -14294,6 +14442,7 @@ "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -14309,6 +14458,7 @@ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -14322,6 +14472,7 @@ "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -14334,7 +14485,8 @@ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true, - "license": "ISC" + "license": "ISC", + "peer": true }, "node_modules/write-file-atomic": { "version": "5.0.1", @@ -14342,6 +14494,7 @@ "integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==", "dev": true, "license": "ISC", + "peer": true, "dependencies": { "imurmurhash": "^0.1.4", "signal-exit": "^4.0.1" @@ -14483,7 +14636,6 @@ "resolved": "https://registry.npmjs.org/zod/-/zod-4.1.13.tgz", "integrity": "sha512-AvvthqfqrAhNH9dnfmrfKzX5upOdjUVJYFqNSlkmGf64gRaTzlPwz99IHYnVs28qYAybvAlBV+H7pn0saFY4Ig==", "license": "MIT", - "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/package.json b/package.json index 7a8667be..8740505a 100644 --- a/package.json +++ b/package.json @@ -57,9 +57,9 @@ "@types/node": "^24.10.1", "@types/nprogress": "^0.2.3", "@types/pg": "^8.15.6", - "@typescript-eslint/eslint-plugin": "^8.48.0", "@types/react": "^19.2.7", "@types/react-dom": "^19.2.3", + "@typescript-eslint/eslint-plugin": "^8.48.0", "@typescript-eslint/parser": "^8.48.0", "typescript-eslint": "^8.48.0", "eslint": "^9.39.1", diff --git a/src/app/api/diff/[owner]/[repository]/[...path]/route.ts b/src/app/api/diff/[owner]/[repository]/[...path]/route.ts new file mode 100644 index 00000000..7486ce4d --- /dev/null +++ b/src/app/api/diff/[owner]/[repository]/[...path]/route.ts @@ -0,0 +1,45 @@ +import { NextRequest, NextResponse } from "next/server" +import { session, diffCalculator } from "@/composition" +import { makeUnauthenticatedAPIErrorResponse } from "@/common" + +interface GetDiffParams { + owner: string + repository: string + path: string[] +} + +export async function GET(req: NextRequest, { params }: { params: Promise }) { + const isAuthenticated = await session.getIsAuthenticated() + if (!isAuthenticated) { + return makeUnauthenticatedAPIErrorResponse() + } + + const { path: paramsPath, owner, repository } = await params + const path = paramsPath.join("/") + + const toRef = req.nextUrl.searchParams.get("to") + const baseRefOid = req.nextUrl.searchParams.get("baseRefOid") + + if (!toRef) { + return NextResponse.json({ error: "Missing 'to' parameter" }, { status: 400 }) + } + + if (!baseRefOid) { + return NextResponse.json({ error: "Missing 'baseRefOid' parameter" }, { status: 400 }) + } + + try { + const diff = await diffCalculator.calculateDiff( + owner, + repository, + path, + baseRefOid, + toRef + ) + + return NextResponse.json(diff) + } catch (error) { + const message = error instanceof Error ? error.message : "Unknown error while calculating diff" + return NextResponse.json({ error: message }, { status: 500 }) + } +} diff --git a/src/common/github/GitHubClient.ts b/src/common/github/GitHubClient.ts index 3ecf10e1..6a47674f 100644 --- a/src/common/github/GitHubClient.ts +++ b/src/common/github/GitHubClient.ts @@ -8,6 +8,8 @@ import IGitHubClient, { GetPullRequestFilesRequest, AddCommentToPullRequestRequest, UpdatePullRequestCommentRequest, + CompareCommitsRequest, + CompareCommitsResponse, RepositoryContent, PullRequestComment, PullRequestFile @@ -119,4 +121,15 @@ export default class GitHubClient implements IGitHubClient { body: request.body }) } + + async compareCommitsWithBasehead(request: CompareCommitsRequest): Promise { + const oauthToken = await this.oauthTokenDataSource.getOAuthToken() + const octokit = new Octokit({ auth: oauthToken.accessToken }) + const response = await octokit.rest.repos.compareCommitsWithBasehead({ + owner: request.repositoryOwner, + repo: request.repositoryName, + basehead: `${request.baseRefOid}...${request.headRefOid}` + }) + return { mergeBaseSha: response.data.merge_base_commit.sha } + } } diff --git a/src/common/github/IGitHubClient.ts b/src/common/github/IGitHubClient.ts index a739f69c..601de84b 100644 --- a/src/common/github/IGitHubClient.ts +++ b/src/common/github/IGitHubClient.ts @@ -70,6 +70,17 @@ export type UpdatePullRequestCommentRequest = { readonly body: string } +export type CompareCommitsRequest = { + readonly repositoryOwner: string + readonly repositoryName: string + readonly baseRefOid: string + readonly headRefOid: string +} + +export type CompareCommitsResponse = { + readonly mergeBaseSha: string +} + export default interface IGitHubClient { graphql(request: GraphQLQueryRequest): Promise getRepositoryContent(request: GetRepositoryContentRequest): Promise @@ -77,4 +88,5 @@ export default interface IGitHubClient { getPullRequestComments(request: GetPullRequestCommentsRequest): Promise addCommentToPullRequest(request: AddCommentToPullRequestRequest): Promise updatePullRequestComment(request: UpdatePullRequestCommentRequest): Promise + compareCommitsWithBasehead(request: CompareCommitsRequest): Promise } diff --git a/src/common/github/OAuthTokenRefreshingGitHubClient.ts b/src/common/github/OAuthTokenRefreshingGitHubClient.ts index 48b6373e..ad33dd8a 100644 --- a/src/common/github/OAuthTokenRefreshingGitHubClient.ts +++ b/src/common/github/OAuthTokenRefreshingGitHubClient.ts @@ -7,6 +7,8 @@ import IGitHubClient, { AddCommentToPullRequestRequest, UpdatePullRequestCommentRequest, GetPullRequestFilesRequest, + CompareCommitsRequest, + CompareCommitsResponse, RepositoryContent, PullRequestComment, PullRequestFile @@ -76,7 +78,13 @@ export default class OAuthTokenRefreshingGitHubClient implements IGitHubClient { return await this.gitHubClient.updatePullRequestComment(request) }) } - + + async compareCommitsWithBasehead(request: CompareCommitsRequest): Promise { + return await this.send(async () => { + return await this.gitHubClient.compareCommitsWithBasehead(request) + }) + } + private async send(fn: () => Promise): Promise { const oauthToken = await this.oauthTokenDataSource.getOAuthToken() try { diff --git a/src/common/github/RepoRestrictedGitHubClient.ts b/src/common/github/RepoRestrictedGitHubClient.ts index 558492f3..eb15dd5c 100644 --- a/src/common/github/RepoRestrictedGitHubClient.ts +++ b/src/common/github/RepoRestrictedGitHubClient.ts @@ -1,15 +1,17 @@ -import { - IGitHubClient, - AddCommentToPullRequestRequest, - GetPullRequestCommentsRequest, - GetPullRequestFilesRequest, - GetRepositoryContentRequest, - GraphQLQueryRequest, - GraphQlQueryResponse, - PullRequestComment, - PullRequestFile, - RepositoryContent, - UpdatePullRequestCommentRequest +import { + IGitHubClient, + AddCommentToPullRequestRequest, + GetPullRequestCommentsRequest, + GetPullRequestFilesRequest, + GetRepositoryContentRequest, + GraphQLQueryRequest, + GraphQlQueryResponse, + PullRequestComment, + PullRequestFile, + RepositoryContent, + UpdatePullRequestCommentRequest, + CompareCommitsRequest, + CompareCommitsResponse } from "@/common"; export class RepoRestrictedGitHubClient implements IGitHubClient { @@ -54,6 +56,11 @@ export class RepoRestrictedGitHubClient implements IGitHubClient { return this.gitHubClient.updatePullRequestComment(request); } + compareCommitsWithBasehead(request: CompareCommitsRequest): Promise { + if (!this.isRepositoryNameValid(request.repositoryName)) return Promise.reject(new Error("Invalid repository name")); + return this.gitHubClient.compareCommitsWithBasehead(request); + } + private isRepositoryNameValid(repositoryName: string): boolean { return repositoryName.endsWith(this.repositoryNameSuffix); } diff --git a/src/common/ui/HighlightText.tsx b/src/common/ui/HighlightText.tsx index db6570e1..67ec7fe8 100644 --- a/src/common/ui/HighlightText.tsx +++ b/src/common/ui/HighlightText.tsx @@ -1,5 +1,5 @@ "use client" -import React from "react" + import { SxProps, Typography, TypographyVariant } from "@mui/material" import styled from "@emotion/styled" diff --git a/src/common/ui/SpacedList.tsx b/src/common/ui/SpacedList.tsx index 313acaef..1aa2b11a 100644 --- a/src/common/ui/SpacedList.tsx +++ b/src/common/ui/SpacedList.tsx @@ -1,21 +1,25 @@ import React from "react" import { List, Box, SxProps } from "@mui/material" -const SpacedList = ({ - itemSpacing, - sx, - children -}: { +interface SpacedListProps { itemSpacing: number sx?: SxProps children?: React.ReactNode -}) => { +} + +const SpacedList = ({ itemSpacing, sx, children }: SpacedListProps) => { + const childrenArray = React.Children.toArray(children) + const lastIndex = childrenArray.length - 1 + return ( - - {React.Children.map(children, (child, idx) => ( - + + {childrenArray.map((child, idx) => ( + {child} ))} diff --git a/src/composition.ts b/src/composition.ts index 10f4e504..8187b966 100644 --- a/src/composition.ts +++ b/src/composition.ts @@ -53,6 +53,8 @@ import { import { RepoRestrictedGitHubClient } from "./common/github/RepoRestrictedGitHubClient" import RsaEncryptionService from "./features/encrypt/EncryptionService" import RemoteConfigEncoder from "./features/projects/domain/RemoteConfigEncoder" +import { OasDiffCalculator } from "./features/diff/data/OasDiffCalculator" +import { IOasDiffCalculator } from "./features/diff/data/IOasDiffCalculator" const gitHubAppCredentials = { appId: env.getOrThrow("GITHUB_APP_ID"), @@ -230,4 +232,6 @@ export const gitHubHookHandler = new GitHubHookHandler({ }) }) }) -}) \ No newline at end of file +}) + +export const diffCalculator: IOasDiffCalculator = new OasDiffCalculator(gitHubClient) diff --git a/src/features/diff/data/IOasDiffCalculator.ts b/src/features/diff/data/IOasDiffCalculator.ts new file mode 100644 index 00000000..92261518 --- /dev/null +++ b/src/features/diff/data/IOasDiffCalculator.ts @@ -0,0 +1,19 @@ +import { DiffChange } from "../domain/DiffChange" + +export interface DiffResult { + from: string + to: string + changes: DiffChange[] + error?: string | null + isNewFile?: boolean +} + +export interface IOasDiffCalculator { + calculateDiff( + owner: string, + repository: string, + path: string, + baseRefOid: string, + toRef: string + ): Promise +} diff --git a/src/features/diff/data/OasDiffCalculator.ts b/src/features/diff/data/OasDiffCalculator.ts new file mode 100644 index 00000000..a15fe67c --- /dev/null +++ b/src/features/diff/data/OasDiffCalculator.ts @@ -0,0 +1,119 @@ +import { execFileSync } from "child_process" +import { DiffChange } from "@/features/diff/domain/DiffChange" +import type { IGitHubClient } from "@/common" +import { DiffResult, IOasDiffCalculator } from "./IOasDiffCalculator" + +/** + * Validates that a URL originates from a trusted GitHub domain. + * @param url - The URL to validate + * @returns true if the URL is from a trusted GitHub domain, false otherwise + */ +function isValidGitHubUrl(url: string): boolean { + try { + const parsedUrl = new URL(url) + const trustedDomains = [ + "raw.githubusercontent.com", + "github.com", + "api.github.com" + ] + return trustedDomains.includes(parsedUrl.hostname) + } catch { + return false + } +} + +export class OasDiffCalculator implements IOasDiffCalculator { + constructor(private readonly githubClient: IGitHubClient) {} + + async calculateDiff( + owner: string, + repository: string, + path: string, + baseRefOid: string, + toRef: string + ): Promise { + // Calculate merge-base for diff + const mergeBaseResult = await this.githubClient.compareCommitsWithBasehead({ + repositoryOwner: owner, + repositoryName: repository, + baseRefOid: baseRefOid, + headRefOid: toRef + }) + const fromRef = mergeBaseResult.mergeBaseSha + + // If comparing same refs, return empty diff + if (fromRef === toRef) { + return { + from: fromRef, + to: toRef, + changes: [] + } + } + + // Fetch spec content from both refs + let spec1 + + try { + spec1 = await this.githubClient.getRepositoryContent({ + repositoryOwner: owner, + repositoryName: repository, + path: path, + ref: fromRef + }) + } catch { + // File doesn't exist in base ref - this is a new file + return { + from: fromRef, + to: toRef, + changes: [], + isNewFile: true + } + } + + const spec2 = await this.githubClient.getRepositoryContent({ + repositoryOwner: owner, + repositoryName: repository, + path: path, + ref: toRef + }) + + // Validate URLs originate from GitHub + if (!isValidGitHubUrl(spec1.downloadURL)) { + throw new Error( + `Invalid URL for base spec: ${spec1.downloadURL}. URL must originate from a trusted GitHub domain.` + ) + } + if (!isValidGitHubUrl(spec2.downloadURL)) { + throw new Error( + `Invalid URL for head spec: ${spec2.downloadURL}. URL must originate from a trusted GitHub domain.` + ) + } + + // Execute oasdiff + const diffData = (() => { + try { + const result = execFileSync( + "oasdiff", + ["changelog", "--format", "json", spec1.downloadURL, spec2.downloadURL], + { encoding: "utf8" } + ) + return JSON.parse(result) as DiffChange[] + } catch (error) { + const errorMessage = + error instanceof Error + ? error.message + : "Unknown error when executing OpenAPI diff command" + throw new Error( + `Failed to execute OpenAPI diff tool. Please ensure "oasdiff" is installed and available in PATH. (${errorMessage})` + ) + } + })() + + return { + from: fromRef, + to: toRef, + changes: diffData, + error: null + } + } +} diff --git a/src/features/diff/domain/DiffChange.ts b/src/features/diff/domain/DiffChange.ts new file mode 100644 index 00000000..83c61036 --- /dev/null +++ b/src/features/diff/domain/DiffChange.ts @@ -0,0 +1,14 @@ +import { z } from "zod" + +export const DiffChangeSchema = z.object({ + id: z.string(), + text: z.string(), + level: z.number(), + operation: z.string().optional(), + operationId: z.string().optional(), + path: z.string().optional(), + source: z.string().optional(), + section: z.string().optional(), +}) + +export type DiffChange = z.infer diff --git a/src/features/projects/data/GitHubProjectDataSource.ts b/src/features/projects/data/GitHubProjectDataSource.ts index 17086513..f8e1f8d8 100644 --- a/src/features/projects/data/GitHubProjectDataSource.ts +++ b/src/features/projects/data/GitHubProjectDataSource.ts @@ -131,7 +131,17 @@ export default class GitHubProjectDataSource implements IProjectDataSource { path: file.name, ref: ref.id }), - editURL: `https://github.com/${ownerName}/${repositoryName}/edit/${ref.name}/${file.name}`, + editURL: `https://github.com/${ownerName}/${repositoryName}/edit/${ref.name}/${encodeURIComponent(file.name)}`, + diffURL: this.getGitHubDiffURL({ + ownerName, + repositoryName, + path: file.name, + baseRefOid: ref.baseRefOid, + headRefOid: ref.id + }), + diffBaseBranch: ref.baseRef, + diffBaseOid: ref.baseRefOid, + diffPrUrl: ref.prNumber ? `https://github.com/${ownerName}/${repositoryName}/pull/${ref.prNumber}` : undefined, isDefault: false // initial value } }).sort((a, b) => a.name.localeCompare(b.name)) @@ -140,7 +150,7 @@ export default class GitHubProjectDataSource implements IProjectDataSource { name: ref.name, specifications: specifications, url: `https://github.com/${ownerName}/${repositoryName}/tree/${ref.name}`, - isDefault: isDefaultRef || false + isDefault: isDefaultRef || false, } } @@ -161,7 +171,29 @@ export default class GitHubProjectDataSource implements IProjectDataSource { path: string ref: string }): string { - return `/api/blob/${ownerName}/${repositoryName}/${path}?ref=${ref}` + const encodedPath = path.split('/').map(segment => encodeURIComponent(segment)).join('/') + return `/api/blob/${ownerName}/${repositoryName}/${encodedPath}?ref=${ref}` + } + + private getGitHubDiffURL({ + ownerName, + repositoryName, + path, + baseRefOid, + headRefOid + }: { + ownerName: string; + repositoryName: string; + path: string; + baseRefOid: string | undefined; + headRefOid: string } + ): string | undefined { + if (!baseRefOid) { + return undefined + } else { + const encodedPath = path.split('/').map(segment => encodeURIComponent(segment)).join('/') + return `/api/diff/${ownerName}/${repositoryName}/${encodedPath}?baseRefOid=${baseRefOid}&to=${headRefOid}` + } } private addRemoteVersions( diff --git a/src/features/projects/data/GitHubRepositoryDataSource.ts b/src/features/projects/data/GitHubRepositoryDataSource.ts index 569a4bd1..c107b506 100644 --- a/src/features/projects/data/GitHubRepositoryDataSource.ts +++ b/src/features/projects/data/GitHubRepositoryDataSource.ts @@ -46,6 +46,13 @@ type GraphQLGitHubRepositoryRef = { } } +type GraphQLPullRequest = { + readonly number: number + readonly headRefName: string + readonly baseRefName: string + readonly baseRefOid: string +} + export default class GitHubProjectDataSource implements IGitHubRepositoryDataSource { private readonly loginsDataSource: IGitHubLoginDataSource private readonly graphQlClient: IGitHubGraphQLClient @@ -99,9 +106,33 @@ export default class GitHubProjectDataSource implements IGitHubRepositoryDataSou return !alreadyAdded }) }) - .then(repositories => { + .then(async repositories => { + // Fetch PRs for all repositories in a single query + const allPullRequests = await this.getOpenPullRequestsForRepositories( + repositories.map(repo => ({ + owner: repo.owner.login, + name: repo.name + })) + ) + // Map from the internal model to the public model. return repositories.map(repository => { + const repoKey = `${repository.owner.login}/${repository.name}` + const pullRequests = allPullRequests.get(repoKey) || new Map() + + const branches = repository.branches.edges.map(branch => { + const pr = pullRequests.get(branch.node.name) + + return { + id: branch.node.target.oid, + name: branch.node.name, + baseRef: pr?.baseRefName, + baseRefOid: pr?.baseRefOid, + prNumber: pr?.number, + files: branch.node.target.tree.entries + } + }) + return { name: repository.name, owner: repository.owner.login, @@ -111,13 +142,7 @@ export default class GitHubProjectDataSource implements IGitHubRepositoryDataSou }, configYml: repository.configYml, configYaml: repository.configYaml, - branches: repository.branches.edges.map(branch => { - return { - id: branch.node.target.oid, - name: branch.node.name, - files: branch.node.target.tree.entries - } - }), + branches: branches, tags: repository.tags.edges.map(branch => { return { id: branch.node.target.oid, @@ -130,6 +155,69 @@ export default class GitHubProjectDataSource implements IGitHubRepositoryDataSou }) } + private async getOpenPullRequestsForRepositories( + repositories: Array<{ owner: string, name: string }> + ): Promise>> { + if (repositories.length === 0) { + return new Map() + } + + // Build a query that fetches PRs for all repositories + const repoQueries = repositories + .map((repo, index) => { + return ` + repo${index}: repository(owner: "${repo.owner}", name: "${repo.name}") { + pullRequests(first: 100, states: [OPEN]) { + edges { + node { + number + headRefName + baseRefName + baseRefOid + } + } + } + }` + }) + .join("\n") + + const request = { + query: ` + query PullRequests { + ${repoQueries} + } + `, + variables: {} + } + + const response = await this.graphQlClient.graphql(request) + const allPullRequests = new Map>() + + repositories.forEach((repo, index) => { + const repoKey = `${repo.owner}/${repo.name}` + const repoData = response[`repo${index}`] + const pullRequests = new Map() + + if (repoData?.pullRequests?.edges) { + const pullRequestEdges = repoData.pullRequests.edges as Edge[] + + pullRequestEdges.forEach(edge => { + const pr = edge.node + pullRequests.set(pr.headRefName, { + number: pr.number, + headRefName: pr.headRefName, + baseRefName: pr.baseRefName, + baseRefOid: pr.baseRefOid + }) + }) + } + + allPullRequests.set(repoKey, pullRequests) + }) + + return allPullRequests + } + private async getRepositoriesForSearchQuery(params: { searchQuery: string, cursor?: string diff --git a/src/features/projects/domain/IGitHubRepositoryDataSource.ts b/src/features/projects/domain/IGitHubRepositoryDataSource.ts index b48ff43e..eb331a95 100644 --- a/src/features/projects/domain/IGitHubRepositoryDataSource.ts +++ b/src/features/projects/domain/IGitHubRepositoryDataSource.ts @@ -17,7 +17,10 @@ export type GitHubRepository = { export type GitHubRepositoryRef = { readonly id: string - readonly name: string + readonly name: string + readonly baseRef?: string + readonly baseRefOid?: string + readonly prNumber?: number readonly files: { readonly name: string }[] diff --git a/src/features/projects/domain/OpenApiSpecification.ts b/src/features/projects/domain/OpenApiSpecification.ts index b0c3bfa5..fe154e37 100644 --- a/src/features/projects/domain/OpenApiSpecification.ts +++ b/src/features/projects/domain/OpenApiSpecification.ts @@ -5,6 +5,10 @@ export const OpenApiSpecificationSchema = z.object({ name: z.string(), url: z.string(), editURL: z.string().optional(), + diffURL: z.string().optional(), + diffBaseBranch: z.string().optional(), + diffBaseOid: z.string().optional(), + diffPrUrl: z.string().optional(), isDefault: z.boolean() }) diff --git a/src/features/projects/domain/ProjectNavigator.ts b/src/features/projects/domain/ProjectNavigator.ts index e3d03217..0adcd1e7 100644 --- a/src/features/projects/domain/ProjectNavigator.ts +++ b/src/features/projects/domain/ProjectNavigator.ts @@ -35,10 +35,12 @@ export default class ProjectNavigator { return e.name == preferredSpecificationName }) if (candidateSpecification) { - this.router.push(`/${project.owner}/${project.name}/${newVersion.id}/${candidateSpecification.id}`) + const encodedPath = this.encodePath(project.owner, project.name, newVersion.id, candidateSpecification.id) + this.router.push(encodedPath) } else { const defaultOrFirstSpecification = getDefaultSpecification(newVersion) - this.router.push(`/${project.owner}/${project.name}/${newVersion.id}/${defaultOrFirstSpecification.id}`) + const encodedPath = this.encodePath(project.owner, project.name, newVersion.id, defaultOrFirstSpecification.id) + this.router.push(encodedPath) } } @@ -48,9 +50,10 @@ export default class ProjectNavigator { versionId: string, specificationId: string ) { - this.router.push(`/${projectOwner}/${projectName}/${versionId}/${specificationId}`) + const encodedPath = this.encodePath(projectOwner, projectName, versionId, specificationId) + this.router.push(encodedPath) } - + navigateIfNeeded(selection: { projectOwner?: string projectName?: string @@ -60,9 +63,15 @@ export default class ProjectNavigator { if (!selection.projectOwner || !selection.projectName || !selection.versionId || !selection.specificationId) { return } - const path = `/${selection.projectOwner}/${selection.projectName}/${selection.versionId}/${selection.specificationId}` + const path = this.encodePath(selection.projectOwner, selection.projectName, selection.versionId, selection.specificationId) if (path !== this.pathnameReader.pathname) { this.router.replace(path) } } + + private encodePath(owner: string, projectName: string, versionId: string, specificationId: string): string { + const encodedVersionId = versionId.split('/').map(segment => encodeURIComponent(segment)).join('/') + const encodedSpecificationId = encodeURIComponent(specificationId) + return `/${owner}/${projectName}/${encodedVersionId}/${encodedSpecificationId}` + } } diff --git a/src/features/projects/domain/Version.ts b/src/features/projects/domain/Version.ts index f6b69989..48dbc4d0 100644 --- a/src/features/projects/domain/Version.ts +++ b/src/features/projects/domain/Version.ts @@ -6,7 +6,7 @@ export const VersionSchema = z.object({ name: z.string(), specifications: OpenApiSpecificationSchema.array(), url: z.string().optional(), - isDefault: z.boolean().default(false) + isDefault: z.boolean().default(false), }) type Version = z.infer diff --git a/src/features/projects/view/toolbar/TrailingToolbarItem.tsx b/src/features/projects/view/toolbar/TrailingToolbarItem.tsx index 4d74f06a..c4f42ea8 100644 --- a/src/features/projects/view/toolbar/TrailingToolbarItem.tsx +++ b/src/features/projects/view/toolbar/TrailingToolbarItem.tsx @@ -68,7 +68,7 @@ const TrailingToolbarItem = () => { } {specification.editURL && - + { } + ) diff --git a/src/features/sidebar/data/index.ts b/src/features/sidebar/data/index.ts index d151c029..c5c8a71b 100644 --- a/src/features/sidebar/data/index.ts +++ b/src/features/sidebar/data/index.ts @@ -1,2 +1,3 @@ export { default as useCloseSidebarOnSelection } from "./useCloseSidebarOnSelection" +export { default as useDiff } from "./useDiff" export { default as useSidebarOpen } from "./useSidebarOpen" diff --git a/src/features/sidebar/data/useDiff.ts b/src/features/sidebar/data/useDiff.ts new file mode 100644 index 00000000..49bc38ee --- /dev/null +++ b/src/features/sidebar/data/useDiff.ts @@ -0,0 +1,83 @@ +import { useState, useEffect } from "react" +import { useProjectSelection } from "@/features/projects/data" +import { DiffChange } from "../../diff/domain/DiffChange" + +interface DiffData { + changes: DiffChange[] + error?: string | null + isNewFile?: boolean +} + +export default function useDiff() { + const { specification } = useProjectSelection() + const [data, setData] = useState(null) + const [loading, setLoading] = useState(false) + const [error, setError] = useState(null) + const diffUrl = specification?.diffURL + + useEffect(() => { + if (!diffUrl) { + return + } + + let isCancelled = false + + const fetchDiff = async () => { + if (isCancelled) { + return + } + + setLoading(true) + setError(null) + setData(null) + + try { + const res = await fetch(diffUrl) + const result = await res.json() + + if (isCancelled) { + return + } + + if (result.error) { + setData(null) + setError(result.error) + } else { + setData(result) + setError(null) + } + setLoading(false) + } catch (err) { + if (isCancelled) { + return + } + + console.error("Failed to fetch diff:", err) + setData(null) + setError("We couldn't load the diff right now. Please try again later.") + setLoading(false) + } + } + + fetchDiff() + + return () => { + isCancelled = true + } + }, [diffUrl]) + + const hasDiffUrl = Boolean(diffUrl) + const resolvedData = hasDiffUrl ? data : { changes: [] } + const resolvedChanges = resolvedData?.changes ?? [] + const resolvedLoading = hasDiffUrl ? loading : false + const resolvedError = hasDiffUrl ? error : null + const isNewFile = resolvedData?.isNewFile ?? false + + return { + data: resolvedData, + loading: resolvedLoading, + changes: resolvedChanges, + error: resolvedError, + isNewFile + } +} diff --git a/src/features/sidebar/data/useDiffbarOpen.ts b/src/features/sidebar/data/useDiffbarOpen.ts new file mode 100644 index 00000000..964efd8c --- /dev/null +++ b/src/features/sidebar/data/useDiffbarOpen.ts @@ -0,0 +1,5 @@ +import { useSessionStorage } from "usehooks-ts" + +export default function useDiffbarOpen() { + return useSessionStorage("isDiffbarOpen", false, { initializeWithValue: false }) +} \ No newline at end of file diff --git a/src/features/sidebar/data/useSidebarOpen.ts b/src/features/sidebar/data/useSidebarOpen.ts index 3d4c1be7..1a8dc151 100644 --- a/src/features/sidebar/data/useSidebarOpen.ts +++ b/src/features/sidebar/data/useSidebarOpen.ts @@ -1,5 +1,5 @@ import { useSessionStorage } from "usehooks-ts" export default function useSidebarOpen() { - return useSessionStorage("isSidebarOpen", true) + return useSessionStorage("isSidebarOpen", true, { initializeWithValue: false }) } \ No newline at end of file diff --git a/src/features/sidebar/view/SecondarySplitHeader.tsx b/src/features/sidebar/view/SecondarySplitHeader.tsx index 95599c3e..870bae8b 100644 --- a/src/features/sidebar/view/SecondarySplitHeader.tsx +++ b/src/features/sidebar/view/SecondarySplitHeader.tsx @@ -2,12 +2,16 @@ import { useState, useEffect, useContext } from "react" import { useSessionStorage } from "usehooks-ts" -import { Box, IconButton, Stack, Tooltip, Collapse } from "@mui/material" +import { Box, IconButton, Stack, Tooltip, Collapse, Divider } from "@mui/material" import { FontAwesomeIcon } from "@fortawesome/react-fontawesome" -import { faBars, faChevronLeft } from "@fortawesome/free-solid-svg-icons" +import { faBars, faChevronLeft, faChevronRight, faArrowRightArrowLeft } from "@fortawesome/free-solid-svg-icons" import { isMac as checkIsMac, SidebarTogglableContext } from "@/common" import { useSidebarOpen } from "@/features/sidebar/data" +import useDiffbarOpen from "@/features/sidebar/data/useDiffbarOpen" import ToggleMobileToolbarButton from "./internal/secondary/ToggleMobileToolbarButton" +import { useProjectSelection } from "@/features/projects/data" + +const isDiffFeatureEnabled = process.env.NEXT_PUBLIC_ENABLE_DIFF_SIDEBAR === "true" const SecondarySplitHeader = ({ mobileToolbar, @@ -17,7 +21,9 @@ const SecondarySplitHeader = ({ children?: React.ReactNode }) => { const [isSidebarOpen, setSidebarOpen] = useSidebarOpen() + const [isDiffbarOpen, setDiffbarOpen] = useDiffbarOpen() const [isMobileToolbarVisible, setMobileToolbarVisible] = useSessionStorage("isMobileToolbarVisible", true) + const { specification } = useProjectSelection() return ( - - + + {children} - {mobileToolbar && + + {mobileToolbar && ( setMobileToolbarVisible(!isMobileToolbarVisible) } /> - } + )} + {isDiffFeatureEnabled && ( + + )} - {mobileToolbar && + {mobileToolbar && ( - } + )} ) } @@ -78,7 +92,7 @@ const ToggleSidebarButton = ({ }, [setIsMac]) const isSidebarTogglable = useContext(SidebarTogglableContext) const openCloseKeyboardShortcut = `(${isMac ? "⌘" : "^"} + .)` - const tooltip = isSidebarOpen ? "Show Projects" : "Hide Projects" + const tooltip = isSidebarOpen ? "Hide Projects" : "Show Projects" return ( @@ -98,3 +112,52 @@ const ToggleSidebarButton = ({ ) } + +const ToggleDiffButton = ({ + isDiffbarOpen, + onClick, + isDiffAvailable +}: { + isDiffbarOpen: boolean, + onClick: (isDiffbarOpen: boolean) => void, + isDiffAvailable: boolean +}) => { + const [isMac, setIsMac] = useState(false) + useEffect(() => { + // checkIsMac uses window so we delay the check. + const timeout = window.setTimeout(() => { + setIsMac(checkIsMac()) + }, 0) + return () => window.clearTimeout(timeout) + }, []) + const isSidebarTogglable = useContext(SidebarTogglableContext) + const openCloseKeyboardShortcut = `(${isMac ? "⌘" : "^"} + K)` + const isDisabled = !isDiffAvailable && !isDiffbarOpen + const tooltip = isDisabled + ? "Changes cannot be displayed" + : isDiffbarOpen + ? "Hide changes" + : "Show changes" + return ( + + + + + onClick(!isDiffbarOpen)} + edge="end" + disabled={isDisabled} + > + + + + + + ) +} diff --git a/src/features/sidebar/view/SplitView.tsx b/src/features/sidebar/view/SplitView.tsx index 04bd4eb9..c6d100c0 100644 --- a/src/features/sidebar/view/SplitView.tsx +++ b/src/features/sidebar/view/SplitView.tsx @@ -1,6 +1,7 @@ import ClientSplitView from "./internal/ClientSplitView" import BaseSidebar from "./internal/sidebar/Sidebar" import ProjectList from "./internal/sidebar/projects/ProjectList" +import DiffContent from "./internal/diffbar/DiffContent" import { env } from "@/common" const SITE_NAME = env.getOrThrow("FRAMNA_DOCS_TITLE") @@ -8,7 +9,7 @@ const HELP_URL = env.get("FRAMNA_DOCS_HELP_URL") const SplitView = ({ children }: { children?: React.ReactNode }) => { return ( - }> + } sidebarRight={}> {children} ) diff --git a/src/features/sidebar/view/internal/ClientSplitView.tsx b/src/features/sidebar/view/internal/ClientSplitView.tsx index 38c6735f..dbda81e6 100644 --- a/src/features/sidebar/view/internal/ClientSplitView.tsx +++ b/src/features/sidebar/view/internal/ClientSplitView.tsx @@ -4,17 +4,26 @@ import { useEffect, useContext } from "react" import { Stack, useMediaQuery, useTheme } from "@mui/material" import { isMac, useKeyboardShortcut, SidebarTogglableContext } from "@/common" import { useSidebarOpen } from "../../data" +import useDiffbarOpen from "../../data/useDiffbarOpen" +import { useProjectSelection } from "@/features/projects/data" import PrimaryContainer from "./primary/Container" import SecondaryContainer from "./secondary/Container" +import RightContainer from "./tertiary/RightContainer" + +const isDiffFeatureEnabled = process.env.NEXT_PUBLIC_ENABLE_DIFF_SIDEBAR === "true" const ClientSplitView = ({ sidebar, - children + children, + sidebarRight }: { sidebar: React.ReactNode children?: React.ReactNode + sidebarRight?: React.ReactNode }) => { const [isSidebarOpen, setSidebarOpen] = useSidebarOpen() + const [isRightSidebarOpen, setRightSidebarOpen] = useDiffbarOpen() + const { specification } = useProjectSelection() const isSidebarTogglable = useContext(SidebarTogglableContext) const theme = useTheme() // Determine if the screen size is small or larger @@ -25,6 +34,13 @@ const ClientSplitView = ({ setSidebarOpen(true) } }, [isSidebarOpen, isSidebarTogglable, setSidebarOpen]) + + // Close diff sidebar if no specification is selected + useEffect(() => { + if (!specification && isRightSidebarOpen) { + setRightSidebarOpen(false) + } + }, [specification, isRightSidebarOpen, setRightSidebarOpen]) useKeyboardShortcut(event => { const isActionKey = isMac() ? event.metaKey : event.ctrlKey if (isActionKey && event.key === ".") { @@ -34,7 +50,17 @@ const ClientSplitView = ({ } } }, [isSidebarTogglable, setSidebarOpen]) + + useKeyboardShortcut(event => { + const isActionKey = isMac() ? event.metaKey : event.ctrlKey + if (isDiffFeatureEnabled && isActionKey && event.key === "k") { + event.preventDefault() + setRightSidebarOpen(!isRightSidebarOpen) + } + }, [isRightSidebarOpen, setRightSidebarOpen]) + const sidebarWidth = 320 + const diffWidth = 320 return ( @@ -45,9 +71,16 @@ const ClientSplitView = ({ > {sidebar} - + {children} + setRightSidebarOpen(false)} + > + {sidebarRight} + ) } diff --git a/src/features/sidebar/view/internal/diffbar/DiffContent.tsx b/src/features/sidebar/view/internal/diffbar/DiffContent.tsx new file mode 100644 index 00000000..c07009b9 --- /dev/null +++ b/src/features/sidebar/view/internal/diffbar/DiffContent.tsx @@ -0,0 +1,119 @@ +"use client" + +import { Alert, Box, Typography, Link } from "@mui/material" +import { useState } from "react" +import useDiff from "@/features/sidebar/data/useDiff" +import { useProjectSelection } from "@/features/projects/data" +import DiffList, { DiffListStatus } from "./components/DiffList" +import DiffDialog from "./components/DiffDialog" + +const DiffContent = () => { + const { data, loading, changes, error, isNewFile } = useDiff() + const { specification } = useProjectSelection() + const [selectedChange, setSelectedChange] = useState(null) + + const closeModal = () => setSelectedChange(null) + + const hasData = Boolean(data) + const hasChanges = changes.length > 0 + const diffStatus: DiffListStatus = loading + ? "loading" + : error + ? "error" + : isNewFile + ? "empty" + : hasData && hasChanges + ? "ready" + : hasData + ? "empty" + : "idle" + + return ( + + + What has changed? + + + {specification?.diffBaseBranch && specification?.diffBaseOid && ( + + Comparing to:{" "} + {specification.diffPrUrl ? ( + + {specification.diffBaseBranch} ({specification.diffBaseOid.substring(0, 7)}) + + ) : ( + `${specification.diffBaseBranch} (${specification.diffBaseOid.substring(0, 7)})` + )} + + )} + + {isNewFile && ( + + + This is a new file that doesn't exist on the base branch. + + + )} + + {error ? ( + + {error} + + ) : null} + + {!isNewFile && ( + + setSelectedChange(i)} + /> + + )} + + + + ) +} + +export default DiffContent diff --git a/src/features/sidebar/view/internal/diffbar/components/DiffDialog.tsx b/src/features/sidebar/view/internal/diffbar/components/DiffDialog.tsx new file mode 100644 index 00000000..4e4820a6 --- /dev/null +++ b/src/features/sidebar/view/internal/diffbar/components/DiffDialog.tsx @@ -0,0 +1,120 @@ +"use client" + +import React from "react" +import { + Dialog, + DialogTitle, + DialogContent, + DialogActions, + Button, + Box, + Typography, +} from "@mui/material" +import { softPaperSx } from "@/common/theme/theme" +import MonoQuotedText from "./MonoQuotedText" +import { getLevelConfig, Level } from "./levelConfig" + +interface ChangeDetails { + path?: string + text?: string | React.ReactNode + level?: number + operation?: string +} + +const DiffDialog = ({ + open, + change, + onClose, +}: { + open: boolean + change: ChangeDetails | null + onClose: () => void +}) => { + const levelConfig = getLevelConfig((change?.level ?? 1) as Level) + + return ( + theme.palette.background.default, + }, + }, + }} + > + Change Details + + + + + {levelConfig.label} + + {change?.operation && change?.path && ( + + at{" "} + + {change.operation} + {" "} + + {change.path} + + + )} + {!change?.operation && change?.path && ( + + {change.path} + + )} + + + {change?.text && ( + + + {typeof change.text === "string" ? ( + + ) : ( + change.text + )} + + + )} + + + + + + ) +} + +export default DiffDialog diff --git a/src/features/sidebar/view/internal/diffbar/components/DiffList.tsx b/src/features/sidebar/view/internal/diffbar/components/DiffList.tsx new file mode 100644 index 00000000..ef37bfd1 --- /dev/null +++ b/src/features/sidebar/view/internal/diffbar/components/DiffList.tsx @@ -0,0 +1,49 @@ +"use client" + +import { Box, Typography } from "@mui/material" +import PopulatedDiffList from "./PopulatedDiffList" +import { DiffChange } from "@/features/diff/domain/DiffChange" + +export type DiffListStatus = "idle" | "loading" | "empty" | "ready" | "error" + +const DiffList = ({ + changes, + status, + selectedChange, + onClick, +}: { + changes: DiffChange[] + status: DiffListStatus + selectedChange: number | null + onClick: (i: number) => void +}) => { + if (status === "loading") { + return ( + + + Loading changes... + + + ) + } else if (status === "empty") { + return ( + + + No changes + + + ) + } else if (status === "ready") { + return ( + + ) + } + + return null +} + +export default DiffList diff --git a/src/features/sidebar/view/internal/diffbar/components/DiffListItem.tsx b/src/features/sidebar/view/internal/diffbar/components/DiffListItem.tsx new file mode 100644 index 00000000..1c81810b --- /dev/null +++ b/src/features/sidebar/view/internal/diffbar/components/DiffListItem.tsx @@ -0,0 +1,108 @@ +"use client" + +import { Box, Typography, ListItem, ListItemButton, Stack } from "@mui/material" +import MenuItemHover from "@/common/ui/MenuItemHover" +import MonoQuotedText from "./MonoQuotedText" +import { getLevelConfig, Level } from "./levelConfig" + +const DiffListItem = ({ + path, + text, + level, + operation, + selected, + onClick, +}: { + path?: string + text?: string + level?: number + operation?: string + selected: boolean + onClick: () => void +}) => { + const levelConfig = getLevelConfig((level ?? 1) as Level) + + return ( + + + + + + + + {levelConfig.label} + + {operation && path && ( + + at{" "} + + {operation} + {" "} + + {path} + + + )} + {!operation && path && ( + + {path} + + )} + + {text && ( + + + + )} + + + + + + ) +} + +export default DiffListItem diff --git a/src/features/sidebar/view/internal/diffbar/components/MonoQuotedText.tsx b/src/features/sidebar/view/internal/diffbar/components/MonoQuotedText.tsx new file mode 100644 index 00000000..3bf0fb41 --- /dev/null +++ b/src/features/sidebar/view/internal/diffbar/components/MonoQuotedText.tsx @@ -0,0 +1,29 @@ +"use client" + +import { Box } from "@mui/material" + +const MonoQuotedText = ({ text }: { text: string }) => { + return ( + <> + {text.split(/(['`])([^'`]+)\1/g).map((part, i) => + i % 3 === 2 ? ( + + {part} + + ) : i % 3 === 1 ? null : ( + part + ) + )} + + ) +} + +export default MonoQuotedText diff --git a/src/features/sidebar/view/internal/diffbar/components/PopulatedDiffList.tsx b/src/features/sidebar/view/internal/diffbar/components/PopulatedDiffList.tsx new file mode 100644 index 00000000..14a04ef8 --- /dev/null +++ b/src/features/sidebar/view/internal/diffbar/components/PopulatedDiffList.tsx @@ -0,0 +1,39 @@ +"use client" + +import SpacedList from "@/common/ui/SpacedList" +import DiffListItem from "./DiffListItem" +import { DiffChange } from "@/features/diff/domain/DiffChange" + +const PopulatedDiffList = ({ + changes, + selectedChange, + onClick, +}: { + changes: DiffChange[] + selectedChange: number | null + onClick: (i: number) => void +}) => { + return ( + + {changes.map((change, i) => ( + onClick(i)} + /> + ))} + + ) +} + +export default PopulatedDiffList diff --git a/src/features/sidebar/view/internal/diffbar/components/levelConfig.ts b/src/features/sidebar/view/internal/diffbar/components/levelConfig.ts new file mode 100644 index 00000000..01b4e504 --- /dev/null +++ b/src/features/sidebar/view/internal/diffbar/components/levelConfig.ts @@ -0,0 +1,13 @@ +export type Level = 1 | 2 | 3 + +export const getLevelConfig = (level: Level) => { + switch (level) { + case 3: + return { label: "breaking", color: "#e88388" } + case 2: + return { label: "warn", color: "#dbab79" } + case 1: + default: + return { label: "info", color: "#66c2cd" } + } +} diff --git a/src/features/sidebar/view/internal/secondary/Container.tsx b/src/features/sidebar/view/internal/secondary/Container.tsx index 29f2b213..6a3a9ead 100644 --- a/src/features/sidebar/view/internal/secondary/Container.tsx +++ b/src/features/sidebar/view/internal/secondary/Container.tsx @@ -6,11 +6,15 @@ import CustomTopLoader from "@/common/ui/CustomTopLoader" const SecondaryContainer = ({ sidebarWidth, offsetContent, + diffWidth, + offsetDiffContent, children, isSM, }: { sidebarWidth: number offsetContent: boolean + diffWidth?: number + offsetDiffContent?: boolean children?: React.ReactNode, isSM: boolean, }) => { @@ -21,6 +25,8 @@ const SecondaryContainer = ({ sidebarWidth={isSM ? sidebarWidth : 0} isSidebarOpen={isSM ? offsetContent: false} + diffWidth={isSM ? (diffWidth || 0) : 0} + isDiffOpen={isSM ? (offsetDiffContent || false) : false} sx={{ ...sx }} > {children} @@ -35,33 +41,41 @@ export default SecondaryContainer interface WrapperStackProps { readonly sidebarWidth: number readonly isSidebarOpen: boolean + readonly diffWidth: number + readonly isDiffOpen: boolean } const WrapperStack = styled(Stack, { - shouldForwardProp: (prop) => prop !== "isSidebarOpen" && prop !== "sidebarWidth" -})(({ theme, sidebarWidth, isSidebarOpen }) => ({ - transition: theme.transitions.create("margin", { - easing: theme.transitions.easing.sharp, - duration: theme.transitions.duration.leavingScreen - }), - marginLeft: `-${sidebarWidth}px`, - ...(isSidebarOpen && { - transition: theme.transitions.create("margin", { - easing: theme.transitions.easing.easeOut, - duration: theme.transitions.duration.enteringScreen, + shouldForwardProp: (prop) => prop !== "isSidebarOpen" && prop !== "sidebarWidth" && prop !== "diffWidth" && prop !== "isDiffOpen" +})(({ theme, sidebarWidth, isSidebarOpen, diffWidth, isDiffOpen }) => { + return { + transition: theme.transitions.create(["margin", "width"], { + easing: theme.transitions.easing.sharp, + duration: theme.transitions.duration.leavingScreen }), - marginLeft: 0 - }) -})) + marginLeft: isSidebarOpen ? 0 : `-${sidebarWidth}px`, + marginRight: isDiffOpen ? 0 : `-${diffWidth}px`, + ...((isSidebarOpen || isDiffOpen) && { + transition: theme.transitions.create(["margin", "width"], { + easing: theme.transitions.easing.easeOut, + duration: theme.transitions.duration.enteringScreen, + }), + }), + }; +}) const InnerSecondaryContainer = ({ sidebarWidth, isSidebarOpen, + diffWidth, + isDiffOpen, children, sx }: { sidebarWidth: number isSidebarOpen: boolean + diffWidth: number + isDiffOpen: boolean children: React.ReactNode sx?: SxProps }) => { @@ -71,6 +85,8 @@ const InnerSecondaryContainer = ({ spacing={0} sidebarWidth={sidebarWidth} isSidebarOpen={isSidebarOpen} + diffWidth={diffWidth} + isDiffOpen={isDiffOpen} sx={{ ...sx, width: "100%", overflowY: "auto" }} > diff --git a/src/features/sidebar/view/internal/tertiary/RightContainer.tsx b/src/features/sidebar/view/internal/tertiary/RightContainer.tsx new file mode 100644 index 00000000..f48f7adb --- /dev/null +++ b/src/features/sidebar/view/internal/tertiary/RightContainer.tsx @@ -0,0 +1,87 @@ +'use client' + +import { SxProps } from "@mui/system" +import { Drawer as MuiDrawer } from "@mui/material" +import { useTheme } from "@mui/material/styles" + +const RightContainer = ({ + width, + isOpen, + onClose, + children +}: { + width: number + isOpen: boolean + onClose?: () => void + children?: React.ReactNode +}) => { + return ( + <> + + {children} + + + {children} + + + ) +} + +export default RightContainer + +const InnerRightContainer = ({ + variant, + width, + isOpen, + onClose, + keepMounted, + sx, + children +}: { + variant: "persistent" | "temporary" + width: number + isOpen: boolean + onClose?: () => void + keepMounted?: boolean + sx: SxProps + children?: React.ReactNode +}) => { + const theme = useTheme() + return ( + + {children} + + ) +} \ No newline at end of file From fa9046b6ed4afdfd7e8d7addeb678d6a61eeef2c Mon Sep 17 00:00:00 2001 From: Ulrik Andersen Date: Thu, 11 Dec 2025 11:23:21 +0100 Subject: [PATCH 02/15] Add scroll-to-change navigation from diff sidebar (#634) * Add scroll-to-change navigation from diff sidebar Clicking on a change in the diff sidebar now scrolls to that operation in the documentation viewer. Supports all three visualizers: - SwaggerUI: DOM-based scrolling with operation expansion - Stoplight: Hash-based navigation - Redocly: Hash set on iframe Also removes unused DiffDialog component. * refactor: remove unused hasChanges property from Selector items * fix: prevent SwaggerUI panel from closing when clicking sidebar item Check is-open class on the block element itself rather than a child .opblock element, since SwaggerUI applies the class directly to the operations-{tag}-{operationId} element. * refactor: simplify scrollToSwaggerOperation with Array.find --- src/features/docs/navigation/index.ts | 1 + .../docs/navigation/scrollToOperation.ts | 81 ++++++++++++ .../projects/view/toolbar/MobileToolbar.tsx | 5 +- .../view/toolbar/TrailingToolbarItem.tsx | 5 +- .../view/internal/diffbar/DiffContent.tsx | 20 ++- .../diffbar/components/DiffDialog.tsx | 120 ------------------ .../internal/diffbar/components/DiffList.tsx | 5 +- .../diffbar/components/DiffListItem.tsx | 3 - .../diffbar/components/PopulatedDiffList.tsx | 9 +- 9 files changed, 102 insertions(+), 147 deletions(-) create mode 100644 src/features/docs/navigation/index.ts create mode 100644 src/features/docs/navigation/scrollToOperation.ts delete mode 100644 src/features/sidebar/view/internal/diffbar/components/DiffDialog.tsx diff --git a/src/features/docs/navigation/index.ts b/src/features/docs/navigation/index.ts new file mode 100644 index 00000000..4a871967 --- /dev/null +++ b/src/features/docs/navigation/index.ts @@ -0,0 +1 @@ +export { scrollToOperation } from "./scrollToOperation" diff --git a/src/features/docs/navigation/scrollToOperation.ts b/src/features/docs/navigation/scrollToOperation.ts new file mode 100644 index 00000000..26d2957d --- /dev/null +++ b/src/features/docs/navigation/scrollToOperation.ts @@ -0,0 +1,81 @@ +import { DocumentationVisualizer } from "@/features/settings/domain" + +/** + * Finds and scrolls to a SwaggerUI operation element. + * SwaggerUI elements have IDs in the format: operations-{tag}-{operationId} + * Since we may not know the tag, we search for elements containing the operationId. + */ +function scrollToSwaggerOperation(operationId: string): boolean { + const block = Array.from(document.querySelectorAll('[id^="operations-"]')) + .find(el => el.id.endsWith(`-${operationId}`)) + + if (!block) return false + + block.scrollIntoView({ behavior: "smooth", block: "start" }) + + // Only expand if not already open (SwaggerUI adds is-open class to the block itself) + if (!block.classList.contains("is-open")) { + const button = block.querySelector(".opblock-summary-control") + if (button instanceof HTMLElement) { + button.click() + } + } + + return true +} + +/** + * Scrolls to an operation in Redocly by setting the hash on the iframe. + * Redocly uses hash format: #operation/{operationId} + */ +function scrollToRedoclyOperation(operationId: string): void { + const iframe = document.querySelector("iframe") + if (!iframe?.contentWindow) { + return + } + iframe.contentWindow.location.hash = `operation/${operationId}` +} + +/** + * Scrolls to an operation in the documentation viewer. + * Each visualizer has its own mechanism for deep linking. + * + * For SwaggerUI: Uses DOM-based scrolling to find operations-{tag}-{operationId} elements + * For Stoplight: #/operations/{operationId} + * For Redocly: #operation/{operationId} (set on iframe) + */ +export function scrollToOperation( + visualizer: DocumentationVisualizer, + operationId?: string, + method?: string, + path?: string +): void { + if (!operationId && (!method || !path)) { + return + } + + switch (visualizer) { + case DocumentationVisualizer.SWAGGER: + // SwaggerUI: Use DOM-based scrolling since hash changes don't trigger navigation + // after initial page load + if (operationId) { + scrollToSwaggerOperation(operationId) + } + break + + case DocumentationVisualizer.STOPLIGHT: + // Stoplight uses hash-based navigation: #/operations/{operationId} + if (operationId) { + window.location.hash = `/operations/${operationId}` + } + break + + case DocumentationVisualizer.REDOCLY: + // Redocly runs in an iframe and uses hash format: #tag/{tag}/operation/{operationId} + // We need to set the hash on the iframe's content window + if (operationId) { + scrollToRedoclyOperation(operationId) + } + break + } +} diff --git a/src/features/projects/view/toolbar/MobileToolbar.tsx b/src/features/projects/view/toolbar/MobileToolbar.tsx index 730ad7c7..16fbd655 100644 --- a/src/features/projects/view/toolbar/MobileToolbar.tsx +++ b/src/features/projects/view/toolbar/MobileToolbar.tsx @@ -28,7 +28,10 @@ const MobileToolbar = () => { sx={{ width: "100%" }} /> ({ + id: spec.id, + name: spec.name + }))} selection={specification.id} onSelect={selectSpecification} sx={{ width: "100%" }} diff --git a/src/features/projects/view/toolbar/TrailingToolbarItem.tsx b/src/features/projects/view/toolbar/TrailingToolbarItem.tsx index c4f42ea8..fe6dce34 100644 --- a/src/features/projects/view/toolbar/TrailingToolbarItem.tsx +++ b/src/features/projects/view/toolbar/TrailingToolbarItem.tsx @@ -59,7 +59,10 @@ const TrailingToolbarItem = () => { /> / ({ + id: spec.id, + name: spec.name + }))} selection={specification.id} onSelect={selectSpecification} sx={{ marginRight: 0.5 }} diff --git a/src/features/sidebar/view/internal/diffbar/DiffContent.tsx b/src/features/sidebar/view/internal/diffbar/DiffContent.tsx index c07009b9..b0f1aa24 100644 --- a/src/features/sidebar/view/internal/diffbar/DiffContent.tsx +++ b/src/features/sidebar/view/internal/diffbar/DiffContent.tsx @@ -1,18 +1,21 @@ "use client" import { Alert, Box, Typography, Link } from "@mui/material" -import { useState } from "react" import useDiff from "@/features/sidebar/data/useDiff" import { useProjectSelection } from "@/features/projects/data" +import useDocumentationVisualizer from "@/features/settings/data/useDocumentationVisualizer" +import { scrollToOperation } from "@/features/docs/navigation" import DiffList, { DiffListStatus } from "./components/DiffList" -import DiffDialog from "./components/DiffDialog" +import { DiffChange } from "@/features/diff/domain/DiffChange" const DiffContent = () => { const { data, loading, changes, error, isNewFile } = useDiff() const { specification } = useProjectSelection() - const [selectedChange, setSelectedChange] = useState(null) + const [visualizer] = useDocumentationVisualizer() - const closeModal = () => setSelectedChange(null) + const handleChangeClick = (change: DiffChange) => { + scrollToOperation(visualizer, change.operationId, change.operation, change.path) + } const hasData = Boolean(data) const hasChanges = changes.length > 0 @@ -101,17 +104,10 @@ const DiffContent = () => { setSelectedChange(i)} + onClick={handleChangeClick} /> )} - - ) } diff --git a/src/features/sidebar/view/internal/diffbar/components/DiffDialog.tsx b/src/features/sidebar/view/internal/diffbar/components/DiffDialog.tsx deleted file mode 100644 index 4e4820a6..00000000 --- a/src/features/sidebar/view/internal/diffbar/components/DiffDialog.tsx +++ /dev/null @@ -1,120 +0,0 @@ -"use client" - -import React from "react" -import { - Dialog, - DialogTitle, - DialogContent, - DialogActions, - Button, - Box, - Typography, -} from "@mui/material" -import { softPaperSx } from "@/common/theme/theme" -import MonoQuotedText from "./MonoQuotedText" -import { getLevelConfig, Level } from "./levelConfig" - -interface ChangeDetails { - path?: string - text?: string | React.ReactNode - level?: number - operation?: string -} - -const DiffDialog = ({ - open, - change, - onClose, -}: { - open: boolean - change: ChangeDetails | null - onClose: () => void -}) => { - const levelConfig = getLevelConfig((change?.level ?? 1) as Level) - - return ( - theme.palette.background.default, - }, - }, - }} - > - Change Details - - - - - {levelConfig.label} - - {change?.operation && change?.path && ( - - at{" "} - - {change.operation} - {" "} - - {change.path} - - - )} - {!change?.operation && change?.path && ( - - {change.path} - - )} - - - {change?.text && ( - - - {typeof change.text === "string" ? ( - - ) : ( - change.text - )} - - - )} - - - - - - ) -} - -export default DiffDialog diff --git a/src/features/sidebar/view/internal/diffbar/components/DiffList.tsx b/src/features/sidebar/view/internal/diffbar/components/DiffList.tsx index ef37bfd1..0a0606e2 100644 --- a/src/features/sidebar/view/internal/diffbar/components/DiffList.tsx +++ b/src/features/sidebar/view/internal/diffbar/components/DiffList.tsx @@ -9,13 +9,11 @@ export type DiffListStatus = "idle" | "loading" | "empty" | "ready" | "error" const DiffList = ({ changes, status, - selectedChange, onClick, }: { changes: DiffChange[] status: DiffListStatus - selectedChange: number | null - onClick: (i: number) => void + onClick: (change: DiffChange) => void }) => { if (status === "loading") { return ( @@ -37,7 +35,6 @@ const DiffList = ({ return ( ) diff --git a/src/features/sidebar/view/internal/diffbar/components/DiffListItem.tsx b/src/features/sidebar/view/internal/diffbar/components/DiffListItem.tsx index 1c81810b..951cf250 100644 --- a/src/features/sidebar/view/internal/diffbar/components/DiffListItem.tsx +++ b/src/features/sidebar/view/internal/diffbar/components/DiffListItem.tsx @@ -10,14 +10,12 @@ const DiffListItem = ({ text, level, operation, - selected, onClick, }: { path?: string text?: string level?: number operation?: string - selected: boolean onClick: () => void }) => { const levelConfig = getLevelConfig((level ?? 1) as Level) @@ -25,7 +23,6 @@ const DiffListItem = ({ return ( void + onClick: (change: DiffChange) => void }) => { return ( - {changes.map((change, i) => ( + {changes.map((change) => ( onClick(i)} + onClick={() => onClick(change)} /> ))} From fbf2e221ec0d8837267512c9aef88a4229552d36 Mon Sep 17 00:00:00 2001 From: Ulrik Andersen Date: Thu, 11 Dec 2025 11:29:57 +0100 Subject: [PATCH 03/15] Add has-changes indicator for specs in PR branches (#633) Show a visual indicator (orange dot with tooltip) on specs that have been modified in the current PR. Only specs whose filenames appear in the PR's changed files list will display the indicator. - Fetch changed files from PR via GraphQL - Add changedFiles to GitHubRepositoryRef type - Only set diffURL on specs in changedFiles - Display subtle orange dot with "Has changes" tooltip --- .../projects/data/GitHubProjectDataSource.ts | 11 +++--- .../data/GitHubRepositoryDataSource.ts | 24 +++++++++++-- .../domain/IGitHubRepositoryDataSource.ts | 5 +-- .../projects/view/toolbar/Selector.tsx | 35 ++++++++++++++----- 4 files changed, 55 insertions(+), 20 deletions(-) diff --git a/src/features/projects/data/GitHubProjectDataSource.ts b/src/features/projects/data/GitHubProjectDataSource.ts index f8e1f8d8..4762ed3e 100644 --- a/src/features/projects/data/GitHubProjectDataSource.ts +++ b/src/features/projects/data/GitHubProjectDataSource.ts @@ -122,6 +122,7 @@ export default class GitHubProjectDataSource implements IProjectDataSource { const specifications = ref.files.filter(file => { return this.isOpenAPISpecification(file.name) }).map(file => { + const isFileChanged = ref.changedFiles?.includes(file.name) ?? false return { id: file.name, name: file.name, @@ -132,16 +133,16 @@ export default class GitHubProjectDataSource implements IProjectDataSource { ref: ref.id }), editURL: `https://github.com/${ownerName}/${repositoryName}/edit/${ref.name}/${encodeURIComponent(file.name)}`, - diffURL: this.getGitHubDiffURL({ + diffURL: isFileChanged ? this.getGitHubDiffURL({ ownerName, repositoryName, path: file.name, baseRefOid: ref.baseRefOid, headRefOid: ref.id - }), - diffBaseBranch: ref.baseRef, - diffBaseOid: ref.baseRefOid, - diffPrUrl: ref.prNumber ? `https://github.com/${ownerName}/${repositoryName}/pull/${ref.prNumber}` : undefined, + }) : undefined, + diffBaseBranch: isFileChanged ? ref.baseRef : undefined, + diffBaseOid: isFileChanged ? ref.baseRefOid : undefined, + diffPrUrl: isFileChanged && ref.prNumber ? `https://github.com/${ownerName}/${repositoryName}/pull/${ref.prNumber}` : undefined, isDefault: false // initial value } }).sort((a, b) => a.name.localeCompare(b.name)) diff --git a/src/features/projects/data/GitHubRepositoryDataSource.ts b/src/features/projects/data/GitHubRepositoryDataSource.ts index c107b506..6a776e34 100644 --- a/src/features/projects/data/GitHubRepositoryDataSource.ts +++ b/src/features/projects/data/GitHubRepositoryDataSource.ts @@ -51,6 +51,7 @@ type GraphQLPullRequest = { readonly headRefName: string readonly baseRefName: string readonly baseRefOid: string + readonly changedFiles: string[] } export default class GitHubProjectDataSource implements IGitHubRepositoryDataSource { @@ -129,7 +130,8 @@ export default class GitHubProjectDataSource implements IGitHubRepositoryDataSou baseRef: pr?.baseRefName, baseRefOid: pr?.baseRefOid, prNumber: pr?.number, - files: branch.node.target.tree.entries + files: branch.node.target.tree.entries, + changedFiles: pr?.changedFiles } }) @@ -174,6 +176,11 @@ export default class GitHubProjectDataSource implements IGitHubRepositoryDataSou headRefName baseRefName baseRefOid + files(first: 100) { + nodes { + path + } + } } } } @@ -199,15 +206,26 @@ export default class GitHubProjectDataSource implements IGitHubRepositoryDataSou const pullRequests = new Map() if (repoData?.pullRequests?.edges) { - const pullRequestEdges = repoData.pullRequests.edges as Edge[] + type RawGraphQLPullRequest = { + number: number + headRefName: string + baseRefName: string + baseRefOid: string + files?: { + nodes?: { path: string }[] + } + } + const pullRequestEdges = repoData.pullRequests.edges as Edge[] pullRequestEdges.forEach(edge => { const pr = edge.node + const changedFiles = pr.files?.nodes?.map(f => f.path) || [] pullRequests.set(pr.headRefName, { number: pr.number, headRefName: pr.headRefName, baseRefName: pr.baseRefName, - baseRefOid: pr.baseRefOid + baseRefOid: pr.baseRefOid, + changedFiles }) }) } diff --git a/src/features/projects/domain/IGitHubRepositoryDataSource.ts b/src/features/projects/domain/IGitHubRepositoryDataSource.ts index eb331a95..c9c86e4e 100644 --- a/src/features/projects/domain/IGitHubRepositoryDataSource.ts +++ b/src/features/projects/domain/IGitHubRepositoryDataSource.ts @@ -24,10 +24,7 @@ export type GitHubRepositoryRef = { readonly files: { readonly name: string }[] -} - -export default interface IGitHubRepositoryDataSource { - getRepositories(): Promise + readonly changedFiles?: string[] } export default interface IGitHubRepositoryDataSource { diff --git a/src/features/projects/view/toolbar/Selector.tsx b/src/features/projects/view/toolbar/Selector.tsx index 4607d1f0..91261998 100644 --- a/src/features/projects/view/toolbar/Selector.tsx +++ b/src/features/projects/view/toolbar/Selector.tsx @@ -4,13 +4,16 @@ import { MenuItem, SelectChangeEvent, FormControl, - Typography + Typography, + Box, + Tooltip } from "@mui/material" import MenuItemHover from "@/common/ui/MenuItemHover" interface SelectorItem { readonly id: string readonly name: string + readonly hasChanges?: boolean } const Selector = ({ @@ -45,13 +48,29 @@ const Selector = ({ {items.map(item => ( - - {item.name} - + + + {item.name} + + {item.hasChanges && ( + + + + )} + ))} From 0a11200997411e7ff2d1065602430fdef13f6373 Mon Sep 17 00:00:00 2001 From: Ulrik Andersen Date: Thu, 11 Dec 2025 11:42:59 +0100 Subject: [PATCH 04/15] style: improve diff sidebar layout and colors (#635) Move level labels above path for better visual hierarchy and increase color saturation for better visibility. --- .../diffbar/components/DiffListItem.tsx | 76 +++++++++---------- .../diffbar/components/levelConfig.ts | 6 +- 2 files changed, 40 insertions(+), 42 deletions(-) diff --git a/src/features/sidebar/view/internal/diffbar/components/DiffListItem.tsx b/src/features/sidebar/view/internal/diffbar/components/DiffListItem.tsx index 951cf250..fd88e698 100644 --- a/src/features/sidebar/view/internal/diffbar/components/DiffListItem.tsx +++ b/src/features/sidebar/view/internal/diffbar/components/DiffListItem.tsx @@ -38,54 +38,52 @@ const DiffListItem = ({ gap: 0.75, }} > - + + {levelConfig.label} + + {operation && path && ( - {levelConfig.label} - - {operation && path && ( - - at{" "} - - {operation} - {" "} - - {path} - - - )} - {!operation && path && ( - + {operation} + {" "} + {path} - - )} - + + + )} + {!operation && path && ( + + {path} + + )} {text && ( { switch (level) { case 3: - return { label: "breaking", color: "#e88388" } + return { label: "breaking", color: "#ff5555" } case 2: - return { label: "warn", color: "#dbab79" } + return { label: "warn", color: "#ffaa33" } case 1: default: - return { label: "info", color: "#66c2cd" } + return { label: "info", color: "#44ddee" } } } From 1f3f873ef2750f3d37171fe39305493bd84f0f19 Mon Sep 17 00:00:00 2001 From: Ulrik Andersen Date: Thu, 11 Dec 2025 11:56:00 +0100 Subject: [PATCH 05/15] fix: pass hasChanges to spec selector for change indicator (#636) The Selector component was updated to display an orange dot for specs with changes, but TrailingToolbarItem and MobileToolbar weren't passing the hasChanges property when mapping specifications. --- src/features/projects/view/toolbar/MobileToolbar.tsx | 3 ++- src/features/projects/view/toolbar/TrailingToolbarItem.tsx | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/features/projects/view/toolbar/MobileToolbar.tsx b/src/features/projects/view/toolbar/MobileToolbar.tsx index 16fbd655..821af89a 100644 --- a/src/features/projects/view/toolbar/MobileToolbar.tsx +++ b/src/features/projects/view/toolbar/MobileToolbar.tsx @@ -30,7 +30,8 @@ const MobileToolbar = () => { ({ id: spec.id, - name: spec.name + name: spec.name, + hasChanges: !!spec.diffURL }))} selection={specification.id} onSelect={selectSpecification} diff --git a/src/features/projects/view/toolbar/TrailingToolbarItem.tsx b/src/features/projects/view/toolbar/TrailingToolbarItem.tsx index fe6dce34..ad3523aa 100644 --- a/src/features/projects/view/toolbar/TrailingToolbarItem.tsx +++ b/src/features/projects/view/toolbar/TrailingToolbarItem.tsx @@ -61,7 +61,8 @@ const TrailingToolbarItem = () => { ({ id: spec.id, - name: spec.name + name: spec.name, + hasChanges: !!spec.diffURL }))} selection={specification.id} onSelect={selectSpecification} From 5524d29cbf5155d30a44a5a10ae037109f225cee Mon Sep 17 00:00:00 2001 From: Ulrik Andersen Date: Thu, 11 Dec 2025 13:22:59 +0100 Subject: [PATCH 06/15] fix: scroll to change works without operationId for SwaggerUI and Redocly (#637) oasdiff provides method+path but not operationId. This change allows scroll-to-change to work by deriving the operation ID from method and path for SwaggerUI, and by searching for matching links in the Redocly iframe. --- .../docs/navigation/scrollToOperation.ts | 63 +++++++++++++------ 1 file changed, 45 insertions(+), 18 deletions(-) diff --git a/src/features/docs/navigation/scrollToOperation.ts b/src/features/docs/navigation/scrollToOperation.ts index 26d2957d..11abac83 100644 --- a/src/features/docs/navigation/scrollToOperation.ts +++ b/src/features/docs/navigation/scrollToOperation.ts @@ -1,5 +1,17 @@ import { DocumentationVisualizer } from "@/features/settings/domain" +/** + * Generates a SwaggerUI-compatible operationId from HTTP method and path. + * SwaggerUI generates IDs in the format: {method}_{path_normalized} + * where path is normalized by replacing / with _ and {param} with _param_ + */ +function generateSwaggerOperationId(method: string, path: string): string { + const normalizedPath = path + .replace(/\//g, "_") + .replace(/\{([^}]+)\}/g, "_$1_") + return `${method.toLowerCase()}${normalizedPath}` +} + /** * Finds and scrolls to a SwaggerUI operation element. * SwaggerUI elements have IDs in the format: operations-{tag}-{operationId} @@ -26,23 +38,42 @@ function scrollToSwaggerOperation(operationId: string): boolean { /** * Scrolls to an operation in Redocly by setting the hash on the iframe. - * Redocly uses hash format: #operation/{operationId} */ -function scrollToRedoclyOperation(operationId: string): void { +function scrollToRedoclyOperation(operationId?: string, method?: string, path?: string): void { const iframe = document.querySelector("iframe") if (!iframe?.contentWindow) { return } - iframe.contentWindow.location.hash = `operation/${operationId}` + + // try direct operationId link first + if (operationId) { + iframe.contentWindow.location.hash = `operation/${operationId}` + return + } + + if (!method || !path) { + return + } + + // fallback to method+path matching + const encodedPath = path.replace(/\//g, "~1") + const links = Array.from( + iframe.contentDocument?.querySelectorAll(`a[href*="${encodedPath}"]`) ?? [] + ) + + for (const link of links) { + const href = link.getAttribute("href") + if (href?.includes(`/${method.toLowerCase()}`) || href?.endsWith(`/${method.toLowerCase()}`)) { + const hash = href.startsWith("#") ? href.substring(1) : href + iframe.contentWindow.location.hash = hash + return + } + } } /** * Scrolls to an operation in the documentation viewer. * Each visualizer has its own mechanism for deep linking. - * - * For SwaggerUI: Uses DOM-based scrolling to find operations-{tag}-{operationId} elements - * For Stoplight: #/operations/{operationId} - * For Redocly: #operation/{operationId} (set on iframe) */ export function scrollToOperation( visualizer: DocumentationVisualizer, @@ -55,27 +86,23 @@ export function scrollToOperation( } switch (visualizer) { - case DocumentationVisualizer.SWAGGER: - // SwaggerUI: Use DOM-based scrolling since hash changes don't trigger navigation - // after initial page load - if (operationId) { - scrollToSwaggerOperation(operationId) + case DocumentationVisualizer.SWAGGER: { + // If operationId is not provided, try to generate it from method+path + const swaggerOpId = operationId ?? (method && path ? generateSwaggerOperationId(method, path) : undefined) + if (swaggerOpId) { + scrollToSwaggerOperation(swaggerOpId) } break + } case DocumentationVisualizer.STOPLIGHT: - // Stoplight uses hash-based navigation: #/operations/{operationId} if (operationId) { window.location.hash = `/operations/${operationId}` } break case DocumentationVisualizer.REDOCLY: - // Redocly runs in an iframe and uses hash format: #tag/{tag}/operation/{operationId} - // We need to set the hash on the iframe's content window - if (operationId) { - scrollToRedoclyOperation(operationId) - } + scrollToRedoclyOperation(operationId, method, path) break } } From 04a7219b0d0e689f41d40517af537f7718d2b72a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 12 Dec 2025 07:04:54 +0100 Subject: [PATCH 07/15] Bump next from 16.0.7 to 16.0.10 (#638) Bumps [next](https://github.com/vercel/next.js) from 16.0.7 to 16.0.10. - [Release notes](https://github.com/vercel/next.js/releases) - [Changelog](https://github.com/vercel/next.js/blob/canary/release.js) - [Commits](https://github.com/vercel/next.js/compare/v16.0.7...v16.0.10) --- updated-dependencies: - dependency-name: next dependency-version: 16.0.10 dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 326 +++++++++++++--------------------------------- package.json | 2 +- 2 files changed, 88 insertions(+), 240 deletions(-) diff --git a/package-lock.json b/package-lock.json index 30325963..eaaad053 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,7 +27,7 @@ "install": "^0.13.0", "ioredis": "^5.8.2", "mobx": "^6.15.0", - "next": "16.0.7", + "next": "16.0.10", "next-auth": "^5.0.0-beta.30", "npm": "^11.6.4", "nprogress": "^0.2.0", @@ -154,6 +154,7 @@ "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", @@ -285,7 +286,6 @@ "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=6.9.0" } @@ -353,7 +353,6 @@ "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -367,7 +366,6 @@ "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -381,7 +379,6 @@ "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.12.13" }, @@ -395,7 +392,6 @@ "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" }, @@ -412,7 +408,6 @@ "integrity": "sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, @@ -429,7 +424,6 @@ "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, @@ -443,7 +437,6 @@ "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -457,7 +450,6 @@ "integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, @@ -474,7 +466,6 @@ "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, @@ -488,7 +479,6 @@ "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -502,7 +492,6 @@ "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, @@ -516,7 +505,6 @@ "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -530,7 +518,6 @@ "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -544,7 +531,6 @@ "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -558,7 +544,6 @@ "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" }, @@ -575,7 +560,6 @@ "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" }, @@ -592,7 +576,6 @@ "integrity": "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, @@ -662,8 +645,7 @@ "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@emnapi/core": { "version": "1.7.1", @@ -756,6 +738,7 @@ "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.14.0.tgz", "integrity": "sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==", "license": "MIT", + "peer": true, "dependencies": { "@babel/runtime": "^7.18.3", "@emotion/babel-plugin": "^11.13.5", @@ -799,6 +782,7 @@ "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.14.1.tgz", "integrity": "sha512-qEEJt42DuToa3gurlH4Qqc1kVpNq8wO8cJtDzU46TjlzWjDlsVyevtYCRijVq3SrHsROS+gVQ8Fnea108GnKzw==", "license": "MIT", + "peer": true, "dependencies": { "@babel/runtime": "^7.18.3", "@emotion/babel-plugin": "^11.13.5", @@ -1062,6 +1046,7 @@ "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-7.1.0.tgz", "integrity": "sha512-fNxRUk1KhjSbnbuBxlWSnBLKLBNun52ZBTcs22H/xEEzM6Ap81ZFTQ4bZBxVQGQgVY0xugKGoRcCbaKjLQ3XZA==", "license": "MIT", + "peer": true, "dependencies": { "@fortawesome/fontawesome-common-types": "7.1.0" }, @@ -1647,7 +1632,6 @@ "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", "dev": true, "license": "ISC", - "peer": true, "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", @@ -1666,7 +1650,6 @@ "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", "dev": true, "license": "ISC", - "peer": true, "dependencies": { "camelcase": "^5.3.1", "find-up": "^4.1.0", @@ -1684,7 +1667,6 @@ "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "sprintf-js": "~1.0.2" } @@ -1695,7 +1677,6 @@ "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" @@ -1710,7 +1691,6 @@ "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" @@ -1725,7 +1705,6 @@ "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "p-locate": "^4.1.0" }, @@ -1739,7 +1718,6 @@ "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "p-try": "^2.0.0" }, @@ -1756,7 +1734,6 @@ "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "p-limit": "^2.2.0" }, @@ -1770,7 +1747,6 @@ "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=8" } @@ -1781,7 +1757,6 @@ "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=8" } @@ -1792,7 +1767,6 @@ "integrity": "sha512-+O1ifRjkvYIkBqASKWgLxrpEhQAAE7hY77ALLUufSk5717KfOShg6IbqLmdsLMPdUiFvA2kTs0R7YZy+l0IzZQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", @@ -1811,7 +1785,6 @@ "integrity": "sha512-03W6IhuhjqTlpzh/ojut/pDB2LPRygyWX8ExpgHtQA8H/3K7+1vKmcINx5UzeOX1se6YEsBsOHQ1CRzf3fOwTQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@jest/console": "30.2.0", "@jest/pattern": "30.0.1", @@ -1870,7 +1843,6 @@ "integrity": "sha512-/QPTL7OBJQ5ac09UDRa3EQes4gt1FTEG/8jZ/4v5IVzx+Cv7dLxlVIvfvSVRiiX2drWyXeBjkMSR8hvOWSog5g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@jest/fake-timers": "30.2.0", "@jest/types": "30.2.0", @@ -1887,7 +1859,6 @@ "integrity": "sha512-V9yxQK5erfzx99Sf+7LbhBwNWEZ9eZay8qQ9+JSC0TrMR1pMDHLMY+BnVPacWU6Jamrh252/IKo4F1Xn/zfiqA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "expect": "30.2.0", "jest-snapshot": "30.2.0" @@ -1915,7 +1886,6 @@ "integrity": "sha512-HI3tRLjRxAbBy0VO8dqqm7Hb2mIa8d5bg/NJkyQcOk7V118ObQML8RC5luTF/Zsg4474a+gDvhce7eTnP4GhYw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@jest/types": "30.2.0", "@sinonjs/fake-timers": "^13.0.0", @@ -1944,7 +1914,6 @@ "integrity": "sha512-b63wmnKPaK+6ZZfpYhz9K61oybvbI1aMcIs80++JI1O1rR1vaxHUCNqo3ITu6NU0d4V34yZFoHMn/uoKr/Rwfw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@jest/environment": "30.2.0", "@jest/expect": "30.2.0", @@ -1975,7 +1944,6 @@ "integrity": "sha512-DRyW6baWPqKMa9CzeiBjHwjd8XeAyco2Vt8XbcLFjiwCOEKOvy82GJ8QQnJE9ofsxCMPjH4MfH8fCWIHHDKpAQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@bcoe/v8-coverage": "^0.2.3", "@jest/console": "30.2.0", @@ -2032,7 +2000,6 @@ "integrity": "sha512-0aVxM3RH6DaiLcjj/b0KrIBZhSX1373Xci4l3cW5xiUWPctZ59zQ7jj4rqcJQ/Z8JuN/4wX3FpJSa3RssVvCug==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@jest/types": "30.2.0", "chalk": "^4.1.2", @@ -2049,7 +2016,6 @@ "integrity": "sha512-MIRWMUUR3sdbP36oyNyhbThLHyJ2eEDClPCiHVbrYAe5g3CHRArIVpBw7cdSB5fr+ofSfIb2Tnsw8iEHL0PYQg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@jridgewell/trace-mapping": "^0.3.25", "callsites": "^3.1.0", @@ -2065,7 +2031,6 @@ "integrity": "sha512-RF+Z+0CCHkARz5HT9mcQCBulb1wgCP3FBvl9VFokMX27acKphwyQsNuWH3c+ojd1LeWBLoTYoxF0zm6S/66mjg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@jest/console": "30.2.0", "@jest/types": "30.2.0", @@ -2082,7 +2047,6 @@ "integrity": "sha512-wXKgU/lk8fKXMu/l5Hog1R61bL4q5GCdT6OJvdAFz1P+QrpoFuLU68eoKuVc4RbrTtNnTL5FByhWdLgOPSph+Q==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@jest/test-result": "30.2.0", "graceful-fs": "^4.2.11", @@ -2099,7 +2063,6 @@ "integrity": "sha512-XsauDV82o5qXbhalKxD7p4TZYYdwcaEXC77PPD2HixEFF+6YGppjrAAQurTl2ECWcEomHBMMNS9AH3kcCFx8jA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/core": "^7.27.4", "@jest/types": "30.2.0", @@ -2126,8 +2089,7 @@ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@jest/types": { "version": "30.2.0", @@ -2235,6 +2197,7 @@ "resolved": "https://registry.npmjs.org/@mui/material/-/material-7.3.5.tgz", "integrity": "sha512-8VVxFmp1GIm9PpmnQoCoYo0UWHoOrdA57tDL62vkpzEgvb/d71Wsbv4FRg7r1Gyx7PuSo0tflH34cdl/NvfHNQ==", "license": "MIT", + "peer": true, "dependencies": { "@babel/runtime": "^7.28.4", "@mui/core-downloads-tracker": "^7.3.5", @@ -2441,9 +2404,9 @@ } }, "node_modules/@next/env": { - "version": "16.0.7", - "resolved": "https://registry.npmjs.org/@next/env/-/env-16.0.7.tgz", - "integrity": "sha512-gpaNgUh5nftFKRkRQGnVi5dpcYSKGcZZkQffZ172OrG/XkrnS7UBTQ648YY+8ME92cC4IojpI2LqTC8sTDhAaw==", + "version": "16.0.10", + "resolved": "https://registry.npmjs.org/@next/env/-/env-16.0.10.tgz", + "integrity": "sha512-8tuaQkyDVgeONQ1MeT9Mkk8pQmZapMKFh5B+OrFUlG3rVmYTXcXlBetBgTurKXGaIZvkoqRT9JL5K3phXcgang==", "license": "MIT" }, "node_modules/@next/eslint-plugin-next": { @@ -2457,9 +2420,9 @@ } }, "node_modules/@next/swc-darwin-arm64": { - "version": "16.0.7", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.0.7.tgz", - "integrity": "sha512-LlDtCYOEj/rfSnEn/Idi+j1QKHxY9BJFmxx7108A6D8K0SB+bNgfYQATPk/4LqOl4C0Wo3LACg2ie6s7xqMpJg==", + "version": "16.0.10", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.0.10.tgz", + "integrity": "sha512-4XgdKtdVsaflErz+B5XeG0T5PeXKDdruDf3CRpnhN+8UebNa5N2H58+3GDgpn/9GBurrQ1uWW768FfscwYkJRg==", "cpu": [ "arm64" ], @@ -2473,9 +2436,9 @@ } }, "node_modules/@next/swc-darwin-x64": { - "version": "16.0.7", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.0.7.tgz", - "integrity": "sha512-rtZ7BhnVvO1ICf3QzfW9H3aPz7GhBrnSIMZyr4Qy6boXF0b5E3QLs+cvJmg3PsTCG2M1PBoC+DANUi4wCOKXpA==", + "version": "16.0.10", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.0.10.tgz", + "integrity": "sha512-spbEObMvRKkQ3CkYVOME+ocPDFo5UqHb8EMTS78/0mQ+O1nqE8toHJVioZo4TvebATxgA8XMTHHrScPrn68OGw==", "cpu": [ "x64" ], @@ -2489,9 +2452,9 @@ } }, "node_modules/@next/swc-linux-arm64-gnu": { - "version": "16.0.7", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.0.7.tgz", - "integrity": "sha512-mloD5WcPIeIeeZqAIP5c2kdaTa6StwP4/2EGy1mUw8HiexSHGK/jcM7lFuS3u3i2zn+xH9+wXJs6njO7VrAqww==", + "version": "16.0.10", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.0.10.tgz", + "integrity": "sha512-uQtWE3X0iGB8apTIskOMi2w/MKONrPOUCi5yLO+v3O8Mb5c7K4Q5KD1jvTpTF5gJKa3VH/ijKjKUq9O9UhwOYw==", "cpu": [ "arm64" ], @@ -2505,9 +2468,9 @@ } }, "node_modules/@next/swc-linux-arm64-musl": { - "version": "16.0.7", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.0.7.tgz", - "integrity": "sha512-+ksWNrZrthisXuo9gd1XnjHRowCbMtl/YgMpbRvFeDEqEBd523YHPWpBuDjomod88U8Xliw5DHhekBC3EOOd9g==", + "version": "16.0.10", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.0.10.tgz", + "integrity": "sha512-llA+hiDTrYvyWI21Z0L1GiXwjQaanPVQQwru5peOgtooeJ8qx3tlqRV2P7uH2pKQaUfHxI/WVarvI5oYgGxaTw==", "cpu": [ "arm64" ], @@ -2521,9 +2484,9 @@ } }, "node_modules/@next/swc-linux-x64-gnu": { - "version": "16.0.7", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.0.7.tgz", - "integrity": "sha512-4WtJU5cRDxpEE44Ana2Xro1284hnyVpBb62lIpU5k85D8xXxatT+rXxBgPkc7C1XwkZMWpK5rXLXTh9PFipWsA==", + "version": "16.0.10", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.0.10.tgz", + "integrity": "sha512-AK2q5H0+a9nsXbeZ3FZdMtbtu9jxW4R/NgzZ6+lrTm3d6Zb7jYrWcgjcpM1k8uuqlSy4xIyPR2YiuUr+wXsavA==", "cpu": [ "x64" ], @@ -2537,9 +2500,9 @@ } }, "node_modules/@next/swc-linux-x64-musl": { - "version": "16.0.7", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.0.7.tgz", - "integrity": "sha512-HYlhqIP6kBPXalW2dbMTSuB4+8fe+j9juyxwfMwCe9kQPPeiyFn7NMjNfoFOfJ2eXkeQsoUGXg+O2SE3m4Qg2w==", + "version": "16.0.10", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.0.10.tgz", + "integrity": "sha512-1TDG9PDKivNw5550S111gsO4RGennLVl9cipPhtkXIFVwo31YZ73nEbLjNC8qG3SgTz/QZyYyaFYMeY4BKZR/g==", "cpu": [ "x64" ], @@ -2553,9 +2516,9 @@ } }, "node_modules/@next/swc-win32-arm64-msvc": { - "version": "16.0.7", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.0.7.tgz", - "integrity": "sha512-EviG+43iOoBRZg9deGauXExjRphhuYmIOJ12b9sAPy0eQ6iwcPxfED2asb/s2/yiLYOdm37kPaiZu8uXSYPs0Q==", + "version": "16.0.10", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.0.10.tgz", + "integrity": "sha512-aEZIS4Hh32xdJQbHz121pyuVZniSNoqDVx1yIr2hy+ZwJGipeqnMZBJHyMxv2tiuAXGx6/xpTcQJ6btIiBjgmg==", "cpu": [ "arm64" ], @@ -2569,9 +2532,9 @@ } }, "node_modules/@next/swc-win32-x64-msvc": { - "version": "16.0.7", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.0.7.tgz", - "integrity": "sha512-gniPjy55zp5Eg0896qSrf3yB1dw4F/3s8VK1ephdsZZ129j2n6e1WqCbE2YgcKhW9hPB9TVZENugquWJD5x0ug==", + "version": "16.0.10", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.0.10.tgz", + "integrity": "sha512-E+njfCoFLb01RAFEnGZn6ERoOqhK1Gl3Lfz1Kjnj0Ulfu7oJbuMyvBKNj/bw8XZnenHDASlygTjZICQW+rYW1Q==", "cpu": [ "x64" ], @@ -2743,6 +2706,7 @@ "resolved": "https://registry.npmjs.org/@octokit/core/-/core-7.0.6.tgz", "integrity": "sha512-DhGl4xMVFGVIyMwswXeyzdL4uXD5OGILGX5N8Y+f6W7LhC1Ze2poSNrkF/fedpVDHEEZ+PHFW0vL14I+mm8K3Q==", "license": "MIT", + "peer": true, "dependencies": { "@octokit/auth-token": "^6.0.0", "@octokit/graphql": "^9.0.3", @@ -2989,7 +2953,6 @@ "dev": true, "license": "MIT", "optional": true, - "peer": true, "engines": { "node": ">=14" } @@ -3000,7 +2963,6 @@ "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": "^12.20.0 || ^14.18.0 || >=16.0.0" }, @@ -3099,7 +3061,6 @@ "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", "dev": true, "license": "BSD-3-Clause", - "peer": true, "dependencies": { "type-detect": "4.0.8" } @@ -3110,7 +3071,6 @@ "integrity": "sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw==", "dev": true, "license": "BSD-3-Clause", - "peer": true, "dependencies": { "@sinonjs/commons": "^3.0.1" } @@ -3478,7 +3438,6 @@ "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", @@ -3493,7 +3452,6 @@ "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/types": "^7.0.0" } @@ -3504,7 +3462,6 @@ "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/parser": "^7.1.0", "@babel/types": "^7.0.0" @@ -3516,7 +3473,6 @@ "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/types": "^7.28.2" } @@ -3625,6 +3581,7 @@ "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.7.tgz", "integrity": "sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==", "license": "MIT", + "peer": true, "dependencies": { "csstype": "^3.2.2" } @@ -3721,6 +3678,7 @@ "integrity": "sha512-jCzKdm/QK0Kg4V4IK/oMlRZlY+QOcdjv89U2NgKHZk1CYTj82/RVSx1mV/0gqCVMJ/DA+Zf/S4NBWNF8GQ+eqQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.48.0", "@typescript-eslint/types": "8.48.0", @@ -3924,8 +3882,7 @@ "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", "dev": true, - "license": "ISC", - "peer": true + "license": "ISC" }, "node_modules/@unrs/resolver-binding-android-arm-eabi": { "version": "1.11.1", @@ -4202,6 +4159,7 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -4251,7 +4209,6 @@ "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "type-fest": "^0.21.3" }, @@ -4268,7 +4225,6 @@ "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -4297,7 +4253,6 @@ "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, "license": "ISC", - "peer": true, "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -4541,7 +4496,6 @@ "integrity": "sha512-0YiBEOxWqKkSQWL9nNGGEgndoeL0ZpWrbLMNL5u/Kaxrli3Eaxlt3ZtIDktEvXt4L/R9r3ODr2zKwGM/2BjxVw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@jest/transform": "30.2.0", "@types/babel__core": "^7.20.5", @@ -4564,7 +4518,6 @@ "integrity": "sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA==", "dev": true, "license": "BSD-3-Clause", - "peer": true, "workspaces": [ "test/babel-8" ], @@ -4585,7 +4538,6 @@ "integrity": "sha512-ftzhzSGMUnOzcCXd6WHdBGMyuwy15Wnn0iyyWGKgBDLxf9/s5ABuraCSpBX2uG0jUg4rqJnxsLc5+oYBqoxVaA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/babel__core": "^7.20.5" }, @@ -4614,7 +4566,6 @@ "integrity": "sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-bigint": "^7.8.3", @@ -4642,7 +4593,6 @@ "integrity": "sha512-US4Z3NOieAQumwFnYdUWKvUKh8+YSnS/gB3t6YBiz0bskpu7Pine8pPCheNxlPEW4wnUkma2a94YuW2q3guvCQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "babel-plugin-jest-hoist": "30.2.0", "babel-preset-current-node-syntax": "^1.2.0" @@ -4724,6 +4674,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "baseline-browser-mapping": "^2.8.25", "caniuse-lite": "^1.0.30001754", @@ -4757,7 +4708,6 @@ "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", "dev": true, "license": "Apache-2.0", - "peer": true, "dependencies": { "node-int64": "^0.4.0" } @@ -4767,8 +4717,7 @@ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/call-bind": { "version": "1.0.8", @@ -4841,7 +4790,6 @@ "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=6" } @@ -4898,7 +4846,6 @@ "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=10" } @@ -4924,8 +4871,7 @@ "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-2.1.1.tgz", "integrity": "sha512-+CmxIZ/L2vNcEfvNtLdU0ZQ6mbq3FZnwAP2PPTiKP+1QOoKwlKlPgb8UKV0Dds7QVaMnHm+FwSft2VB0s/SLjQ==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/classnames": { "version": "2.5.1", @@ -5035,7 +4981,6 @@ "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", "dev": true, "license": "MIT", - "peer": true, "engines": { "iojs": ">= 1.0.0", "node": ">= 0.12.0" @@ -5046,8 +4991,7 @@ "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.3.tgz", "integrity": "sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/color-convert": { "version": "2.0.1", @@ -5092,6 +5036,7 @@ "integrity": "sha512-c3Q2VVkGAUyupsjRnaNX6u8Dq2vAdzm9iuPj5FW0fRxzlxgq9Q39MDq10IvmQSpLgHQNyQzQmOo6bgGHmH3NNg==", "hasInstallScript": true, "license": "MIT", + "peer": true, "funding": { "type": "opencollective", "url": "https://opencollective.com/core-js" @@ -5252,7 +5197,6 @@ "integrity": "sha512-HGFtf8yhuhGhqO07SV79tRp+br4MnbdjeVxotpn1QBl30pcLLCQjX5b2295ll0fv8RKDKsmWYrl05usHM9CewQ==", "dev": true, "license": "MIT", - "peer": true, "peerDependencies": { "babel-plugin-macros": "^3.1.0" }, @@ -5275,7 +5219,6 @@ "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -5349,7 +5292,6 @@ "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=8" } @@ -5406,8 +5348,7 @@ "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/electron-to-chromium": { "version": "1.5.254", @@ -5422,7 +5363,6 @@ "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -5442,6 +5382,7 @@ "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", "license": "MIT", + "peer": true, "dependencies": { "iconv-lite": "^0.6.2" } @@ -5679,6 +5620,7 @@ "integrity": "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -5864,6 +5806,7 @@ "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@rtsao/scc": "^1.1.0", "array-includes": "^3.1.9", @@ -6209,7 +6152,6 @@ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true, "license": "BSD-2-Clause", - "peer": true, "bin": { "esparse": "bin/esparse.js", "esvalidate": "bin/esvalidate.js" @@ -6276,7 +6218,6 @@ "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.0", @@ -6300,8 +6241,7 @@ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true, - "license": "ISC", - "peer": true + "license": "ISC" }, "node_modules/exit-x": { "version": "0.2.2", @@ -6309,7 +6249,6 @@ "integrity": "sha512-+I6B/IkJc1o/2tiURyz/ivu/O0nKNEArIUB5O7zBrlDVJr22SCLH3xTeEry428LvFhRzIA1g8izguxJ/gbNcVQ==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">= 0.8.0" } @@ -6454,7 +6393,6 @@ "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", "dev": true, "license": "Apache-2.0", - "peer": true, "dependencies": { "bser": "2.1.1" } @@ -6563,7 +6501,6 @@ "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", "dev": true, "license": "ISC", - "peer": true, "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" @@ -6580,8 +6517,7 @@ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "dev": true, - "license": "ISC", - "peer": true + "license": "ISC" }, "node_modules/fsevents": { "version": "2.3.3", @@ -6594,7 +6530,6 @@ "os": [ "darwin" ], - "peer": true, "engines": { "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } @@ -6699,7 +6634,6 @@ "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=8.0.0" } @@ -6724,7 +6658,6 @@ "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=10" }, @@ -6769,7 +6702,6 @@ "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", "dev": true, "license": "ISC", - "peer": true, "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", @@ -7017,8 +6949,7 @@ "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/http2-client": { "version": "1.3.5", @@ -7045,7 +6976,6 @@ "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "dev": true, "license": "Apache-2.0", - "peer": true, "engines": { "node": ">=10.17.0" } @@ -7094,7 +7024,6 @@ "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "pkg-dir": "^4.2.0", "resolve-cwd": "^3.0.0" @@ -7126,7 +7055,6 @@ "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", "dev": true, "license": "ISC", - "peer": true, "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -7137,8 +7065,7 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true, - "license": "ISC", - "peer": true + "license": "ISC" }, "node_modules/install": { "version": "0.13.0", @@ -7169,6 +7096,7 @@ "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.8.2.tgz", "integrity": "sha512-C6uC+kleiIMmjViJINWk80sOQw5lEzse1ZmvD+S/s8p8CWapftSaC+kocGTx6xrbrJ4WmYQGC08ffHLr6ToR6Q==", "license": "MIT", + "peer": true, "dependencies": { "@ioredis/commands": "1.4.0", "cluster-key-slot": "^1.1.0", @@ -7379,7 +7307,6 @@ "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=6" } @@ -7524,7 +7451,6 @@ "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=8" }, @@ -7649,7 +7575,6 @@ "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", "dev": true, "license": "BSD-3-Clause", - "peer": true, "engines": { "node": ">=8" } @@ -7660,7 +7585,6 @@ "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", "dev": true, "license": "BSD-3-Clause", - "peer": true, "dependencies": { "@babel/core": "^7.23.9", "@babel/parser": "^7.23.9", @@ -7678,7 +7602,6 @@ "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", "dev": true, "license": "BSD-3-Clause", - "peer": true, "dependencies": { "istanbul-lib-coverage": "^3.0.0", "make-dir": "^4.0.0", @@ -7694,7 +7617,6 @@ "integrity": "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==", "dev": true, "license": "BSD-3-Clause", - "peer": true, "dependencies": { "@jridgewell/trace-mapping": "^0.3.23", "debug": "^4.1.1", @@ -7710,7 +7632,6 @@ "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", "dev": true, "license": "BSD-3-Clause", - "peer": true, "dependencies": { "html-escaper": "^2.0.0", "istanbul-lib-report": "^3.0.0" @@ -7743,7 +7664,6 @@ "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", "dev": true, "license": "BlueOak-1.0.0", - "peer": true, "dependencies": { "@isaacs/cliui": "^8.0.2" }, @@ -7788,7 +7708,6 @@ "integrity": "sha512-L8lR1ChrRnSdfeOvTrwZMlnWV8G/LLjQ0nG9MBclwWZidA2N5FviRki0Bvh20WRMOX31/JYvzdqTJrk5oBdydQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "execa": "^5.1.1", "jest-util": "30.2.0", @@ -7804,7 +7723,6 @@ "integrity": "sha512-Fh0096NC3ZkFx05EP2OXCxJAREVxj1BcW/i6EWqqymcgYKWjyyDpral3fMxVcHXg6oZM7iULer9wGRFvfpl+Tg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@jest/environment": "30.2.0", "@jest/expect": "30.2.0", @@ -7837,7 +7755,6 @@ "integrity": "sha512-Os9ukIvADX/A9sLt6Zse3+nmHtHaE6hqOsjQtNiugFTbKRHYIYtZXNGNK9NChseXy7djFPjndX1tL0sCTlfpAA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@jest/core": "30.2.0", "@jest/test-result": "30.2.0", @@ -7871,7 +7788,6 @@ "integrity": "sha512-g4WkyzFQVWHtu6uqGmQR4CQxz/CH3yDSlhzXMWzNjDx843gYjReZnMRanjRCq5XZFuQrGDxgUaiYWE8BRfVckA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/core": "^7.27.4", "@jest/get-type": "30.1.0", @@ -7940,7 +7856,6 @@ "integrity": "sha512-tR/FFgZKS1CXluOQzZvNH3+0z9jXr3ldGSD8bhyuxvlVUwbeLOGynkunvlTMxchC5urrKndYiwCFC0DLVjpOCA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "detect-newline": "^3.1.0" }, @@ -7954,7 +7869,6 @@ "integrity": "sha512-lpWlJlM7bCUf1mfmuqTA8+j2lNURW9eNafOy99knBM01i5CQeY5UH1vZjgT9071nDJac1M4XsbyI44oNOdhlDQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@jest/get-type": "30.1.0", "@jest/types": "30.2.0", @@ -7972,7 +7886,6 @@ "integrity": "sha512-ElU8v92QJ9UrYsKrxDIKCxu6PfNj4Hdcktcn0JX12zqNdqWHB0N+hwOnnBBXvjLd2vApZtuLUGs1QSY+MsXoNA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@jest/environment": "30.2.0", "@jest/fake-timers": "30.2.0", @@ -7992,7 +7905,6 @@ "integrity": "sha512-sQA/jCb9kNt+neM0anSj6eZhLZUIhQgwDt7cPGjumgLM4rXsfb9kpnlacmvZz3Q5tb80nS+oG/if+NBKrHC+Xw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", @@ -8018,7 +7930,6 @@ "integrity": "sha512-M6jKAjyzjHG0SrQgwhgZGy9hFazcudwCNovY/9HPIicmNSBuockPSedAP9vlPK6ONFJ1zfyH/M2/YYJxOz5cdQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@jest/get-type": "30.1.0", "pretty-format": "30.2.0" @@ -8085,7 +7996,6 @@ "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=6" }, @@ -8114,7 +8024,6 @@ "integrity": "sha512-TCrHSxPlx3tBY3hWNtRQKbtgLhsXa1WmbJEqBlTBrGafd5fiQFByy2GNCEoGR+Tns8d15GaL9cxEzKOO3GEb2A==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "chalk": "^4.1.2", "graceful-fs": "^4.2.11", @@ -8135,7 +8044,6 @@ "integrity": "sha512-xTOIGug/0RmIe3mmCqCT95yO0vj6JURrn1TKWlNbhiAefJRWINNPgwVkrVgt/YaerPzY3iItufd80v3lOrFJ2w==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "jest-regex-util": "30.0.1", "jest-snapshot": "30.2.0" @@ -8150,7 +8058,6 @@ "integrity": "sha512-PqvZ2B2XEyPEbclp+gV6KO/F1FIFSbIwewRgmROCMBo/aZ6J1w8Qypoj2pEOcg3G2HzLlaP6VUtvwCI8dM3oqQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@jest/console": "30.2.0", "@jest/environment": "30.2.0", @@ -8185,7 +8092,6 @@ "integrity": "sha512-p1+GVX/PJqTucvsmERPMgCPvQJpFt4hFbM+VN3n8TMo47decMUcJbt+rgzwrEme0MQUA/R+1de2axftTHkKckg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@jest/environment": "30.2.0", "@jest/fake-timers": "30.2.0", @@ -8220,7 +8126,6 @@ "integrity": "sha512-5WEtTy2jXPFypadKNpbNkZ72puZCa6UjSr/7djeecHWOu7iYhSXSnHScT8wBz3Rn8Ena5d5RYRcsyKIeqG1IyA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/core": "^7.27.4", "@babel/generator": "^7.27.5", @@ -8285,7 +8190,6 @@ "integrity": "sha512-FBGWi7dP2hpdi8nBoWxSsLvBFewKAg0+uSQwBaof4Y4DPgBabXgpSYC5/lR7VmnIlSpASmCi/ntRWPbv7089Pw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@jest/get-type": "30.1.0", "@jest/types": "30.2.0", @@ -8304,7 +8208,6 @@ "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=10" }, @@ -8318,7 +8221,6 @@ "integrity": "sha512-PYxa28dxJ9g777pGm/7PrbnMeA0Jr7osHP9bS7eJy9DuAjMgdGtxgf0uKMyoIsTWAkIbUW5hSDdJ3urmgXBqxg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@jest/test-result": "30.2.0", "@jest/types": "30.2.0", @@ -8339,7 +8241,6 @@ "integrity": "sha512-0Q4Uk8WF7BUwqXHuAjc23vmopWJw5WH7w2tqBoUOZpOjW/ZnR44GXXd1r82RvnmI2GZge3ivrYXk/BE2+VtW2g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/node": "*", "@ungap/structured-clone": "^1.3.0", @@ -8357,7 +8258,6 @@ "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -8527,7 +8427,6 @@ "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=6" } @@ -8905,7 +8804,6 @@ "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "semver": "^7.5.3" }, @@ -8929,7 +8827,6 @@ "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", "dev": true, "license": "BSD-3-Clause", - "peer": true, "dependencies": { "tmpl": "1.0.5" } @@ -8967,8 +8864,7 @@ "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/merge2": { "version": "1.4.1", @@ -9000,7 +8896,6 @@ "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=6" } @@ -9037,7 +8932,6 @@ "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", "dev": true, "license": "ISC", - "peer": true, "engines": { "node": ">=16 || 14 >=14.17" } @@ -9047,6 +8941,7 @@ "resolved": "https://registry.npmjs.org/mobx/-/mobx-6.15.0.tgz", "integrity": "sha512-UczzB+0nnwGotYSgllfARAqWCJ5e/skuV2K/l+Zyck/H6pJIhLXuBnz+6vn2i211o7DtbE78HQtsYEKICHGI+g==", "license": "MIT", + "peer": true, "funding": { "type": "opencollective", "url": "https://opencollective.com/mobx" @@ -9157,12 +9052,12 @@ "license": "MIT" }, "node_modules/next": { - "version": "16.0.7", - "resolved": "https://registry.npmjs.org/next/-/next-16.0.7.tgz", - "integrity": "sha512-3mBRJyPxT4LOxAJI6IsXeFtKfiJUbjCLgvXO02fV8Wy/lIhPvP94Fe7dGhUgHXcQy4sSuYwQNcOLhIfOm0rL0A==", + "version": "16.0.10", + "resolved": "https://registry.npmjs.org/next/-/next-16.0.10.tgz", + "integrity": "sha512-RtWh5PUgI+vxlV3HdR+IfWA1UUHu0+Ram/JBO4vWB54cVPentCD0e+lxyAYEsDTqGGMg7qpjhKh6dc6aW7W/sA==", "license": "MIT", "dependencies": { - "@next/env": "16.0.7", + "@next/env": "16.0.10", "@swc/helpers": "0.5.15", "caniuse-lite": "^1.0.30001579", "postcss": "8.4.31", @@ -9175,14 +9070,14 @@ "node": ">=20.9.0" }, "optionalDependencies": { - "@next/swc-darwin-arm64": "16.0.7", - "@next/swc-darwin-x64": "16.0.7", - "@next/swc-linux-arm64-gnu": "16.0.7", - "@next/swc-linux-arm64-musl": "16.0.7", - "@next/swc-linux-x64-gnu": "16.0.7", - "@next/swc-linux-x64-musl": "16.0.7", - "@next/swc-win32-arm64-msvc": "16.0.7", - "@next/swc-win32-x64-msvc": "16.0.7", + "@next/swc-darwin-arm64": "16.0.10", + "@next/swc-darwin-x64": "16.0.10", + "@next/swc-linux-arm64-gnu": "16.0.10", + "@next/swc-linux-arm64-musl": "16.0.10", + "@next/swc-linux-x64-gnu": "16.0.10", + "@next/swc-linux-x64-musl": "16.0.10", + "@next/swc-win32-arm64-msvc": "16.0.10", + "@next/swc-win32-x64-msvc": "16.0.10", "sharp": "^0.34.4" }, "peerDependencies": { @@ -9329,8 +9224,7 @@ "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/node-readfiles": { "version": "0.2.0", @@ -9354,7 +9248,6 @@ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -9521,7 +9414,6 @@ "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "path-key": "^3.0.0" }, @@ -11225,6 +11117,7 @@ "version": "4.0.3", "inBundle": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -11607,7 +11500,6 @@ "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "dev": true, "license": "ISC", - "peer": true, "dependencies": { "wrappy": "1" } @@ -11618,7 +11510,6 @@ "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "mimic-fn": "^2.1.0" }, @@ -11714,7 +11605,6 @@ "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=6" } @@ -11724,8 +11614,7 @@ "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", "dev": true, - "license": "BlueOak-1.0.0", - "peer": true + "license": "BlueOak-1.0.0" }, "node_modules/parent-module": { "version": "1.0.1", @@ -11779,7 +11668,6 @@ "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -11806,7 +11694,6 @@ "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", "dev": true, "license": "BlueOak-1.0.0", - "peer": true, "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" @@ -11823,8 +11710,7 @@ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", "dev": true, - "license": "ISC", - "peer": true + "license": "ISC" }, "node_modules/path-type": { "version": "4.0.0", @@ -11847,6 +11733,7 @@ "integrity": "sha512-enxc1h0jA/aq5oSDMvqyW3q89ra6XIIDZgCX9vkMrnz5DFTw/Ny3Li2lFQ+pt3L6MCgm/5o2o8HW9hiJji+xvw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "pg-connection-string": "^2.9.1", "pg-pool": "^3.10.1", @@ -11963,7 +11850,6 @@ "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">= 6" } @@ -11974,7 +11860,6 @@ "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "find-up": "^4.0.0" }, @@ -11988,7 +11873,6 @@ "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" @@ -12003,7 +11887,6 @@ "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "p-locate": "^4.1.0" }, @@ -12017,7 +11900,6 @@ "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "p-try": "^2.0.0" }, @@ -12034,7 +11916,6 @@ "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "p-limit": "^2.2.0" }, @@ -12156,6 +12037,7 @@ "resolved": "https://registry.npmjs.org/preact/-/preact-10.24.3.tgz", "integrity": "sha512-Z2dPnBnMUfyQfSQ+GBdsGa16hz35YmLmtTLhM169uW944hYL6xzTYkJjC07j+Wosz733pMWx0fgON3JNw1jJQA==", "license": "MIT", + "peer": true, "funding": { "type": "opencollective", "url": "https://opencollective.com/preact" @@ -12266,8 +12148,7 @@ "url": "https://opencollective.com/fast-check" } ], - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/queue-microtask": { "version": "1.2.3", @@ -12295,6 +12176,7 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz", "integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==", "license": "MIT", + "peer": true, "engines": { "node": ">=0.10.0" } @@ -12304,6 +12186,7 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz", "integrity": "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==", "license": "MIT", + "peer": true, "dependencies": { "scheduler": "^0.27.0" }, @@ -12524,7 +12407,6 @@ "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "resolve-from": "^5.0.0" }, @@ -12538,7 +12420,6 @@ "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=8" } @@ -12934,7 +12815,6 @@ "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", "dev": true, "license": "ISC", - "peer": true, "engines": { "node": ">=14" }, @@ -12985,7 +12865,6 @@ "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" @@ -12997,7 +12876,6 @@ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, "license": "BSD-3-Clause", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -13017,8 +12895,7 @@ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", "dev": true, - "license": "BSD-3-Clause", - "peer": true + "license": "BSD-3-Clause" }, "node_modules/stable-hash": { "version": "0.0.5", @@ -13081,7 +12958,6 @@ "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "char-regex": "^1.0.2", "strip-ansi": "^6.0.0" @@ -13096,7 +12972,6 @@ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=8" } @@ -13107,7 +12982,6 @@ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -13121,7 +12995,6 @@ "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", @@ -13141,7 +13014,6 @@ "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -13157,7 +13029,6 @@ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=8" } @@ -13167,8 +13038,7 @@ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/string-width-cjs/node_modules/strip-ansi": { "version": "6.0.1", @@ -13176,7 +13046,6 @@ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -13303,7 +13172,6 @@ "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "ansi-regex": "^6.0.1" }, @@ -13321,7 +13189,6 @@ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -13335,7 +13202,6 @@ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=8" } @@ -13346,7 +13212,6 @@ "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=8" } @@ -13357,7 +13222,6 @@ "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=6" } @@ -13392,6 +13256,7 @@ "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-6.1.19.tgz", "integrity": "sha512-1v/e3Dl1BknC37cXMhwGomhO8AkYmN41CqyX9xhUDxry1ns3BFQy2lLDRQXJRdVVWB9OHemv/53xaStimvWyuA==", "license": "MIT", + "peer": true, "dependencies": { "@emotion/is-prop-valid": "1.2.2", "@emotion/unitless": "0.8.1", @@ -13591,7 +13456,6 @@ "integrity": "sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@pkgr/core": "^0.2.9" }, @@ -13629,7 +13493,6 @@ "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", "dev": true, "license": "ISC", - "peer": true, "dependencies": { "@istanbuljs/schema": "^0.1.2", "glob": "^7.1.4", @@ -13645,7 +13508,6 @@ "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -13658,7 +13520,6 @@ "deprecated": "Glob versions prior to v9 are no longer supported", "dev": true, "license": "ISC", - "peer": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -13680,7 +13541,6 @@ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, "license": "ISC", - "peer": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -13729,6 +13589,7 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -13741,8 +13602,7 @@ "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", "dev": true, - "license": "BSD-3-Clause", - "peer": true + "license": "BSD-3-Clause" }, "node_modules/to-regex-range": { "version": "5.0.1", @@ -13912,7 +13772,6 @@ "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=4" } @@ -13923,7 +13782,6 @@ "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", "dev": true, "license": "(MIT OR CC0-1.0)", - "peer": true, "engines": { "node": ">=10" }, @@ -14015,6 +13873,7 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -14211,7 +14070,6 @@ "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", "dev": true, "license": "ISC", - "peer": true, "dependencies": { "@jridgewell/trace-mapping": "^0.3.12", "@types/istanbul-lib-coverage": "^2.0.1", @@ -14226,8 +14084,7 @@ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/walker": { "version": "1.0.8", @@ -14235,7 +14092,6 @@ "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", "dev": true, "license": "Apache-2.0", - "peer": true, "dependencies": { "makeerror": "1.0.12" } @@ -14384,7 +14240,6 @@ "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", @@ -14404,7 +14259,6 @@ "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -14423,7 +14277,6 @@ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=8" } @@ -14433,8 +14286,7 @@ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/wrap-ansi-cjs/node_modules/string-width": { "version": "4.2.3", @@ -14442,7 +14294,6 @@ "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -14458,7 +14309,6 @@ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -14472,7 +14322,6 @@ "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -14485,8 +14334,7 @@ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true, - "license": "ISC", - "peer": true + "license": "ISC" }, "node_modules/write-file-atomic": { "version": "5.0.1", @@ -14494,7 +14342,6 @@ "integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==", "dev": true, "license": "ISC", - "peer": true, "dependencies": { "imurmurhash": "^0.1.4", "signal-exit": "^4.0.1" @@ -14636,6 +14483,7 @@ "resolved": "https://registry.npmjs.org/zod/-/zod-4.1.13.tgz", "integrity": "sha512-AvvthqfqrAhNH9dnfmrfKzX5upOdjUVJYFqNSlkmGf64gRaTzlPwz99IHYnVs28qYAybvAlBV+H7pn0saFY4Ig==", "license": "MIT", + "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/package.json b/package.json index 8740505a..3a921d9f 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "install": "^0.13.0", "ioredis": "^5.8.2", "mobx": "^6.15.0", - "next": "16.0.7", + "next": "16.0.10", "next-auth": "^5.0.0-beta.30", "npm": "^11.6.4", "nprogress": "^0.2.0", From dbbef7926abaf02728e86acf6b5515f2cd10691d Mon Sep 17 00:00:00 2001 From: Ulrik Andersen Date: Fri, 12 Dec 2025 11:22:57 +0100 Subject: [PATCH 08/15] fix: refresh projects when window regains focus (#639) Previously only listened to visibilitychange which fires on tab switch but not when alt-tabbing back from another application. Now also listens to window focus event. --- src/features/projects/view/ProjectsContextProvider.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/features/projects/view/ProjectsContextProvider.tsx b/src/features/projects/view/ProjectsContextProvider.tsx index e680ad57..c29683c2 100644 --- a/src/features/projects/view/ProjectsContextProvider.tsx +++ b/src/features/projects/view/ProjectsContextProvider.tsx @@ -47,8 +47,10 @@ useEffect(() => { if (!document.hidden) refreshProjects(); }; document.addEventListener("visibilitychange", handleVisibilityChange); + window.addEventListener("focus", refreshProjects); return () => { document.removeEventListener("visibilitychange", handleVisibilityChange); + window.removeEventListener("focus", refreshProjects); window.clearTimeout(timeout); }; }, [refreshProjects]); From 5e00eccfa615178cf6e9a996cef4e9310be530a3 Mon Sep 17 00:00:00 2001 From: Ulrik Andersen Date: Fri, 12 Dec 2025 13:11:58 +0100 Subject: [PATCH 09/15] feat: add loading indicator when refreshing projects (#640) Show a subtle spinner in the sidebar header when projects and versions are being refreshed, with a tooltip explaining the action. --- .../sidebar/view/internal/sidebar/Header.tsx | 61 ++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/src/features/sidebar/view/internal/sidebar/Header.tsx b/src/features/sidebar/view/internal/sidebar/Header.tsx index 3c17d48c..3b6a2258 100644 --- a/src/features/sidebar/view/internal/sidebar/Header.tsx +++ b/src/features/sidebar/view/internal/sidebar/Header.tsx @@ -1,14 +1,48 @@ "use client" +import { useContext, useEffect, useRef, useState } from "react" import Image from "next/image" -import { Box, Button, Typography } from "@mui/material" +import { Box, Button, CircularProgress, Tooltip, Typography } from "@mui/material" +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome" +import { faCheck } from "@fortawesome/free-solid-svg-icons" import { useRouter } from "next/navigation" import * as NProgress from "nprogress" +import { ProjectsContext } from "@/common" import { useCloseSidebarOnSelection } from "@/features/sidebar/data" const Header = ({ siteName }: { siteName?: string }) => { const router = useRouter() const { closeSidebarIfNeeded } = useCloseSidebarOnSelection() + const { refreshing } = useContext(ProjectsContext) + const [showCheck, setShowCheck] = useState(false) + const [fadeOut, setFadeOut] = useState(false) + const wasRefreshing = useRef(false) + + useEffect(() => { + if (refreshing) { + // Clear any existing checkmark when a new refresh starts + const clearTimeout_ = setTimeout(() => { + setShowCheck(false) + setFadeOut(false) + }, 0) + wasRefreshing.current = true + return () => clearTimeout(clearTimeout_) + } else if (wasRefreshing.current) { + wasRefreshing.current = false + // Delay checkmark appearance to let spinner fade out first + const showTimeout = setTimeout(() => { + setShowCheck(true) + setFadeOut(false) + }, 400) + const fadeTimeout = setTimeout(() => setFadeOut(true), 1600) + const hideTimeout = setTimeout(() => setShowCheck(false), 2200) + return () => { + clearTimeout(showTimeout) + clearTimeout(fadeTimeout) + clearTimeout(hideTimeout) + } + } + }, [refreshing]) return ( { {siteName} + + + + + + + + + + ) } From dc6199547c644b9cc6b234ce912ac8f2447278c1 Mon Sep 17 00:00:00 2001 From: Ulrik Andersen Date: Fri, 19 Dec 2025 10:44:51 +0100 Subject: [PATCH 10/15] fix: preserve scroll position when projects refresh The encrypted URLs for remote specs contain random IVs, causing different ciphertext on each refresh. This triggered unnecessary state updates and re-renders, resetting the documentation viewer's scroll position. Add urlHash field computed from underlying remote config, and compare projects by fingerprint (urlHash for remote specs, URL for others). --- __test__/projects/GitHubProjectDataSource.test.ts | 7 +++++++ .../projects/data/GitHubProjectDataSource.ts | 4 ++++ .../projects/domain/OpenApiSpecification.ts | 1 + .../projects/view/ProjectsContextProvider.tsx | 13 +++++++------ 4 files changed, 19 insertions(+), 6 deletions(-) diff --git a/__test__/projects/GitHubProjectDataSource.test.ts b/__test__/projects/GitHubProjectDataSource.test.ts index 12438c76..586375bc 100644 --- a/__test__/projects/GitHubProjectDataSource.test.ts +++ b/__test__/projects/GitHubProjectDataSource.test.ts @@ -845,11 +845,13 @@ test("It adds remote versions from the project configuration", async () => { id: "huey", name: "Huey", url: `/api/remotes/${base64RemoteConfigEncoder.encode({ url: "https://example.com/huey.yml" })}`, + urlHash: "89ba381286214eec", isDefault: false }, { id: "dewey", name: "Dewey", url: `/api/remotes/${base64RemoteConfigEncoder.encode({ url: "https://example.com/dewey.yml" })}`, + urlHash: "8f810fff152505f6", isDefault: false }] }, { @@ -860,6 +862,7 @@ test("It adds remote versions from the project configuration", async () => { id: "louie", name: "Louie", url: `/api/remotes/${base64RemoteConfigEncoder.encode({ url: "https://example.com/louie.yml" })}`, + urlHash: "b83ebf43ceede6bc", isDefault: false }] }]) @@ -925,6 +928,7 @@ test("It modifies ID of remote version if the ID already exists", async () => { id: "baz", name: "Baz", url: `/api/remotes/${base64RemoteConfigEncoder.encode({ url: "https://example.com/baz.yml" })}`, + urlHash: "25cb42ff63570cb5", isDefault: false }] }, { @@ -935,6 +939,7 @@ test("It modifies ID of remote version if the ID already exists", async () => { id: "hello", name: "Hello", url: `/api/remotes/${base64RemoteConfigEncoder.encode({ url: "https://example.com/hello.yml" })}`, + urlHash: "d078bd689699d1f0", isDefault: false }] }]) @@ -979,6 +984,7 @@ test("It lets users specify the ID of a remote version", async () => { id: "baz", name: "Baz", url: `/api/remotes/${base64RemoteConfigEncoder.encode({ url: "https://example.com/baz.yml" })}`, + urlHash: "25cb42ff63570cb5", isDefault: false }] }]) @@ -1023,6 +1029,7 @@ test("It lets users specify the ID of a remote specification", async () => { id: "some-spec", name: "Baz", url: `/api/remotes/${base64RemoteConfigEncoder.encode({ url: "https://example.com/baz.yml" })}`, + urlHash: "25cb42ff63570cb5", isDefault: false }] }]) diff --git a/src/features/projects/data/GitHubProjectDataSource.ts b/src/features/projects/data/GitHubProjectDataSource.ts index 17086513..8a8402d2 100644 --- a/src/features/projects/data/GitHubProjectDataSource.ts +++ b/src/features/projects/data/GitHubProjectDataSource.ts @@ -1,3 +1,4 @@ +import { createHash } from "crypto" import { IEncryptionService } from "@/features/encrypt/EncryptionService" import { Project, @@ -185,11 +186,14 @@ export default class GitHubProjectDataSource implements IProjectDataSource { }; const encodedRemoteConfig = this.remoteConfigEncoder.encode(remoteConfig); + // 16 hex chars (64 bits) - sufficient for change detection, not cryptographic security + const configHash = createHash("sha256").update(JSON.stringify(remoteConfig)).digest("hex").slice(0, 16); return { id: this.makeURLSafeID((e.id || e.name).toLowerCase()), name: e.name, url: `/api/remotes/${encodedRemoteConfig}`, + urlHash: configHash, isDefault: false // initial value }; }) diff --git a/src/features/projects/domain/OpenApiSpecification.ts b/src/features/projects/domain/OpenApiSpecification.ts index b0c3bfa5..c3252969 100644 --- a/src/features/projects/domain/OpenApiSpecification.ts +++ b/src/features/projects/domain/OpenApiSpecification.ts @@ -4,6 +4,7 @@ export const OpenApiSpecificationSchema = z.object({ id: z.string(), name: z.string(), url: z.string(), + urlHash: z.string().optional(), editURL: z.string().optional(), isDefault: z.boolean() }) diff --git a/src/features/projects/view/ProjectsContextProvider.tsx b/src/features/projects/view/ProjectsContextProvider.tsx index e680ad57..0e3731d5 100644 --- a/src/features/projects/view/ProjectsContextProvider.tsx +++ b/src/features/projects/view/ProjectsContextProvider.tsx @@ -15,10 +15,9 @@ const ProjectsContextProvider = ({ const [refreshing, setRefreshing] = useState(false); const isLoadingRef = useRef(false); - - const setProjectsAndRefreshed = (value: Project[]) => { - setProjects(value); - }; + // Fingerprint uses urlHash for remote specs (stable), URL for others (already stable) + const fingerprint = (list: Project[]) => + list.flatMap(p => p.versions.flatMap(v => v.specifications.map(s => s.urlHash ?? s.url))).sort().join(); const refreshProjects = useCallback(() => { if (isLoadingRef.current) return; @@ -26,8 +25,10 @@ const refreshProjects = useCallback(() => { setRefreshing(true); fetch("/api/refresh-projects", { method: "POST" }) .then((res) => res.json()) - .then(({ projects }) => { - if (projects) setProjectsAndRefreshed(projects); + .then(({ projects: newProjects }) => { + if (newProjects) { + setProjects(prev => fingerprint(prev) === fingerprint(newProjects) ? prev : newProjects); + } }) .catch((error) => console.error("Failed to refresh projects", error)) .finally(() => { From f897e1ff4fadd565709c5129a05d05143fe216fb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Jan 2026 07:03:04 +0000 Subject: [PATCH 11/15] Bump the react group with 2 updates Bumps the react group with 2 updates: [react](https://github.com/facebook/react/tree/HEAD/packages/react) and [react-dom](https://github.com/facebook/react/tree/HEAD/packages/react-dom). Updates `react` from 19.2.0 to 19.2.3 - [Release notes](https://github.com/facebook/react/releases) - [Changelog](https://github.com/facebook/react/blob/main/CHANGELOG.md) - [Commits](https://github.com/facebook/react/commits/v19.2.3/packages/react) Updates `react-dom` from 19.2.0 to 19.2.3 - [Release notes](https://github.com/facebook/react/releases) - [Changelog](https://github.com/facebook/react/blob/main/CHANGELOG.md) - [Commits](https://github.com/facebook/react/commits/v19.2.3/packages/react-dom) --- updated-dependencies: - dependency-name: react dependency-version: 19.2.3 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: react - dependency-name: react-dom dependency-version: 19.2.3 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: react ... Signed-off-by: dependabot[bot] --- package-lock.json | 18 +++++++++--------- package.json | 4 ++-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/package-lock.json b/package-lock.json index eaaad053..48d0bd58 100644 --- a/package-lock.json +++ b/package-lock.json @@ -32,8 +32,8 @@ "npm": "^11.6.4", "nprogress": "^0.2.0", "octokit": "^5.0.5", - "react": "^19.2.0", - "react-dom": "^19.2.0", + "react": "^19.2.3", + "react-dom": "^19.2.3", "redis-semaphore": "^5.6.2", "redoc": "^2.5.2", "sharp": "^0.34.2", @@ -12172,9 +12172,9 @@ "license": "MIT" }, "node_modules/react": { - "version": "19.2.0", - "resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz", - "integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==", + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.3.tgz", + "integrity": "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==", "license": "MIT", "peer": true, "engines": { @@ -12182,16 +12182,16 @@ } }, "node_modules/react-dom": { - "version": "19.2.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz", - "integrity": "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==", + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==", "license": "MIT", "peer": true, "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { - "react": "^19.2.0" + "react": "^19.2.3" } }, "node_modules/react-is": { diff --git a/package.json b/package.json index 3a921d9f..f17f6497 100644 --- a/package.json +++ b/package.json @@ -39,8 +39,8 @@ "npm": "^11.6.4", "nprogress": "^0.2.0", "octokit": "^5.0.5", - "react": "^19.2.0", - "react-dom": "^19.2.0", + "react": "^19.2.3", + "react-dom": "^19.2.3", "redis-semaphore": "^5.6.2", "redoc": "^2.5.2", "sharp": "^0.34.2", From 0f61d0c8d1ae92cd999c6458f314dc026c3dfe95 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Jan 2026 07:06:34 +0000 Subject: [PATCH 12/15] Bump the everything-else group with 17 updates Bumps the everything-else group with 17 updates: | Package | From | To | | --- | --- | --- | | [@mui/icons-material](https://github.com/mui/material-ui/tree/HEAD/packages/mui-icons-material) | `7.3.5` | `7.3.6` | | [@mui/material](https://github.com/mui/material-ui/tree/HEAD/packages/mui-material) | `7.3.5` | `7.3.6` | | [@octokit/webhooks](https://github.com/octokit/webhooks.js) | `14.1.3` | `14.2.0` | | [next](https://github.com/vercel/next.js) | `16.0.10` | `16.1.1` | | [npm](https://github.com/npm/cli) | `11.6.4` | `11.7.0` | | [swr](https://github.com/vercel/swr) | `2.3.7` | `2.3.8` | | [zod](https://github.com/colinhacks/zod) | `4.1.13` | `4.3.4` | | [@tailwindcss/postcss](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/@tailwindcss-postcss) | `4.1.17` | `4.1.18` | | [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) | `24.10.1` | `25.0.3` | | [@types/pg](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/pg) | `8.15.6` | `8.16.0` | | [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) | `8.48.0` | `8.51.0` | | [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) | `8.48.0` | `8.51.0` | | [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint) | `8.48.0` | `8.51.0` | | [eslint](https://github.com/eslint/eslint) | `9.39.1` | `9.39.2` | | [eslint-config-next](https://github.com/vercel/next.js/tree/HEAD/packages/eslint-config-next) | `16.0.6` | `16.1.1` | | [tailwindcss](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss) | `4.1.17` | `4.1.18` | | [ts-jest](https://github.com/kulshekhar/ts-jest) | `29.4.5` | `29.4.6` | Updates `@mui/icons-material` from 7.3.5 to 7.3.6 - [Release notes](https://github.com/mui/material-ui/releases) - [Changelog](https://github.com/mui/material-ui/blob/master/CHANGELOG.md) - [Commits](https://github.com/mui/material-ui/commits/v7.3.6/packages/mui-icons-material) Updates `@mui/material` from 7.3.5 to 7.3.6 - [Release notes](https://github.com/mui/material-ui/releases) - [Changelog](https://github.com/mui/material-ui/blob/master/CHANGELOG.md) - [Commits](https://github.com/mui/material-ui/commits/v7.3.6/packages/mui-material) Updates `@octokit/webhooks` from 14.1.3 to 14.2.0 - [Release notes](https://github.com/octokit/webhooks.js/releases) - [Commits](https://github.com/octokit/webhooks.js/compare/v14.1.3...v14.2.0) Updates `next` from 16.0.10 to 16.1.1 - [Release notes](https://github.com/vercel/next.js/releases) - [Changelog](https://github.com/vercel/next.js/blob/canary/release.js) - [Commits](https://github.com/vercel/next.js/compare/v16.0.10...v16.1.1) Updates `npm` from 11.6.4 to 11.7.0 - [Release notes](https://github.com/npm/cli/releases) - [Changelog](https://github.com/npm/cli/blob/latest/CHANGELOG.md) - [Commits](https://github.com/npm/cli/compare/v11.6.4...v11.7.0) Updates `swr` from 2.3.7 to 2.3.8 - [Release notes](https://github.com/vercel/swr/releases) - [Commits](https://github.com/vercel/swr/compare/v2.3.7...v2.3.8) Updates `zod` from 4.1.13 to 4.3.4 - [Release notes](https://github.com/colinhacks/zod/releases) - [Commits](https://github.com/colinhacks/zod/compare/v4.1.13...v4.3.4) Updates `@tailwindcss/postcss` from 4.1.17 to 4.1.18 - [Release notes](https://github.com/tailwindlabs/tailwindcss/releases) - [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md) - [Commits](https://github.com/tailwindlabs/tailwindcss/commits/v4.1.18/packages/@tailwindcss-postcss) Updates `@types/node` from 24.10.1 to 25.0.3 - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node) Updates `@types/pg` from 8.15.6 to 8.16.0 - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/pg) Updates `@typescript-eslint/eslint-plugin` from 8.48.0 to 8.51.0 - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.51.0/packages/eslint-plugin) Updates `@typescript-eslint/parser` from 8.48.0 to 8.51.0 - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.51.0/packages/parser) Updates `typescript-eslint` from 8.48.0 to 8.51.0 - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.51.0/packages/typescript-eslint) Updates `eslint` from 9.39.1 to 9.39.2 - [Release notes](https://github.com/eslint/eslint/releases) - [Commits](https://github.com/eslint/eslint/compare/v9.39.1...v9.39.2) Updates `eslint-config-next` from 16.0.6 to 16.1.1 - [Release notes](https://github.com/vercel/next.js/releases) - [Changelog](https://github.com/vercel/next.js/blob/canary/release.js) - [Commits](https://github.com/vercel/next.js/commits/v16.1.1/packages/eslint-config-next) Updates `tailwindcss` from 4.1.17 to 4.1.18 - [Release notes](https://github.com/tailwindlabs/tailwindcss/releases) - [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md) - [Commits](https://github.com/tailwindlabs/tailwindcss/commits/v4.1.18/packages/tailwindcss) Updates `ts-jest` from 29.4.5 to 29.4.6 - [Release notes](https://github.com/kulshekhar/ts-jest/releases) - [Changelog](https://github.com/kulshekhar/ts-jest/blob/main/CHANGELOG.md) - [Commits](https://github.com/kulshekhar/ts-jest/compare/v29.4.5...v29.4.6) --- updated-dependencies: - dependency-name: "@mui/icons-material" dependency-version: 7.3.6 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: everything-else - dependency-name: "@mui/material" dependency-version: 7.3.6 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: everything-else - dependency-name: "@octokit/webhooks" dependency-version: 14.2.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: everything-else - dependency-name: next dependency-version: 16.1.1 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: everything-else - dependency-name: npm dependency-version: 11.7.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: everything-else - dependency-name: swr dependency-version: 2.3.8 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: everything-else - dependency-name: zod dependency-version: 4.3.4 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: everything-else - dependency-name: "@tailwindcss/postcss" dependency-version: 4.1.18 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: everything-else - dependency-name: "@types/node" dependency-version: 25.0.3 dependency-type: direct:development update-type: version-update:semver-major dependency-group: everything-else - dependency-name: "@types/pg" dependency-version: 8.16.0 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: everything-else - dependency-name: "@typescript-eslint/eslint-plugin" dependency-version: 8.51.0 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: everything-else - dependency-name: "@typescript-eslint/parser" dependency-version: 8.51.0 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: everything-else - dependency-name: typescript-eslint dependency-version: 8.51.0 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: everything-else - dependency-name: eslint dependency-version: 9.39.2 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: everything-else - dependency-name: eslint-config-next dependency-version: 16.1.1 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: everything-else - dependency-name: tailwindcss dependency-version: 4.1.18 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: everything-else - dependency-name: ts-jest dependency-version: 29.4.6 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: everything-else ... Signed-off-by: dependabot[bot] --- package-lock.json | 598 +++++++++++++++++++++++----------------------- package.json | 30 +-- 2 files changed, 310 insertions(+), 318 deletions(-) diff --git a/package-lock.json b/package-lock.json index eaaad053..9df995a1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,20 +16,20 @@ "@fortawesome/free-regular-svg-icons": "^7.1.0", "@fortawesome/free-solid-svg-icons": "^7.1.0", "@fortawesome/react-fontawesome": "^3.1.1", - "@mui/icons-material": "^7.3.5", + "@mui/icons-material": "^7.3.6", "@mui/material": "^7.0.1", "@octokit/auth-app": "^8.1.2", "@octokit/core": "^7.0.6", - "@octokit/webhooks": "~14.1.3", + "@octokit/webhooks": "~14.2.0", "core-js": "^3.47.0", "encoding": "^0.1.13", "figma-squircle": "^1.1.0", "install": "^0.13.0", "ioredis": "^5.8.2", "mobx": "^6.15.0", - "next": "16.0.10", + "next": "16.1.1", "next-auth": "^5.0.0-beta.30", - "npm": "^11.6.4", + "npm": "^11.7.0", "nprogress": "^0.2.0", "octokit": "^5.0.5", "react": "^19.2.0", @@ -38,30 +38,30 @@ "redoc": "^2.5.2", "sharp": "^0.34.2", "styled-components": "^6.1.19", - "swr": "^2.3.7", + "swr": "^2.3.8", "usehooks-ts": "^3.1.1", "yaml": "^2.8.2", - "zod": "^4.1.13" + "zod": "^4.3.4" }, "devDependencies": { "@auth/pg-adapter": "^1.11.1", - "@tailwindcss/postcss": "^4.1.17", + "@tailwindcss/postcss": "^4.1.18", "@types/jest": "^30.0.0", - "@types/node": "^24.10.1", + "@types/node": "^25.0.3", "@types/nprogress": "^0.2.3", - "@types/pg": "^8.15.6", + "@types/pg": "^8.16.0", "@types/react": "^19.2.7", "@types/react-dom": "^19.2.3", - "@typescript-eslint/eslint-plugin": "^8.48.0", - "@typescript-eslint/parser": "^8.48.0", - "eslint": "^9.39.1", - "eslint-config-next": "^16.0.6", + "@typescript-eslint/eslint-plugin": "^8.51.0", + "@typescript-eslint/parser": "^8.51.0", + "eslint": "^9.39.2", + "eslint-config-next": "^16.1.1", "pg": "^8.16.3", "postcss": "^8.5.6", "tailwindcss": "^4.1.4", - "ts-jest": "^29.4.5", + "ts-jest": "^29.4.6", "typescript": "^5.9.3", - "typescript-eslint": "^8.48.0" + "typescript-eslint": "^8.51.0" }, "engines": { "node": ">=24.0.0 <25.0.0", @@ -981,9 +981,9 @@ } }, "node_modules/@eslint/js": { - "version": "9.39.1", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.1.tgz", - "integrity": "sha512-S26Stp4zCy88tH94QbBv3XCuzRQiZ9yXofEILmglYTh/Ug/a9/umqvgFtYBAo3Lp0nsI/5/qH1CCrbdK3AP1Tw==", + "version": "9.39.2", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.2.tgz", + "integrity": "sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==", "dev": true, "license": "MIT", "engines": { @@ -2157,9 +2157,9 @@ } }, "node_modules/@mui/core-downloads-tracker": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-7.3.5.tgz", - "integrity": "sha512-kOLwlcDPnVz2QMhiBv0OQ8le8hTCqKM9cRXlfVPL91l3RGeOsxrIhNRsUt3Xb8wb+pTVUolW+JXKym93vRKxCw==", + "version": "7.3.6", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-7.3.6.tgz", + "integrity": "sha512-QaYtTHlr8kDFN5mE1wbvVARRKH7Fdw1ZuOjBJcFdVpfNfRYKF3QLT4rt+WaB6CKJvpqxRsmEo0kpYinhH5GeHg==", "license": "MIT", "funding": { "type": "opencollective", @@ -2167,9 +2167,9 @@ } }, "node_modules/@mui/icons-material": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-7.3.5.tgz", - "integrity": "sha512-LciL1GLMZ+VlzyHAALSVAR22t8IST4LCXmljcUSx2NOutgO2XnxdIp8ilFbeNf9wpo0iUFbAuoQcB7h+HHIf3A==", + "version": "7.3.6", + "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-7.3.6.tgz", + "integrity": "sha512-0FfkXEj22ysIq5pa41A2NbcAhJSvmcZQ/vcTIbjDsd6hlslG82k5BEBqqS0ZJprxwIL3B45qpJ+bPHwJPlF7uQ==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.28.4" @@ -2182,7 +2182,7 @@ "url": "https://opencollective.com/mui-org" }, "peerDependencies": { - "@mui/material": "^7.3.5", + "@mui/material": "^7.3.6", "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", "react": "^17.0.0 || ^18.0.0 || ^19.0.0" }, @@ -2193,17 +2193,17 @@ } }, "node_modules/@mui/material": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/@mui/material/-/material-7.3.5.tgz", - "integrity": "sha512-8VVxFmp1GIm9PpmnQoCoYo0UWHoOrdA57tDL62vkpzEgvb/d71Wsbv4FRg7r1Gyx7PuSo0tflH34cdl/NvfHNQ==", + "version": "7.3.6", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-7.3.6.tgz", + "integrity": "sha512-R4DaYF3dgCQCUAkr4wW1w26GHXcf5rCmBRHVBuuvJvaGLmZdD8EjatP80Nz5JCw0KxORAzwftnHzXVnjR8HnFw==", "license": "MIT", "peer": true, "dependencies": { "@babel/runtime": "^7.28.4", - "@mui/core-downloads-tracker": "^7.3.5", - "@mui/system": "^7.3.5", - "@mui/types": "^7.4.8", - "@mui/utils": "^7.3.5", + "@mui/core-downloads-tracker": "^7.3.6", + "@mui/system": "^7.3.6", + "@mui/types": "^7.4.9", + "@mui/utils": "^7.3.6", "@popperjs/core": "^2.11.8", "@types/react-transition-group": "^4.4.12", "clsx": "^2.1.1", @@ -2222,7 +2222,7 @@ "peerDependencies": { "@emotion/react": "^11.5.0", "@emotion/styled": "^11.3.0", - "@mui/material-pigment-css": "^7.3.5", + "@mui/material-pigment-css": "^7.3.6", "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", "react": "^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" @@ -2243,13 +2243,13 @@ } }, "node_modules/@mui/private-theming": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-7.3.5.tgz", - "integrity": "sha512-cTx584W2qrLonwhZLbEN7P5pAUu0nZblg8cLBlTrZQ4sIiw8Fbvg7GvuphQaSHxPxrCpa7FDwJKtXdbl2TSmrA==", + "version": "7.3.6", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-7.3.6.tgz", + "integrity": "sha512-Ws9wZpqM+FlnbZXaY/7yvyvWQo1+02Tbx50mVdNmzWEi51C51y56KAbaDCYyulOOBL6BJxuaqG8rNNuj7ivVyw==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.28.4", - "@mui/utils": "^7.3.5", + "@mui/utils": "^7.3.6", "prop-types": "^15.8.1" }, "engines": { @@ -2270,9 +2270,9 @@ } }, "node_modules/@mui/styled-engine": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-7.3.5.tgz", - "integrity": "sha512-zbsZ0uYYPndFCCPp2+V3RLcAN6+fv4C8pdwRx6OS3BwDkRCN8WBehqks7hWyF3vj1kdQLIWrpdv/5Y0jHRxYXQ==", + "version": "7.3.6", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-7.3.6.tgz", + "integrity": "sha512-+wiYbtvj+zyUkmDB+ysH6zRjuQIJ+CM56w0fEXV+VDNdvOuSywG+/8kpjddvvlfMLsaWdQe5oTuYGBcodmqGzQ==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.28.4", @@ -2304,16 +2304,16 @@ } }, "node_modules/@mui/system": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/@mui/system/-/system-7.3.5.tgz", - "integrity": "sha512-yPaf5+gY3v80HNkJcPi6WT+r9ebeM4eJzrREXPxMt7pNTV/1eahyODO4fbH3Qvd8irNxDFYn5RQ3idHW55rA6g==", + "version": "7.3.6", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-7.3.6.tgz", + "integrity": "sha512-8fehAazkHNP1imMrdD2m2hbA9sl7Ur6jfuNweh5o4l9YPty4iaZzRXqYvBCWQNwFaSHmMEj2KPbyXGp7Bt73Rg==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.28.4", - "@mui/private-theming": "^7.3.5", - "@mui/styled-engine": "^7.3.5", - "@mui/types": "^7.4.8", - "@mui/utils": "^7.3.5", + "@mui/private-theming": "^7.3.6", + "@mui/styled-engine": "^7.3.6", + "@mui/types": "^7.4.9", + "@mui/utils": "^7.3.6", "clsx": "^2.1.1", "csstype": "^3.1.3", "prop-types": "^15.8.1" @@ -2344,9 +2344,9 @@ } }, "node_modules/@mui/types": { - "version": "7.4.8", - "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.4.8.tgz", - "integrity": "sha512-ZNXLBjkPV6ftLCmmRCafak3XmSn8YV0tKE/ZOhzKys7TZXUiE0mZxlH8zKDo6j6TTUaDnuij68gIG+0Ucm7Xhw==", + "version": "7.4.9", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.4.9.tgz", + "integrity": "sha512-dNO8Z9T2cujkSIaCnWwprfeKmTWh97cnjkgmpFJ2sbfXLx8SMZijCYHOtP/y5nnUb/Rm2omxbDMmtUoSaUtKaw==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.28.4" @@ -2361,13 +2361,13 @@ } }, "node_modules/@mui/utils": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-7.3.5.tgz", - "integrity": "sha512-jisvFsEC3sgjUjcPnR4mYfhzjCDIudttSGSbe1o/IXFNu0kZuR+7vqQI0jg8qtcVZBHWrwTfvAZj9MNMumcq1g==", + "version": "7.3.6", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-7.3.6.tgz", + "integrity": "sha512-jn+Ba02O6PiFs7nKva8R2aJJ9kJC+3kQ2R0BbKNY3KQQ36Qng98GnPRFTlbwYTdMD6hLEBKaMLUktyg/rTfd2w==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.28.4", - "@mui/types": "^7.4.8", + "@mui/types": "^7.4.9", "@types/prop-types": "^15.7.15", "clsx": "^2.1.1", "prop-types": "^15.8.1", @@ -2404,15 +2404,15 @@ } }, "node_modules/@next/env": { - "version": "16.0.10", - "resolved": "https://registry.npmjs.org/@next/env/-/env-16.0.10.tgz", - "integrity": "sha512-8tuaQkyDVgeONQ1MeT9Mkk8pQmZapMKFh5B+OrFUlG3rVmYTXcXlBetBgTurKXGaIZvkoqRT9JL5K3phXcgang==", + "version": "16.1.1", + "resolved": "https://registry.npmjs.org/@next/env/-/env-16.1.1.tgz", + "integrity": "sha512-3oxyM97Sr2PqiVyMyrZUtrtM3jqqFxOQJVuKclDsgj/L728iZt/GyslkN4NwarledZATCenbk4Offjk1hQmaAA==", "license": "MIT" }, "node_modules/@next/eslint-plugin-next": { - "version": "16.0.6", - "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-16.0.6.tgz", - "integrity": "sha512-9INsBF3/4XL0/tON8AGsh0svnTtDMLwv3iREGWnWkewGdOnd790tguzq9rX8xwrVthPyvaBHhw1ww0GZz0jO5Q==", + "version": "16.1.1", + "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-16.1.1.tgz", + "integrity": "sha512-Ovb/6TuLKbE1UiPcg0p39Ke3puyTCIKN9hGbNItmpQsp+WX3qrjO3WaMVSi6JHr9X1NrmthqIguVHodMJbh/dw==", "dev": true, "license": "MIT", "dependencies": { @@ -2420,9 +2420,9 @@ } }, "node_modules/@next/swc-darwin-arm64": { - "version": "16.0.10", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.0.10.tgz", - "integrity": "sha512-4XgdKtdVsaflErz+B5XeG0T5PeXKDdruDf3CRpnhN+8UebNa5N2H58+3GDgpn/9GBurrQ1uWW768FfscwYkJRg==", + "version": "16.1.1", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.1.1.tgz", + "integrity": "sha512-JS3m42ifsVSJjSTzh27nW+Igfha3NdBOFScr9C80hHGrWx55pTrVL23RJbqir7k7/15SKlrLHhh/MQzqBBYrQA==", "cpu": [ "arm64" ], @@ -2436,9 +2436,9 @@ } }, "node_modules/@next/swc-darwin-x64": { - "version": "16.0.10", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.0.10.tgz", - "integrity": "sha512-spbEObMvRKkQ3CkYVOME+ocPDFo5UqHb8EMTS78/0mQ+O1nqE8toHJVioZo4TvebATxgA8XMTHHrScPrn68OGw==", + "version": "16.1.1", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.1.1.tgz", + "integrity": "sha512-hbyKtrDGUkgkyQi1m1IyD3q4I/3m9ngr+V93z4oKHrPcmxwNL5iMWORvLSGAf2YujL+6HxgVvZuCYZfLfb4bGw==", "cpu": [ "x64" ], @@ -2452,9 +2452,9 @@ } }, "node_modules/@next/swc-linux-arm64-gnu": { - "version": "16.0.10", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.0.10.tgz", - "integrity": "sha512-uQtWE3X0iGB8apTIskOMi2w/MKONrPOUCi5yLO+v3O8Mb5c7K4Q5KD1jvTpTF5gJKa3VH/ijKjKUq9O9UhwOYw==", + "version": "16.1.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.1.1.tgz", + "integrity": "sha512-/fvHet+EYckFvRLQ0jPHJCUI5/B56+2DpI1xDSvi80r/3Ez+Eaa2Yq4tJcRTaB1kqj/HrYKn8Yplm9bNoMJpwQ==", "cpu": [ "arm64" ], @@ -2468,9 +2468,9 @@ } }, "node_modules/@next/swc-linux-arm64-musl": { - "version": "16.0.10", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.0.10.tgz", - "integrity": "sha512-llA+hiDTrYvyWI21Z0L1GiXwjQaanPVQQwru5peOgtooeJ8qx3tlqRV2P7uH2pKQaUfHxI/WVarvI5oYgGxaTw==", + "version": "16.1.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.1.1.tgz", + "integrity": "sha512-MFHrgL4TXNQbBPzkKKur4Fb5ICEJa87HM7fczFs2+HWblM7mMLdco3dvyTI+QmLBU9xgns/EeeINSZD6Ar+oLg==", "cpu": [ "arm64" ], @@ -2484,9 +2484,9 @@ } }, "node_modules/@next/swc-linux-x64-gnu": { - "version": "16.0.10", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.0.10.tgz", - "integrity": "sha512-AK2q5H0+a9nsXbeZ3FZdMtbtu9jxW4R/NgzZ6+lrTm3d6Zb7jYrWcgjcpM1k8uuqlSy4xIyPR2YiuUr+wXsavA==", + "version": "16.1.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.1.1.tgz", + "integrity": "sha512-20bYDfgOQAPUkkKBnyP9PTuHiJGM7HzNBbuqmD0jiFVZ0aOldz+VnJhbxzjcSabYsnNjMPsE0cyzEudpYxsrUQ==", "cpu": [ "x64" ], @@ -2500,9 +2500,9 @@ } }, "node_modules/@next/swc-linux-x64-musl": { - "version": "16.0.10", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.0.10.tgz", - "integrity": "sha512-1TDG9PDKivNw5550S111gsO4RGennLVl9cipPhtkXIFVwo31YZ73nEbLjNC8qG3SgTz/QZyYyaFYMeY4BKZR/g==", + "version": "16.1.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.1.1.tgz", + "integrity": "sha512-9pRbK3M4asAHQRkwaXwu601oPZHghuSC8IXNENgbBSyImHv/zY4K5udBusgdHkvJ/Tcr96jJwQYOll0qU8+fPA==", "cpu": [ "x64" ], @@ -2516,9 +2516,9 @@ } }, "node_modules/@next/swc-win32-arm64-msvc": { - "version": "16.0.10", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.0.10.tgz", - "integrity": "sha512-aEZIS4Hh32xdJQbHz121pyuVZniSNoqDVx1yIr2hy+ZwJGipeqnMZBJHyMxv2tiuAXGx6/xpTcQJ6btIiBjgmg==", + "version": "16.1.1", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.1.1.tgz", + "integrity": "sha512-bdfQkggaLgnmYrFkSQfsHfOhk/mCYmjnrbRCGgkMcoOBZ4n+TRRSLmT/CU5SATzlBJ9TpioUyBW/vWFXTqQRiA==", "cpu": [ "arm64" ], @@ -2532,9 +2532,9 @@ } }, "node_modules/@next/swc-win32-x64-msvc": { - "version": "16.0.10", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.0.10.tgz", - "integrity": "sha512-E+njfCoFLb01RAFEnGZn6ERoOqhK1Gl3Lfz1Kjnj0Ulfu7oJbuMyvBKNj/bw8XZnenHDASlygTjZICQW+rYW1Q==", + "version": "16.1.1", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.1.1.tgz", + "integrity": "sha512-Ncwbw2WJ57Al5OX0k4chM68DKhEPlrXBaSXDCi2kPi5f4d8b3ejr3RRJGfKBLrn2YJL5ezNS7w2TZLHSti8CMw==", "cpu": [ "x64" ], @@ -2797,9 +2797,9 @@ "license": "MIT" }, "node_modules/@octokit/openapi-webhooks-types": { - "version": "12.0.3", - "resolved": "https://registry.npmjs.org/@octokit/openapi-webhooks-types/-/openapi-webhooks-types-12.0.3.tgz", - "integrity": "sha512-90MF5LVHjBedwoHyJsgmaFhEN1uzXyBDRLEBe7jlTYx/fEhPAk3P3DAJsfZwC54m8hAIryosJOL+UuZHB3K3yA==", + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-webhooks-types/-/openapi-webhooks-types-12.1.0.tgz", + "integrity": "sha512-WiuzhOsiOvb7W3Pvmhf8d2C6qaLHXrWiLBP4nJ/4kydu+wpagV5Fkz9RfQwV2afYzv3PB+3xYgp4mAdNGjDprA==", "license": "MIT" }, "node_modules/@octokit/plugin-paginate-graphql": { @@ -2915,12 +2915,12 @@ } }, "node_modules/@octokit/webhooks": { - "version": "14.1.3", - "resolved": "https://registry.npmjs.org/@octokit/webhooks/-/webhooks-14.1.3.tgz", - "integrity": "sha512-gcK4FNaROM9NjA0mvyfXl0KPusk7a1BeA8ITlYEZVQCXF5gcETTd4yhAU0Kjzd8mXwYHppzJBWgdBVpIR9wUcQ==", + "version": "14.2.0", + "resolved": "https://registry.npmjs.org/@octokit/webhooks/-/webhooks-14.2.0.tgz", + "integrity": "sha512-da6KbdNCV5sr1/txD896V+6W0iamFWrvVl8cHkBSPT+YlvmT3DwXa4jxZnQc+gnuTEqSWbBeoSZYTayXH9wXcw==", "license": "MIT", "dependencies": { - "@octokit/openapi-webhooks-types": "12.0.3", + "@octokit/openapi-webhooks-types": "12.1.0", "@octokit/request-error": "^7.0.0", "@octokit/webhooks-methods": "^6.0.0" }, @@ -3085,9 +3085,9 @@ } }, "node_modules/@tailwindcss/node": { - "version": "4.1.17", - "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.17.tgz", - "integrity": "sha512-csIkHIgLb3JisEFQ0vxr2Y57GUNYh447C8xzwj89U/8fdW8LhProdxvnVH6U8M2Y73QKiTIH+LWbK3V2BBZsAg==", + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.18.tgz", + "integrity": "sha512-DoR7U1P7iYhw16qJ49fgXUlry1t4CpXeErJHnQ44JgTSKMaZUdf17cfn5mHchfJ4KRBZRFA/Coo+MUF5+gOaCQ==", "dev": true, "license": "MIT", "dependencies": { @@ -3097,37 +3097,37 @@ "lightningcss": "1.30.2", "magic-string": "^0.30.21", "source-map-js": "^1.2.1", - "tailwindcss": "4.1.17" + "tailwindcss": "4.1.18" } }, "node_modules/@tailwindcss/oxide": { - "version": "4.1.17", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.17.tgz", - "integrity": "sha512-F0F7d01fmkQhsTjXezGBLdrl1KresJTcI3DB8EkScCldyKp3Msz4hub4uyYaVnk88BAS1g5DQjjF6F5qczheLA==", + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.18.tgz", + "integrity": "sha512-EgCR5tTS5bUSKQgzeMClT6iCY3ToqE1y+ZB0AKldj809QXk1Y+3jB0upOYZrn9aGIzPtUsP7sX4QQ4XtjBB95A==", "dev": true, "license": "MIT", "engines": { "node": ">= 10" }, "optionalDependencies": { - "@tailwindcss/oxide-android-arm64": "4.1.17", - "@tailwindcss/oxide-darwin-arm64": "4.1.17", - "@tailwindcss/oxide-darwin-x64": "4.1.17", - "@tailwindcss/oxide-freebsd-x64": "4.1.17", - "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.17", - "@tailwindcss/oxide-linux-arm64-gnu": "4.1.17", - "@tailwindcss/oxide-linux-arm64-musl": "4.1.17", - "@tailwindcss/oxide-linux-x64-gnu": "4.1.17", - "@tailwindcss/oxide-linux-x64-musl": "4.1.17", - "@tailwindcss/oxide-wasm32-wasi": "4.1.17", - "@tailwindcss/oxide-win32-arm64-msvc": "4.1.17", - "@tailwindcss/oxide-win32-x64-msvc": "4.1.17" + "@tailwindcss/oxide-android-arm64": "4.1.18", + "@tailwindcss/oxide-darwin-arm64": "4.1.18", + "@tailwindcss/oxide-darwin-x64": "4.1.18", + "@tailwindcss/oxide-freebsd-x64": "4.1.18", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.18", + "@tailwindcss/oxide-linux-arm64-gnu": "4.1.18", + "@tailwindcss/oxide-linux-arm64-musl": "4.1.18", + "@tailwindcss/oxide-linux-x64-gnu": "4.1.18", + "@tailwindcss/oxide-linux-x64-musl": "4.1.18", + "@tailwindcss/oxide-wasm32-wasi": "4.1.18", + "@tailwindcss/oxide-win32-arm64-msvc": "4.1.18", + "@tailwindcss/oxide-win32-x64-msvc": "4.1.18" } }, "node_modules/@tailwindcss/oxide-android-arm64": { - "version": "4.1.17", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.17.tgz", - "integrity": "sha512-BMqpkJHgOZ5z78qqiGE6ZIRExyaHyuxjgrJ6eBO5+hfrfGkuya0lYfw8fRHG77gdTjWkNWEEm+qeG2cDMxArLQ==", + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.18.tgz", + "integrity": "sha512-dJHz7+Ugr9U/diKJA0W6N/6/cjI+ZTAoxPf9Iz9BFRF2GzEX8IvXxFIi/dZBloVJX/MZGvRuFA9rqwdiIEZQ0Q==", "cpu": [ "arm64" ], @@ -3142,9 +3142,9 @@ } }, "node_modules/@tailwindcss/oxide-darwin-arm64": { - "version": "4.1.17", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.17.tgz", - "integrity": "sha512-EquyumkQweUBNk1zGEU/wfZo2qkp/nQKRZM8bUYO0J+Lums5+wl2CcG1f9BgAjn/u9pJzdYddHWBiFXJTcxmOg==", + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.18.tgz", + "integrity": "sha512-Gc2q4Qhs660bhjyBSKgq6BYvwDz4G+BuyJ5H1xfhmDR3D8HnHCmT/BSkvSL0vQLy/nkMLY20PQ2OoYMO15Jd0A==", "cpu": [ "arm64" ], @@ -3159,9 +3159,9 @@ } }, "node_modules/@tailwindcss/oxide-darwin-x64": { - "version": "4.1.17", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.17.tgz", - "integrity": "sha512-gdhEPLzke2Pog8s12oADwYu0IAw04Y2tlmgVzIN0+046ytcgx8uZmCzEg4VcQh+AHKiS7xaL8kGo/QTiNEGRog==", + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.18.tgz", + "integrity": "sha512-FL5oxr2xQsFrc3X9o1fjHKBYBMD1QZNyc1Xzw/h5Qu4XnEBi3dZn96HcHm41c/euGV+GRiXFfh2hUCyKi/e+yw==", "cpu": [ "x64" ], @@ -3176,9 +3176,9 @@ } }, "node_modules/@tailwindcss/oxide-freebsd-x64": { - "version": "4.1.17", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.17.tgz", - "integrity": "sha512-hxGS81KskMxML9DXsaXT1H0DyA+ZBIbyG/sSAjWNe2EDl7TkPOBI42GBV3u38itzGUOmFfCzk1iAjDXds8Oh0g==", + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.18.tgz", + "integrity": "sha512-Fj+RHgu5bDodmV1dM9yAxlfJwkkWvLiRjbhuO2LEtwtlYlBgiAT4x/j5wQr1tC3SANAgD+0YcmWVrj8R9trVMA==", "cpu": [ "x64" ], @@ -3193,9 +3193,9 @@ } }, "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { - "version": "4.1.17", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.17.tgz", - "integrity": "sha512-k7jWk5E3ldAdw0cNglhjSgv501u7yrMf8oeZ0cElhxU6Y2o7f8yqelOp3fhf7evjIS6ujTI3U8pKUXV2I4iXHQ==", + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.18.tgz", + "integrity": "sha512-Fp+Wzk/Ws4dZn+LV2Nqx3IilnhH51YZoRaYHQsVq3RQvEl+71VGKFpkfHrLM/Li+kt5c0DJe/bHXK1eHgDmdiA==", "cpu": [ "arm" ], @@ -3210,9 +3210,9 @@ } }, "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { - "version": "4.1.17", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.17.tgz", - "integrity": "sha512-HVDOm/mxK6+TbARwdW17WrgDYEGzmoYayrCgmLEw7FxTPLcp/glBisuyWkFz/jb7ZfiAXAXUACfyItn+nTgsdQ==", + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.18.tgz", + "integrity": "sha512-S0n3jboLysNbh55Vrt7pk9wgpyTTPD0fdQeh7wQfMqLPM/Hrxi+dVsLsPrycQjGKEQk85Kgbx+6+QnYNiHalnw==", "cpu": [ "arm64" ], @@ -3227,9 +3227,9 @@ } }, "node_modules/@tailwindcss/oxide-linux-arm64-musl": { - "version": "4.1.17", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.17.tgz", - "integrity": "sha512-HvZLfGr42i5anKtIeQzxdkw/wPqIbpeZqe7vd3V9vI3RQxe3xU1fLjss0TjyhxWcBaipk7NYwSrwTwK1hJARMg==", + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.18.tgz", + "integrity": "sha512-1px92582HkPQlaaCkdRcio71p8bc8i/ap5807tPRDK/uw953cauQBT8c5tVGkOwrHMfc2Yh6UuxaH4vtTjGvHg==", "cpu": [ "arm64" ], @@ -3244,9 +3244,9 @@ } }, "node_modules/@tailwindcss/oxide-linux-x64-gnu": { - "version": "4.1.17", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.17.tgz", - "integrity": "sha512-M3XZuORCGB7VPOEDH+nzpJ21XPvK5PyjlkSFkFziNHGLc5d6g3di2McAAblmaSUNl8IOmzYwLx9NsE7bplNkwQ==", + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.18.tgz", + "integrity": "sha512-v3gyT0ivkfBLoZGF9LyHmts0Isc8jHZyVcbzio6Wpzifg/+5ZJpDiRiUhDLkcr7f/r38SWNe7ucxmGW3j3Kb/g==", "cpu": [ "x64" ], @@ -3261,9 +3261,9 @@ } }, "node_modules/@tailwindcss/oxide-linux-x64-musl": { - "version": "4.1.17", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.17.tgz", - "integrity": "sha512-k7f+pf9eXLEey4pBlw+8dgfJHY4PZ5qOUFDyNf7SI6lHjQ9Zt7+NcscjpwdCEbYi6FI5c2KDTDWyf2iHcCSyyQ==", + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.18.tgz", + "integrity": "sha512-bhJ2y2OQNlcRwwgOAGMY0xTFStt4/wyU6pvI6LSuZpRgKQwxTec0/3Scu91O8ir7qCR3AuepQKLU/kX99FouqQ==", "cpu": [ "x64" ], @@ -3278,9 +3278,9 @@ } }, "node_modules/@tailwindcss/oxide-wasm32-wasi": { - "version": "4.1.17", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.17.tgz", - "integrity": "sha512-cEytGqSSoy7zK4JRWiTCx43FsKP/zGr0CsuMawhH67ONlH+T79VteQeJQRO/X7L0juEUA8ZyuYikcRBf0vsxhg==", + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.18.tgz", + "integrity": "sha512-LffYTvPjODiP6PT16oNeUQJzNVyJl1cjIebq/rWWBF+3eDst5JGEFSc5cWxyRCJ0Mxl+KyIkqRxk1XPEs9x8TA==", "bundleDependencies": [ "@napi-rs/wasm-runtime", "@emnapi/core", @@ -3296,10 +3296,10 @@ "license": "MIT", "optional": true, "dependencies": { - "@emnapi/core": "^1.6.0", - "@emnapi/runtime": "^1.6.0", + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1", "@emnapi/wasi-threads": "^1.1.0", - "@napi-rs/wasm-runtime": "^1.0.7", + "@napi-rs/wasm-runtime": "^1.1.0", "@tybys/wasm-util": "^0.10.1", "tslib": "^2.4.0" }, @@ -3308,7 +3308,7 @@ } }, "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/core": { - "version": "1.6.0", + "version": "1.7.1", "dev": true, "inBundle": true, "license": "MIT", @@ -3319,7 +3319,7 @@ } }, "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/runtime": { - "version": "1.6.0", + "version": "1.7.1", "dev": true, "inBundle": true, "license": "MIT", @@ -3339,14 +3339,14 @@ } }, "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@napi-rs/wasm-runtime": { - "version": "1.0.7", + "version": "1.1.0", "dev": true, "inBundle": true, "license": "MIT", "optional": true, "dependencies": { - "@emnapi/core": "^1.5.0", - "@emnapi/runtime": "^1.5.0", + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1", "@tybys/wasm-util": "^0.10.1" } }, @@ -3368,9 +3368,9 @@ "optional": true }, "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { - "version": "4.1.17", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.17.tgz", - "integrity": "sha512-JU5AHr7gKbZlOGvMdb4722/0aYbU+tN6lv1kONx0JK2cGsh7g148zVWLM0IKR3NeKLv+L90chBVYcJ8uJWbC9A==", + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.18.tgz", + "integrity": "sha512-HjSA7mr9HmC8fu6bdsZvZ+dhjyGCLdotjVOgLA2vEqxEBZaQo9YTX4kwgEvPCpRh8o4uWc4J/wEoFzhEmjvPbA==", "cpu": [ "arm64" ], @@ -3385,9 +3385,9 @@ } }, "node_modules/@tailwindcss/oxide-win32-x64-msvc": { - "version": "4.1.17", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.17.tgz", - "integrity": "sha512-SKWM4waLuqx0IH+FMDUw6R66Hu4OuTALFgnleKbqhgGU30DY20NORZMZUKgLRjQXNN2TLzKvh48QXTig4h4bGw==", + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.18.tgz", + "integrity": "sha512-bJWbyYpUlqamC8dpR7pfjA0I7vdF6t5VpUGMWRkXVE3AXgIZjYUYAK7II1GNaxR8J1SSrSrppRar8G++JekE3Q==", "cpu": [ "x64" ], @@ -3402,17 +3402,17 @@ } }, "node_modules/@tailwindcss/postcss": { - "version": "4.1.17", - "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.1.17.tgz", - "integrity": "sha512-+nKl9N9mN5uJ+M7dBOOCzINw94MPstNR/GtIhz1fpZysxL/4a+No64jCBD6CPN+bIHWFx3KWuu8XJRrj/572Dw==", + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.1.18.tgz", + "integrity": "sha512-Ce0GFnzAOuPyfV5SxjXGn0CubwGcuDB0zcdaPuCSzAa/2vII24JTkH+I6jcbXLb1ctjZMZZI6OjDaLPJQL1S0g==", "dev": true, "license": "MIT", "dependencies": { "@alloc/quick-lru": "^5.2.0", - "@tailwindcss/node": "4.1.17", - "@tailwindcss/oxide": "4.1.17", + "@tailwindcss/node": "4.1.18", + "@tailwindcss/oxide": "4.1.18", "postcss": "^8.4.41", - "tailwindcss": "4.1.17" + "tailwindcss": "4.1.18" } }, "node_modules/@tybys/wasm-util": { @@ -3536,9 +3536,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "24.10.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.1.tgz", - "integrity": "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==", + "version": "25.0.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.0.3.tgz", + "integrity": "sha512-W609buLVRVmeW693xKfzHeIV6nJGGz98uCPfeXI1ELMLXVeKYZ9m15fAMSaUPBHYLGFsVRcMmSCksQOrZV9BYA==", "dev": true, "license": "MIT", "dependencies": { @@ -3559,9 +3559,9 @@ "license": "MIT" }, "node_modules/@types/pg": { - "version": "8.15.6", - "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.15.6.tgz", - "integrity": "sha512-NoaMtzhxOrubeL/7UZuNTrejB4MPAJ0RpxZqXQf2qXuVlTPuG6Y8p4u9dKRaue4yjmC7ZhzVO2/Yyyn25znrPQ==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.16.0.tgz", + "integrity": "sha512-RmhMd/wD+CF8Dfo+cVIy3RR5cl8CyfXQ0tGgW6XBL8L4LM/UTEbNXYRbLwU6w+CgrKBNbrQWt4FUtTfaU5jSYQ==", "dev": true, "license": "MIT", "dependencies": { @@ -3643,21 +3643,20 @@ "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.48.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.48.0.tgz", - "integrity": "sha512-XxXP5tL1txl13YFtrECECQYeZjBZad4fyd3cFV4a19LkAY/bIp9fev3US4S5fDVV2JaYFiKAZ/GRTOLer+mbyQ==", + "version": "8.51.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.51.0.tgz", + "integrity": "sha512-XtssGWJvypyM2ytBnSnKtHYOGT+4ZwTnBVl36TA4nRO2f4PRNGz5/1OszHzcZCvcBMh+qb7I06uoCmLTRdR9og==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.48.0", - "@typescript-eslint/type-utils": "8.48.0", - "@typescript-eslint/utils": "8.48.0", - "@typescript-eslint/visitor-keys": "8.48.0", - "graphemer": "^1.4.0", + "@typescript-eslint/scope-manager": "8.51.0", + "@typescript-eslint/type-utils": "8.51.0", + "@typescript-eslint/utils": "8.51.0", + "@typescript-eslint/visitor-keys": "8.51.0", "ignore": "^7.0.0", "natural-compare": "^1.4.0", - "ts-api-utils": "^2.1.0" + "ts-api-utils": "^2.2.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3667,23 +3666,23 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.48.0", + "@typescript-eslint/parser": "^8.51.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/parser": { - "version": "8.48.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.48.0.tgz", - "integrity": "sha512-jCzKdm/QK0Kg4V4IK/oMlRZlY+QOcdjv89U2NgKHZk1CYTj82/RVSx1mV/0gqCVMJ/DA+Zf/S4NBWNF8GQ+eqQ==", + "version": "8.51.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.51.0.tgz", + "integrity": "sha512-3xP4XzzDNQOIqBMWogftkwxhg5oMKApqY0BAflmLZiFYHqyhSOxv/cd/zPQLTcCXr4AkaKb25joocY0BD1WC6A==", "dev": true, "license": "MIT", "peer": true, "dependencies": { - "@typescript-eslint/scope-manager": "8.48.0", - "@typescript-eslint/types": "8.48.0", - "@typescript-eslint/typescript-estree": "8.48.0", - "@typescript-eslint/visitor-keys": "8.48.0", + "@typescript-eslint/scope-manager": "8.51.0", + "@typescript-eslint/types": "8.51.0", + "@typescript-eslint/typescript-estree": "8.51.0", + "@typescript-eslint/visitor-keys": "8.51.0", "debug": "^4.3.4" }, "engines": { @@ -3699,14 +3698,14 @@ } }, "node_modules/@typescript-eslint/project-service": { - "version": "8.48.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.48.0.tgz", - "integrity": "sha512-Ne4CTZyRh1BecBf84siv42wv5vQvVmgtk8AuiEffKTUo3DrBaGYZueJSxxBZ8fjk/N3DrgChH4TOdIOwOwiqqw==", + "version": "8.51.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.51.0.tgz", + "integrity": "sha512-Luv/GafO07Z7HpiI7qeEW5NW8HUtZI/fo/kE0YbtQEFpJRUuR0ajcWfCE5bnMvL7QQFrmT/odMe8QZww8X2nfQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.48.0", - "@typescript-eslint/types": "^8.48.0", + "@typescript-eslint/tsconfig-utils": "^8.51.0", + "@typescript-eslint/types": "^8.51.0", "debug": "^4.3.4" }, "engines": { @@ -3721,14 +3720,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.48.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.48.0.tgz", - "integrity": "sha512-uGSSsbrtJrLduti0Q1Q9+BF1/iFKaxGoQwjWOIVNJv0o6omrdyR8ct37m4xIl5Zzpkp69Kkmvom7QFTtue89YQ==", + "version": "8.51.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.51.0.tgz", + "integrity": "sha512-JhhJDVwsSx4hiOEQPeajGhCWgBMBwVkxC/Pet53EpBVs7zHHtayKefw1jtPaNRXpI9RA2uocdmpdfE7T+NrizA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.48.0", - "@typescript-eslint/visitor-keys": "8.48.0" + "@typescript-eslint/types": "8.51.0", + "@typescript-eslint/visitor-keys": "8.51.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3739,9 +3738,9 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.48.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.48.0.tgz", - "integrity": "sha512-WNebjBdFdyu10sR1M4OXTt2OkMd5KWIL+LLfeH9KhgP+jzfDV/LI3eXzwJ1s9+Yc0Kzo2fQCdY/OpdusCMmh6w==", + "version": "8.51.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.51.0.tgz", + "integrity": "sha512-Qi5bSy/vuHeWyir2C8u/uqGMIlIDu8fuiYWv48ZGlZ/k+PRPHtaAu7erpc7p5bzw2WNNSniuxoMSO4Ar6V9OXw==", "dev": true, "license": "MIT", "engines": { @@ -3756,17 +3755,17 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.48.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.48.0.tgz", - "integrity": "sha512-zbeVaVqeXhhab6QNEKfK96Xyc7UQuoFWERhEnj3mLVnUWrQnv15cJNseUni7f3g557gm0e46LZ6IJ4NJVOgOpw==", + "version": "8.51.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.51.0.tgz", + "integrity": "sha512-0XVtYzxnobc9K0VU7wRWg1yiUrw4oQzexCG2V2IDxxCxhqBMSMbjB+6o91A+Uc0GWtgjCa3Y8bi7hwI0Tu4n5Q==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.48.0", - "@typescript-eslint/typescript-estree": "8.48.0", - "@typescript-eslint/utils": "8.48.0", + "@typescript-eslint/types": "8.51.0", + "@typescript-eslint/typescript-estree": "8.51.0", + "@typescript-eslint/utils": "8.51.0", "debug": "^4.3.4", - "ts-api-utils": "^2.1.0" + "ts-api-utils": "^2.2.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3781,9 +3780,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.48.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.48.0.tgz", - "integrity": "sha512-cQMcGQQH7kwKoVswD1xdOytxQR60MWKM1di26xSUtxehaDs/32Zpqsu5WJlXTtTTqyAVK8R7hvsUnIXRS+bjvA==", + "version": "8.51.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.51.0.tgz", + "integrity": "sha512-TizAvWYFM6sSscmEakjY3sPqGwxZRSywSsPEiuZF6d5GmGD9Gvlsv0f6N8FvAAA0CD06l3rIcWNbsN1e5F/9Ag==", "dev": true, "license": "MIT", "engines": { @@ -3795,21 +3794,21 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.48.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.48.0.tgz", - "integrity": "sha512-ljHab1CSO4rGrQIAyizUS6UGHHCiAYhbfcIZ1zVJr5nMryxlXMVWS3duFPSKvSUbFPwkXMFk1k0EMIjub4sRRQ==", + "version": "8.51.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.51.0.tgz", + "integrity": "sha512-1qNjGqFRmlq0VW5iVlcyHBbCjPB7y6SxpBkrbhNWMy/65ZoncXCEPJxkRZL8McrseNH6lFhaxCIaX+vBuFnRng==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.48.0", - "@typescript-eslint/tsconfig-utils": "8.48.0", - "@typescript-eslint/types": "8.48.0", - "@typescript-eslint/visitor-keys": "8.48.0", + "@typescript-eslint/project-service": "8.51.0", + "@typescript-eslint/tsconfig-utils": "8.51.0", + "@typescript-eslint/types": "8.51.0", + "@typescript-eslint/visitor-keys": "8.51.0", "debug": "^4.3.4", "minimatch": "^9.0.4", "semver": "^7.6.0", "tinyglobby": "^0.2.15", - "ts-api-utils": "^2.1.0" + "ts-api-utils": "^2.2.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3823,16 +3822,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.48.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.48.0.tgz", - "integrity": "sha512-yTJO1XuGxCsSfIVt1+1UrLHtue8xz16V8apzPYI06W0HbEbEWHxHXgZaAgavIkoh+GeV6hKKd5jm0sS6OYxWXQ==", + "version": "8.51.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.51.0.tgz", + "integrity": "sha512-11rZYxSe0zabiKaCP2QAwRf/dnmgFgvTmeDTtZvUvXG3UuAdg/GU02NExmmIXzz3vLGgMdtrIosI84jITQOxUA==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", - "@typescript-eslint/scope-manager": "8.48.0", - "@typescript-eslint/types": "8.48.0", - "@typescript-eslint/typescript-estree": "8.48.0" + "@typescript-eslint/scope-manager": "8.51.0", + "@typescript-eslint/types": "8.51.0", + "@typescript-eslint/typescript-estree": "8.51.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3847,13 +3846,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.48.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.48.0.tgz", - "integrity": "sha512-T0XJMaRPOH3+LBbAfzR2jalckP1MSG/L9eUtY0DEzUyVaXJ/t6zN0nR7co5kz0Jko/nkSYCBRkz1djvjajVTTg==", + "version": "8.51.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.51.0.tgz", + "integrity": "sha512-mM/JRQOzhVN1ykejrvwnBRV3+7yTKK8tVANVN3o1O0t0v7o+jqdVu9crPy5Y9dov15TJk/FTIgoUGHrTOVL3Zg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.48.0", + "@typescript-eslint/types": "8.51.0", "eslint-visitor-keys": "^4.2.1" }, "engines": { @@ -4614,7 +4613,6 @@ "version": "2.8.28", "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.28.tgz", "integrity": "sha512-gYjt7OIqdM0PcttNYP2aVrr2G0bMALkBaoehD4BuRGjAOtipg0b6wHg1yNL+s5zSnLZZrGHOw4IrND8CD+3oIQ==", - "dev": true, "license": "Apache-2.0", "bin": { "baseline-browser-mapping": "dist/cli.js" @@ -5388,9 +5386,9 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.18.3", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz", - "integrity": "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==", + "version": "5.18.4", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.4.tgz", + "integrity": "sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q==", "dev": true, "license": "MIT", "dependencies": { @@ -5615,9 +5613,9 @@ } }, "node_modules/eslint": { - "version": "9.39.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.1.tgz", - "integrity": "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==", + "version": "9.39.2", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.2.tgz", + "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", "dev": true, "license": "MIT", "peer": true, @@ -5628,7 +5626,7 @@ "@eslint/config-helpers": "^0.4.2", "@eslint/core": "^0.17.0", "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.39.1", + "@eslint/js": "9.39.2", "@eslint/plugin-kit": "^0.4.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", @@ -5676,13 +5674,13 @@ } }, "node_modules/eslint-config-next": { - "version": "16.0.6", - "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-16.0.6.tgz", - "integrity": "sha512-nx0Z2S50TlcSQ2RtyULCff5tlKTwqF/ICh3U9s8C/e2aRXAm1Ootdb7BEHGZmejtJSgsFq8PVFdlWy8BHiz2pg==", + "version": "16.1.1", + "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-16.1.1.tgz", + "integrity": "sha512-55nTpVWm3qeuxoQKLOjQVciKZJUphKrNM0fCcQHAIOGl6VFXgaqeMfv0aKJhs7QtcnlAPhNVqsqRfRjeKBPIUA==", "dev": true, "license": "MIT", "dependencies": { - "@next/eslint-plugin-next": "16.0.6", + "@next/eslint-plugin-next": "16.1.1", "eslint-import-resolver-node": "^0.3.6", "eslint-import-resolver-typescript": "^3.5.2", "eslint-plugin-import": "^2.32.0", @@ -6378,9 +6376,9 @@ } }, "node_modules/fastq": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", - "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", "dev": true, "license": "ISC", "dependencies": { @@ -6780,13 +6778,6 @@ "dev": true, "license": "ISC" }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true, - "license": "MIT" - }, "node_modules/handlebars": { "version": "4.7.8", "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", @@ -9052,13 +9043,14 @@ "license": "MIT" }, "node_modules/next": { - "version": "16.0.10", - "resolved": "https://registry.npmjs.org/next/-/next-16.0.10.tgz", - "integrity": "sha512-RtWh5PUgI+vxlV3HdR+IfWA1UUHu0+Ram/JBO4vWB54cVPentCD0e+lxyAYEsDTqGGMg7qpjhKh6dc6aW7W/sA==", + "version": "16.1.1", + "resolved": "https://registry.npmjs.org/next/-/next-16.1.1.tgz", + "integrity": "sha512-QI+T7xrxt1pF6SQ/JYFz95ro/mg/1Znk5vBebsWwbpejj1T0A23hO7GYEaVac9QUOT2BIMiuzm0L99ooq7k0/w==", "license": "MIT", "dependencies": { - "@next/env": "16.0.10", + "@next/env": "16.1.1", "@swc/helpers": "0.5.15", + "baseline-browser-mapping": "^2.8.3", "caniuse-lite": "^1.0.30001579", "postcss": "8.4.31", "styled-jsx": "5.1.6" @@ -9070,14 +9062,14 @@ "node": ">=20.9.0" }, "optionalDependencies": { - "@next/swc-darwin-arm64": "16.0.10", - "@next/swc-darwin-x64": "16.0.10", - "@next/swc-linux-arm64-gnu": "16.0.10", - "@next/swc-linux-arm64-musl": "16.0.10", - "@next/swc-linux-x64-gnu": "16.0.10", - "@next/swc-linux-x64-musl": "16.0.10", - "@next/swc-win32-arm64-msvc": "16.0.10", - "@next/swc-win32-x64-msvc": "16.0.10", + "@next/swc-darwin-arm64": "16.1.1", + "@next/swc-darwin-x64": "16.1.1", + "@next/swc-linux-arm64-gnu": "16.1.1", + "@next/swc-linux-arm64-musl": "16.1.1", + "@next/swc-linux-x64-gnu": "16.1.1", + "@next/swc-linux-x64-musl": "16.1.1", + "@next/swc-win32-arm64-msvc": "16.1.1", + "@next/swc-win32-x64-msvc": "16.1.1", "sharp": "^0.34.4" }, "peerDependencies": { @@ -9253,9 +9245,9 @@ } }, "node_modules/npm": { - "version": "11.6.4", - "resolved": "https://registry.npmjs.org/npm/-/npm-11.6.4.tgz", - "integrity": "sha512-ERjKtGoFpQrua/9bG0+h3xiv/4nVdGViCjUYA1AmlV24fFvfnSB7B7dIfZnySQ1FDLd0ZVrWPsLLp78dCtJdRQ==", + "version": "11.7.0", + "resolved": "https://registry.npmjs.org/npm/-/npm-11.7.0.tgz", + "integrity": "sha512-wiCZpv/41bIobCoJ31NStIWKfAxxYyD1iYnWCtiyns8s5v3+l8y0HCP/sScuH6B5+GhIfda4HQKiqeGZwJWhFw==", "bundleDependencies": [ "@isaacs/string-locale-compare", "@npmcli/arborist", @@ -9334,8 +9326,8 @@ ], "dependencies": { "@isaacs/string-locale-compare": "^1.1.0", - "@npmcli/arborist": "^9.1.8", - "@npmcli/config": "^10.4.4", + "@npmcli/arborist": "^9.1.9", + "@npmcli/config": "^10.4.5", "@npmcli/fs": "^5.0.0", "@npmcli/map-workspaces": "^5.0.3", "@npmcli/metavuln-calculator": "^9.0.3", @@ -9360,11 +9352,11 @@ "is-cidr": "^6.0.1", "json-parse-even-better-errors": "^5.0.0", "libnpmaccess": "^10.0.3", - "libnpmdiff": "^8.0.11", - "libnpmexec": "^10.1.10", - "libnpmfund": "^7.0.11", + "libnpmdiff": "^8.0.12", + "libnpmexec": "^10.1.11", + "libnpmfund": "^7.0.12", "libnpmorg": "^8.0.1", - "libnpmpack": "^9.0.11", + "libnpmpack": "^9.0.12", "libnpmpublish": "^11.1.3", "libnpmsearch": "^9.0.1", "libnpmteam": "^8.0.2", @@ -9472,7 +9464,7 @@ } }, "node_modules/npm/node_modules/@npmcli/arborist": { - "version": "9.1.8", + "version": "9.1.9", "inBundle": true, "license": "ISC", "dependencies": { @@ -9518,7 +9510,7 @@ } }, "node_modules/npm/node_modules/@npmcli/config": { - "version": "10.4.4", + "version": "10.4.5", "inBundle": true, "license": "ISC", "dependencies": { @@ -10256,11 +10248,11 @@ } }, "node_modules/npm/node_modules/libnpmdiff": { - "version": "8.0.11", + "version": "8.0.12", "inBundle": true, "license": "ISC", "dependencies": { - "@npmcli/arborist": "^9.1.8", + "@npmcli/arborist": "^9.1.9", "@npmcli/installed-package-contents": "^4.0.0", "binary-extensions": "^3.0.0", "diff": "^8.0.2", @@ -10274,11 +10266,11 @@ } }, "node_modules/npm/node_modules/libnpmexec": { - "version": "10.1.10", + "version": "10.1.11", "inBundle": true, "license": "ISC", "dependencies": { - "@npmcli/arborist": "^9.1.8", + "@npmcli/arborist": "^9.1.9", "@npmcli/package-json": "^7.0.0", "@npmcli/run-script": "^10.0.0", "ci-info": "^4.0.0", @@ -10296,11 +10288,11 @@ } }, "node_modules/npm/node_modules/libnpmfund": { - "version": "7.0.11", + "version": "7.0.12", "inBundle": true, "license": "ISC", "dependencies": { - "@npmcli/arborist": "^9.1.8" + "@npmcli/arborist": "^9.1.9" }, "engines": { "node": "^20.17.0 || >=22.9.0" @@ -10319,11 +10311,11 @@ } }, "node_modules/npm/node_modules/libnpmpack": { - "version": "9.0.11", + "version": "9.0.12", "inBundle": true, "license": "ISC", "dependencies": { - "@npmcli/arborist": "^9.1.8", + "@npmcli/arborist": "^9.1.9", "@npmcli/run-script": "^10.0.0", "npm-package-arg": "^13.0.0", "pacote": "^21.0.2" @@ -12195,9 +12187,9 @@ } }, "node_modules/react-is": { - "version": "19.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.0.tgz", - "integrity": "sha512-x3Ax3kNSMIIkyVYhWPyO09bu0uttcAIoecO/um/rKGQ4EltYWVYtyiGkS/3xMynrbVQdS69Jhlv8FXUEZehlzA==", + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.3.tgz", + "integrity": "sha512-qJNJfu81ByyabuG7hPFEbXqNcWSU3+eVus+KJs+0ncpGfMyYdvSmxiJxbWR65lYi1I+/0HBcliO029gc4F+PnA==", "license": "MIT" }, "node_modules/react-tabs": { @@ -13438,13 +13430,13 @@ } }, "node_modules/swr": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/swr/-/swr-2.3.7.tgz", - "integrity": "sha512-ZEquQ82QvalqTxhBVv/DlAg2mbmUjF4UgpPg9wwk4ufb9rQnZXh1iKyyKBqV6bQGu1Ie7L1QwSYO07qFIa1p+g==", + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/swr/-/swr-2.3.8.tgz", + "integrity": "sha512-gaCPRVoMq8WGDcWj9p4YWzCMPHzE0WNl6W8ADIx9c3JBEIdMkJGMzW+uzXvxHMltwcYACr9jP+32H8/hgwMR7w==", "license": "MIT", "dependencies": { "dequal": "^2.0.3", - "use-sync-external-store": "^1.4.0" + "use-sync-external-store": "^1.6.0" }, "peerDependencies": { "react": "^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" @@ -13467,9 +13459,9 @@ } }, "node_modules/tailwindcss": { - "version": "4.1.17", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.17.tgz", - "integrity": "sha512-j9Ee2YjuQqYT9bbRTfTZht9W/ytp5H+jJpZKiYdP/bpnXARAuELt9ofP0lPnmHjbga7SNQIxdTAXCmtKVYjN+Q==", + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.18.tgz", + "integrity": "sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==", "dev": true, "license": "MIT" }, @@ -13633,9 +13625,9 @@ "license": "MIT" }, "node_modules/ts-api-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", - "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.3.0.tgz", + "integrity": "sha512-6eg3Y9SF7SsAvGzRHQvvc1skDAhwI4YQ32ui1scxD1Ccr0G5qIIbUBT3pFTKX8kmWIQClHobtUdNuaBgwdfdWg==", "dev": true, "license": "MIT", "engines": { @@ -13646,9 +13638,9 @@ } }, "node_modules/ts-jest": { - "version": "29.4.5", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.4.5.tgz", - "integrity": "sha512-HO3GyiWn2qvTQA4kTgjDcXiMwYQt68a1Y8+JuLRVpdIzm+UOLSHgl/XqR4c6nzJkq5rOkjc02O2I7P7l/Yof0Q==", + "version": "29.4.6", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.4.6.tgz", + "integrity": "sha512-fSpWtOO/1AjSNQguk43hb/JCo16oJDnMJf3CdEGNkqsEX3t0KX96xvyX1D7PfLCpVoKu4MfVrqUkFyblYoY4lA==", "dev": true, "license": "MIT", "dependencies": { @@ -13883,16 +13875,16 @@ } }, "node_modules/typescript-eslint": { - "version": "8.48.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.48.0.tgz", - "integrity": "sha512-fcKOvQD9GUn3Xw63EgiDqhvWJ5jsyZUaekl3KVpGsDJnN46WJTe3jWxtQP9lMZm1LJNkFLlTaWAxK2vUQR+cqw==", + "version": "8.51.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.51.0.tgz", + "integrity": "sha512-jh8ZuM5oEh2PSdyQG9YAEM1TCGuWenLSuSUhf/irbVUNW9O5FhbFVONviN2TgMTBnUmyHv7E56rYnfLZK6TkiA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.48.0", - "@typescript-eslint/parser": "8.48.0", - "@typescript-eslint/typescript-estree": "8.48.0", - "@typescript-eslint/utils": "8.48.0" + "@typescript-eslint/eslint-plugin": "8.51.0", + "@typescript-eslint/parser": "8.51.0", + "@typescript-eslint/typescript-estree": "8.51.0", + "@typescript-eslint/utils": "8.51.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -14479,9 +14471,9 @@ } }, "node_modules/zod": { - "version": "4.1.13", - "resolved": "https://registry.npmjs.org/zod/-/zod-4.1.13.tgz", - "integrity": "sha512-AvvthqfqrAhNH9dnfmrfKzX5upOdjUVJYFqNSlkmGf64gRaTzlPwz99IHYnVs28qYAybvAlBV+H7pn0saFY4Ig==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.4.tgz", + "integrity": "sha512-Zw/uYiiyF6pUT1qmKbZziChgNPRu+ZRneAsMUDU6IwmXdWt5JwcUfy2bvLOCUtz5UniaN/Zx5aFttZYbYc7O/A==", "license": "MIT", "peer": true, "funding": { diff --git a/package.json b/package.json index 3a921d9f..16435e82 100644 --- a/package.json +++ b/package.json @@ -23,20 +23,20 @@ "@fortawesome/free-regular-svg-icons": "^7.1.0", "@fortawesome/free-solid-svg-icons": "^7.1.0", "@fortawesome/react-fontawesome": "^3.1.1", - "@mui/icons-material": "^7.3.5", + "@mui/icons-material": "^7.3.6", "@mui/material": "^7.0.1", "@octokit/auth-app": "^8.1.2", "@octokit/core": "^7.0.6", - "@octokit/webhooks": "~14.1.3", + "@octokit/webhooks": "~14.2.0", "core-js": "^3.47.0", "encoding": "^0.1.13", "figma-squircle": "^1.1.0", "install": "^0.13.0", "ioredis": "^5.8.2", "mobx": "^6.15.0", - "next": "16.0.10", + "next": "16.1.1", "next-auth": "^5.0.0-beta.30", - "npm": "^11.6.4", + "npm": "^11.7.0", "nprogress": "^0.2.0", "octokit": "^5.0.5", "react": "^19.2.0", @@ -45,29 +45,29 @@ "redoc": "^2.5.2", "sharp": "^0.34.2", "styled-components": "^6.1.19", - "swr": "^2.3.7", + "swr": "^2.3.8", "usehooks-ts": "^3.1.1", "yaml": "^2.8.2", - "zod": "^4.1.13" + "zod": "^4.3.4" }, "devDependencies": { "@auth/pg-adapter": "^1.11.1", - "@tailwindcss/postcss": "^4.1.17", + "@tailwindcss/postcss": "^4.1.18", "@types/jest": "^30.0.0", - "@types/node": "^24.10.1", + "@types/node": "^25.0.3", "@types/nprogress": "^0.2.3", - "@types/pg": "^8.15.6", + "@types/pg": "^8.16.0", "@types/react": "^19.2.7", "@types/react-dom": "^19.2.3", - "@typescript-eslint/eslint-plugin": "^8.48.0", - "@typescript-eslint/parser": "^8.48.0", - "typescript-eslint": "^8.48.0", - "eslint": "^9.39.1", - "eslint-config-next": "^16.0.6", + "@typescript-eslint/eslint-plugin": "^8.51.0", + "@typescript-eslint/parser": "^8.51.0", + "typescript-eslint": "^8.51.0", + "eslint": "^9.39.2", + "eslint-config-next": "^16.1.1", "pg": "^8.16.3", "postcss": "^8.5.6", "tailwindcss": "^4.1.4", - "ts-jest": "^29.4.5", + "ts-jest": "^29.4.6", "typescript": "^5.9.3" } } From dfb844ce3974aaeb089abb443a393be75175ad2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20B=2E=20St=C3=B8vring?= Date: Mon, 5 Jan 2026 11:17:06 +0100 Subject: [PATCH 13/15] Rename project configuration filename in .env.example --- .env.example | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.env.example b/.env.example index 3e2770b5..af803bee 100644 --- a/.env.example +++ b/.env.example @@ -2,7 +2,7 @@ FRAMNA_DOCS_BASE_URL=http://localhost:3000 FRAMNA_DOCS_TITLE=Framna Docs FRAMNA_DOCS_DESCRIPTION=Documentation for Framna's APIs FRAMNA_DOCS_HELP_URL=https://github.com/shapehq/framna-docs/wiki -FRAMNA_DOCS_PROJECT_CONFIGURATION_FILENAME=.shape-docs.yml +FRAMNA_DOCS_PROJECT_CONFIGURATION_FILENAME=.framna-docs.yml NEXTAUTH_URL=https://docs.example.com NEXTAUTH_SECRET=use [openssl rand -base64 32] to generate a 32 bytes value REDIS_URL=localhost From af9cdcf1e1027f193d74086def52634d65498bbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=B8vring?= Date: Mon, 5 Jan 2026 13:42:32 +0100 Subject: [PATCH 14/15] Fixes loading screen shown below documentation --- src/app/(authed)/(project-doc)/[...slug]/page.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/app/(authed)/(project-doc)/[...slug]/page.tsx b/src/app/(authed)/(project-doc)/[...slug]/page.tsx index 66bb1423..e636c24e 100644 --- a/src/app/(authed)/(project-doc)/[...slug]/page.tsx +++ b/src/app/(authed)/(project-doc)/[...slug]/page.tsx @@ -36,9 +36,7 @@ export default function Page() { {project && (!version || !specification) && !refreshing && } - {refreshing && // project data is currently being fetched - show loading indicator - - } + {!project && refreshing && } {!project && !refreshing && } ) From c23a8286351acd8f7304fae4339134f9b48533b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=B8vring?= Date: Mon, 5 Jan 2026 13:44:59 +0100 Subject: [PATCH 15/15] Checks for version and specification --- src/app/(authed)/(project-doc)/[...slug]/page.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/app/(authed)/(project-doc)/[...slug]/page.tsx b/src/app/(authed)/(project-doc)/[...slug]/page.tsx index e636c24e..02473315 100644 --- a/src/app/(authed)/(project-doc)/[...slug]/page.tsx +++ b/src/app/(authed)/(project-doc)/[...slug]/page.tsx @@ -36,7 +36,9 @@ export default function Page() { {project && (!version || !specification) && !refreshing && } - {!project && refreshing && } + {!project && !version && !specification && refreshing && + + } {!project && !refreshing && } )