From 98262d8fb29c05b202b229dd4479ae7ffe038da4 Mon Sep 17 00:00:00 2001
From: Cian Johnston
Date: Wed, 1 Oct 2025 13:38:25 +0100
Subject: [PATCH 001/298] ci: allow dispatching workflow triage via label
(#20042)
Allows creating a task for an issue if a label 'traiage' is set.
Requires membership of the `coder` org to run.
Manual workflow_dispatch:
https://github.com/coder/coder/actions/runs/18158719999/job/51684512634
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
---
.github/workflows/traiage.yaml | 85 ++++++++++++++++++++++++++++------
1 file changed, 72 insertions(+), 13 deletions(-)
diff --git a/.github/workflows/traiage.yaml b/.github/workflows/traiage.yaml
index 615c5bec19e7f..dc45f242dbb87 100644
--- a/.github/workflows/traiage.yaml
+++ b/.github/workflows/traiage.yaml
@@ -1,6 +1,9 @@
name: AI Triage Automation
on:
+ issues:
+ types:
+ - labeled
workflow_dispatch:
inputs:
issue_url:
@@ -32,6 +35,7 @@ jobs:
traiage:
name: Triage GitHub Issue with Claude Code
runs-on: ubuntu-latest
+ if: github.event.label.name == 'traiage' || github.event_name == 'workflow_dispatch'
timeout-minutes: 30
env:
CODER_URL: ${{ secrets.TRAIAGE_CODER_URL }}
@@ -43,17 +47,58 @@ jobs:
actions: write
steps:
- - name: Checkout repository
- uses: actions/checkout@v4
- with:
- persist-credentials: false
- fetch-depth: 0
+ - name: Get GitHub user ID
+ id: github-user-id
+ if: always()
+ env:
+ GITHUB_ACTOR: ${{ github.actor }}
+ GITHUB_EVENT_NAME: ${{ github.event_name }}
+ GITHUB_EVENT_USER_ID: ${{ github.event.sender.id }}
+ GITHUB_EVENT_USER_LOGIN: ${{ github.event.sender.login }}
+ GH_TOKEN: ${{ github.token }}
+ run: |
+ # For workflow_dispatch, use the actor who triggered it
+ # For issues events, use the issue author
+ if [[ "${GITHUB_EVENT_NAME}" == "workflow_dispatch" ]]; then
+ if ! GITHUB_USER_ID=$(gh api "users/${GITHUB_ACTOR}" --jq '.id'); then
+ echo "::error::Failed to get GitHub user ID for actor ${GITHUB_ACTOR}"
+ exit 1
+ fi
+ echo "Using workflow_dispatch actor: ${GITHUB_ACTOR} (ID: ${GITHUB_USER_ID})"
+ echo "github_user_id=${GITHUB_USER_ID}" >> "${GITHUB_OUTPUT}"
+ echo "github_username=${GITHUB_ACTOR}" >> "${GITHUB_OUTPUT}"
+ exit 0
+ elif [[ "${GITHUB_EVENT_NAME}" == "issues" ]]; then
+ GITHUB_USER_ID=${GITHUB_EVENT_USER_ID}
+ echo "Using issue author: ${GITHUB_EVENT_USER_LOGIN} (ID: ${GITHUB_USER_ID})"
+ echo "github_user_id=${GITHUB_USER_ID}" >> "${GITHUB_OUTPUT}"
+ echo "github_username=${GITHUB_EVENT_USER_LOGIN}" >> "${GITHUB_OUTPUT}"
+ exit 0
+ else
+ echo "::error::Unsupported event type: ${GITHUB_EVENT_NAME}"
+ exit 1
+ fi
+
+ - name: Verify organization membership
+ env:
+ GITHUB_ORG: ${{ github.repository_owner }}
+ GH_TOKEN: ${{ github.token }}
+ GITHUB_USERNAME: ${{ steps.github-user-id.outputs.github_username }}
+ GITHUB_USER_ID: ${{ steps.github-user-id.outputs.github_user_id }}
+ run: |
+ # Check if the actor is a member of the organization
+ if ! gh api "orgs/${GITHUB_ORG}/members/${GITHUB_USERNAME}" --silent 2>/dev/null; then
+ echo "::error title=Access Denied::User ${GITHUB_USERNAME} is not a member of the ${GITHUB_ORG} organization"
+ echo "::error::You must be a member of the ${GITHUB_ORG} GitHub organization to run this workflow."
+ exit 1
+ fi
+ echo "::notice::User ${GITHUB_USERNAME} verified as member of ${GITHUB_ORG} organization"
- name: Extract context key from issue
id: extract-context
env:
ISSUE_URL: ${{ inputs.issue_url }}
- GITHUB_TOKEN: ${{ github.token }}
+ GH_TOKEN: ${{ github.token }}
run: |
issue_number="$(gh issue view "${ISSUE_URL}" --json number --jq '.number')"
context_key="gh-${issue_number}"
@@ -82,11 +127,9 @@ jobs:
id: get-coder-username
env:
CODER_SESSION_TOKEN: ${{ secrets.TRAIAGE_CODER_SESSION_TOKEN }}
- GITHUB_USER_ID: ${{
- (github.event_name == 'workflow_dispatch' && github.actor_id)
- }}
+ GH_TOKEN: ${{ github.token }}
+ GITHUB_USER_ID: ${{ steps.github-user-id.outputs.github_user_id }}
run: |
- [[ -z "${GITHUB_USER_ID}" || "${GITHUB_USER_ID}" == "null" ]] && echo "No GitHub actor ID found" && exit 1
user_json=$(
coder users list --github-user-id="${GITHUB_USER_ID}" --output=json
)
@@ -94,13 +137,20 @@ jobs:
[[ -z "${coder_username}" || "${coder_username}" == "null" ]] && echo "No Coder user with GitHub user ID ${GITHUB_USER_ID} found" && exit 1
echo "coder_username=${coder_username}" >> "${GITHUB_OUTPUT}"
+ - name: Checkout repository
+ uses: actions/checkout@v4
+ with:
+ persist-credentials: false
+ fetch-depth: 0
+
# TODO(Cian): this is a good use-case for 'recipes'
- name: Create Coder task
id: create-task
env:
CODER_USERNAME: ${{ steps.get-coder-username.outputs.coder_username }}
CONTEXT_KEY: ${{ steps.extract-context.outputs.context_key }}
- GITHUB_TOKEN: ${{ github.token }}
+ GH_TOKEN: ${{ github.token }}
+ GITHUB_REPOSITORY: ${{ github.repository }}
ISSUE_URL: ${{ inputs.issue_url }}
PREFIX: ${{ inputs.prefix }}
RUN_ID: ${{ github.run_id }}
@@ -125,7 +175,11 @@ jobs:
export TASK_NAME="${PREFIX}-${CONTEXT_KEY}-${RUN_ID}"
echo "Creating task: $TASK_NAME"
./scripts/traiage.sh create
- coder exp task status "${CODER_USERNAME}/$TASK_NAME" --watch
+ if [[ "${ISSUE_URL}" == "https://github.com/${GITHUB_REPOSITORY}"* ]]; then
+ gh issue comment "${ISSUE_URL}" --body "Task created: ${TASK_NAME}" --create-if-none --edit-last
+ else
+ echo "Skipping comment on other repo."
+ fi
echo "TASK_NAME=${CODER_USERNAME}/${TASK_NAME}" >> "${GITHUB_OUTPUT}"
echo "TASK_NAME=${CODER_USERNAME}/${TASK_NAME}" >> "${GITHUB_ENV}"
@@ -134,7 +188,11 @@ jobs:
if: inputs.cleanup
env:
BUCKET_PREFIX: "gs://coder-traiage-outputs/traiage"
+ CODER_USERNAME: ${{ steps.get-coder-username.outputs.coder_username }}
+ TASK_NAME: ${{ steps.create-task.outputs.TASK_NAME }}
run: |
+ echo "Waiting for task to complete..."
+ coder exp task status "${CODER_USERNAME}/$TASK_NAME" --watch
echo "Creating archive for workspace: $TASK_NAME"
./scripts/traiage.sh archive
echo "archive_url=${BUCKET_PREFIX%%/}/$TASK_NAME.tar.gz" >> "${GITHUB_OUTPUT}"
@@ -145,8 +203,9 @@ jobs:
env:
ARCHIVE_URL: ${{ steps.create-archive.outputs.archive_url }}
BUCKET_PREFIX: "gs://coder-traiage-outputs/traiage"
+ CODER_USERNAME: ${{ steps.get-coder-username.outputs.coder_username }}
CONTEXT_KEY: ${{ steps.extract-context.outputs.context_key }}
- GITHUB_TOKEN: ${{ github.token }}
+ GH_TOKEN: ${{ github.token }}
GITHUB_REPOSITORY: ${{ github.repository }}
ISSUE_URL: ${{ inputs.issue_url }}
TASK_NAME: ${{ steps.create-task.outputs.TASK_NAME }}
From 257fb768828e991df3715da69f6a67d10256ee3b Mon Sep 17 00:00:00 2001
From: Cian Johnston
Date: Wed, 1 Oct 2025 15:50:40 +0100
Subject: [PATCH 002/298] ci: automatically determine issue URL when invoked
via issue label assignment (#20089)
Silly me forgot that `inputs.*` will likely be empty when invoked
outside of `workflow_dispatch`.
Sample run:
https://github.com/coder/coder/actions/runs/18165531528/job/51706661391
---
.github/workflows/traiage.yaml | 24 +++++++++++++++++++++---
1 file changed, 21 insertions(+), 3 deletions(-)
diff --git a/.github/workflows/traiage.yaml b/.github/workflows/traiage.yaml
index dc45f242dbb87..24192fc2d1812 100644
--- a/.github/workflows/traiage.yaml
+++ b/.github/workflows/traiage.yaml
@@ -94,10 +94,28 @@ jobs:
fi
echo "::notice::User ${GITHUB_USERNAME} verified as member of ${GITHUB_ORG} organization"
+ - name: Determine issue URL
+ id: determine-issue-url
+ env:
+ INPUTS_ISSUE_URL: ${{ inputs.issue_url }}
+ GITHUB_EVENT_ISSUE_HTML_URL: ${{ github.event.issue.html_url }}
+ GITHUB_EVENT_NAME: ${{ github.event_name }}
+ run: |
+ if [[ "${GITHUB_EVENT_NAME}" == "workflow_dispatch" ]]; then
+ echo "issue_url=${INPUTS_ISSUE_URL}" >> "${GITHUB_OUTPUT}"
+ exit 0
+ elif [[ "${GITHUB_EVENT_NAME}" == "issues" ]]; then
+ echo "issue_url=${GITHUB_EVENT_ISSUE_HTML_URL}" >> "${GITHUB_OUTPUT}"
+ exit 0
+ else
+ echo "::error::Unsupported event type: ${GITHUB_EVENT_NAME}"
+ exit 1
+ fi
+
- name: Extract context key from issue
id: extract-context
env:
- ISSUE_URL: ${{ inputs.issue_url }}
+ ISSUE_URL: ${{ steps.determine-issue-url.outputs.issue_url }}
GH_TOKEN: ${{ github.token }}
run: |
issue_number="$(gh issue view "${ISSUE_URL}" --json number --jq '.number')"
@@ -151,7 +169,7 @@ jobs:
CONTEXT_KEY: ${{ steps.extract-context.outputs.context_key }}
GH_TOKEN: ${{ github.token }}
GITHUB_REPOSITORY: ${{ github.repository }}
- ISSUE_URL: ${{ inputs.issue_url }}
+ ISSUE_URL: ${{ steps.determine-issue-url.outputs.issue_url }}
PREFIX: ${{ inputs.prefix }}
RUN_ID: ${{ github.run_id }}
TEMPLATE_PARAMETERS: ${{ secrets.TRAIAGE_TEMPLATE_PARAMETERS }}
@@ -207,7 +225,7 @@ jobs:
CONTEXT_KEY: ${{ steps.extract-context.outputs.context_key }}
GH_TOKEN: ${{ github.token }}
GITHUB_REPOSITORY: ${{ github.repository }}
- ISSUE_URL: ${{ inputs.issue_url }}
+ ISSUE_URL: ${{ steps.determine-issue-url.outputs.issue_url }}
TASK_NAME: ${{ steps.create-task.outputs.TASK_NAME }}
run: |
SUMMARY_FILE=$(mktemp)
From 3a56ea56a7f5357902ca4ed5c1aff54bf40b899f Mon Sep 17 00:00:00 2001
From: Steven Masley
Date: Wed, 1 Oct 2025 13:23:51 -0500
Subject: [PATCH 003/298] test: fix rbac benchmark to test performance instead
of cache (#20097)
The benchmark should be testing the performance of `authorize`, not a
cache lookup
---
coderd/rbac/authz_test.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/coderd/rbac/authz_test.go b/coderd/rbac/authz_test.go
index cd2bbb808add9..25955131242a8 100644
--- a/coderd/rbac/authz_test.go
+++ b/coderd/rbac/authz_test.go
@@ -187,7 +187,7 @@ func BenchmarkRBACAuthorizeGroups(b *testing.B) {
uuid.MustParse("0632b012-49e0-4d70-a5b3-f4398f1dcd52"),
uuid.MustParse("70dbaa7a-ea9c-4f68-a781-97b08af8461d"),
)
- authorizer := rbac.NewStrictCachingAuthorizer(prometheus.NewRegistry())
+ authorizer := rbac.NewAuthorizer(prometheus.NewRegistry())
// Same benchmark cases, but this time groups will be used to match.
// Some '*' permissions will still match, but using a fake action reduces
From 0fbe21e574dc27b5f9cc2bb50aec29c84c40926c Mon Sep 17 00:00:00 2001
From: Bruno Quaresma
Date: Wed, 1 Oct 2025 15:24:20 -0300
Subject: [PATCH 004/298] chore: downgrade msw and @radix-ui/dialog (#20098)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The upgrade caused the following error:
```
node: ../deps/uv/src/unix/stream.c:456: uv__stream_destroy: Assertion `!uv__io_active(&stream->io_watcher, POLLIN | POLLOUT)' failed.
```
After downgrading `msw`, a new error appeared only in
`WorkspacesPage.test.tsx`:
```
<--- Last few GCs --->
[2799:0x292c2000] 16790 ms: Scavenge 336.1 (443.3) -> 322.8 (443.3) MB, pooled: 32 MB, 6.45 / 0.00 ms (average mu = 0.997, current mu = 0.996) allocation failure;
[2799:0x292c2000] 16883 ms: Scavenge 336.7 (443.3) -> 326.8 (443.3) MB, pooled: 32 MB, 8.29 / 0.00 ms (average mu = 0.997, current mu = 0.996) allocation failure;
[2799:0x292c2000] 16989 ms: Scavenge 339.6 (443.3) -> 329.1 (443.3) MB, pooled: 32 MB, 9.87 / 0.00 ms (average mu = 0.997, current mu = 0.996) allocation failure;
```
After some debugging, I traced it to `@radix-ui/dialog`. I didn’t find
any open issues about memory leaks there, so my guess is it’s just using
more memory than our default allocation. Jest has an option to increase
the memory limit, but we should be fine for now.
Related issue:
[https://github.com/mswjs/msw/issues/2537](https://github.com/mswjs/msw/issues/2537)
---
site/package.json | 4 +-
site/pnpm-lock.yaml | 308 ++++++++++++++++++++------------------------
2 files changed, 139 insertions(+), 173 deletions(-)
diff --git a/site/package.json b/site/package.json
index 7a52d5545eb8d..11ed58a05838a 100644
--- a/site/package.json
+++ b/site/package.json
@@ -55,7 +55,7 @@
"@radix-ui/react-avatar": "1.1.2",
"@radix-ui/react-checkbox": "1.1.4",
"@radix-ui/react-collapsible": "1.1.2",
- "@radix-ui/react-dialog": "1.1.15",
+ "@radix-ui/react-dialog": "1.1.4",
"@radix-ui/react-dropdown-menu": "2.1.4",
"@radix-ui/react-label": "2.1.0",
"@radix-ui/react-popover": "1.1.5",
@@ -169,7 +169,7 @@
"jest-websocket-mock": "2.5.0",
"jest_workaround": "0.1.14",
"knip": "5.64.1",
- "msw": "2.11.3",
+ "msw": "2.4.8",
"postcss": "8.5.1",
"protobufjs": "7.4.0",
"rollup-plugin-visualizer": "5.14.0",
diff --git a/site/pnpm-lock.yaml b/site/pnpm-lock.yaml
index c77df41bc3ede..676011c935c76 100644
--- a/site/pnpm-lock.yaml
+++ b/site/pnpm-lock.yaml
@@ -80,8 +80,8 @@ importers:
specifier: 1.1.2
version: 1.1.2(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
'@radix-ui/react-dialog':
- specifier: 1.1.15
- version: 1.1.15(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ specifier: 1.1.4
+ version: 1.1.4(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
'@radix-ui/react-dropdown-menu':
specifier: 2.1.4
version: 2.1.4(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
@@ -283,7 +283,7 @@ importers:
version: 2.2.0
'@chromatic-com/storybook':
specifier: 4.1.0
- version: 4.1.0(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.11.3(@types/node@20.17.16)(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)))
+ version: 4.1.0(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)))
'@octokit/types':
specifier: 12.3.0
version: 12.3.0
@@ -292,16 +292,16 @@ importers:
version: 1.55.1
'@storybook/addon-docs':
specifier: 9.1.2
- version: 9.1.2(@types/react@19.1.13)(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.11.3(@types/node@20.17.16)(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)))
+ version: 9.1.2(@types/react@19.1.13)(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)))
'@storybook/addon-links':
specifier: 9.1.2
- version: 9.1.2(react@19.1.1)(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.11.3(@types/node@20.17.16)(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)))
+ version: 9.1.2(react@19.1.1)(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)))
'@storybook/addon-themes':
specifier: 9.1.2
- version: 9.1.2(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.11.3(@types/node@20.17.16)(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)))
+ version: 9.1.2(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)))
'@storybook/react-vite':
specifier: 9.1.2
- version: 9.1.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(rollup@4.52.3)(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.11.3(@types/node@20.17.16)(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)))(typescript@5.6.3)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0))
+ version: 9.1.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(rollup@4.52.3)(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)))(typescript@5.6.3)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0))
'@swc/core':
specifier: 1.3.38
version: 1.3.38
@@ -417,8 +417,8 @@ importers:
specifier: 5.64.1
version: 5.64.1(@types/node@20.17.16)(typescript@5.6.3)
msw:
- specifier: 2.11.3
- version: 2.11.3(@types/node@20.17.16)(typescript@5.6.3)
+ specifier: 2.4.8
+ version: 2.4.8(typescript@5.6.3)
postcss:
specifier: 8.5.1
version: 8.5.1
@@ -436,10 +436,10 @@ importers:
version: 1.17.0
storybook:
specifier: 9.1.2
- version: 9.1.2(@testing-library/dom@10.4.0)(msw@2.11.3(@types/node@20.17.16)(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0))
+ version: 9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0))
storybook-addon-remix-react-router:
specifier: 5.0.0
- version: 5.0.0(react-dom@19.1.1(react@19.1.1))(react-router@7.8.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react@19.1.1)(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.11.3(@types/node@20.17.16)(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)))
+ version: 5.0.0(react-dom@19.1.1(react@19.1.1))(react-router@7.8.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react@19.1.1)(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)))
tailwindcss:
specifier: 3.4.17
version: 3.4.17(ts-node@10.9.2(@swc/core@1.3.38)(@types/node@20.17.16)(typescript@5.6.3))
@@ -717,6 +717,9 @@ packages:
'@bundled-es-modules/statuses@1.0.1':
resolution: {integrity: sha512-yn7BklA5acgcBr+7w064fGV+SGIFySjCKpqjcWgBAIfrAkY+4GQTJJHQMeT3V/sgz23VTEVV8TtOmkvJAhFVfg==, tarball: https://registry.npmjs.org/@bundled-es-modules/statuses/-/statuses-1.0.1.tgz}
+ '@bundled-es-modules/tough-cookie@0.1.6':
+ resolution: {integrity: sha512-dvMHbL464C0zI+Yqxbz6kZ5TOEp7GLW+pry/RWndAR8MJQAXZ2rPmIs8tziTZjeIyhSNZgZbCePtfSbdWqStJw==, tarball: https://registry.npmjs.org/@bundled-es-modules/tough-cookie/-/tough-cookie-0.1.6.tgz}
+
'@chromatic-com/storybook@4.1.0':
resolution: {integrity: sha512-B9XesFX5lQUdP81/QBTtkiYOFqEsJwQpzkZlcYPm2n/L1S/8ZabSPbz6NoY8hOJTXWZ2p7grygUlxyGy+gAvfQ==, tarball: https://registry.npmjs.org/@chromatic-com/storybook/-/storybook-4.1.0.tgz}
engines: {node: '>=20.0.0', yarn: '>=1.22.18'}
@@ -1189,40 +1192,25 @@ packages:
peerDependencies:
react: '*'
- '@inquirer/ansi@1.0.0':
- resolution: {integrity: sha512-JWaTfCxI1eTmJ1BIv86vUfjVatOdxwD0DAVKYevY8SazeUUZtW+tNbsdejVO1GYE0GXJW1N1ahmiC3TFd+7wZA==, tarball: https://registry.npmjs.org/@inquirer/ansi/-/ansi-1.0.0.tgz}
+ '@inquirer/confirm@3.2.0':
+ resolution: {integrity: sha512-oOIwPs0Dvq5220Z8lGL/6LHRTEr9TgLHmiI99Rj1PJ1p1czTys+olrgBqZk4E2qC0YTzeHprxSQmoHioVdJ7Lw==, tarball: https://registry.npmjs.org/@inquirer/confirm/-/confirm-3.2.0.tgz}
engines: {node: '>=18'}
- '@inquirer/confirm@5.1.18':
- resolution: {integrity: sha512-MilmWOzHa3Ks11tzvuAmFoAd/wRuaP3SwlT1IZhyMke31FKLxPiuDWcGXhU+PKveNOpAc4axzAgrgxuIJJRmLw==, tarball: https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.18.tgz}
+ '@inquirer/core@9.2.1':
+ resolution: {integrity: sha512-F2VBt7W/mwqEU4bL0RnHNZmC/OxzNx9cOYxHqnXX3MP6ruYvZUZAW9imgN9+h/uBT/oP8Gh888J2OZSbjSeWcg==, tarball: https://registry.npmjs.org/@inquirer/core/-/core-9.2.1.tgz}
engines: {node: '>=18'}
- peerDependencies:
- '@types/node': '>=18'
- peerDependenciesMeta:
- '@types/node':
- optional: true
-
- '@inquirer/core@10.2.2':
- resolution: {integrity: sha512-yXq/4QUnk4sHMtmbd7irwiepjB8jXU0kkFRL4nr/aDBA2mDz13cMakEWdDwX3eSCTkk03kwcndD1zfRAIlELxA==, tarball: https://registry.npmjs.org/@inquirer/core/-/core-10.2.2.tgz}
- engines: {node: '>=18'}
- peerDependencies:
- '@types/node': '>=18'
- peerDependenciesMeta:
- '@types/node':
- optional: true
'@inquirer/figures@1.0.13':
resolution: {integrity: sha512-lGPVU3yO9ZNqA7vTYz26jny41lE7yoQansmqdMLBEfqaGsmdg7V3W9mK9Pvb5IL4EVZ9GnSDGMO/cJXud5dMaw==, tarball: https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.13.tgz}
engines: {node: '>=18'}
- '@inquirer/type@3.0.8':
- resolution: {integrity: sha512-lg9Whz8onIHRthWaN1Q9EGLa/0LFJjyM8mEUbL1eTi6yMGvBf8gvyDLtxSXztQsxMvhxxNpJYrwa1YHdq+w4Jw==, tarball: https://registry.npmjs.org/@inquirer/type/-/type-3.0.8.tgz}
+ '@inquirer/type@1.5.5':
+ resolution: {integrity: sha512-MzICLu4yS7V8AA61sANROZ9vT1H3ooca5dSmI1FjZkzq7o/koMsRfQSzRtFo+F3Ao4Sf1C0bpLKejpKB/+j6MA==, tarball: https://registry.npmjs.org/@inquirer/type/-/type-1.5.5.tgz}
+ engines: {node: '>=18'}
+
+ '@inquirer/type@2.0.0':
+ resolution: {integrity: sha512-XvJRx+2KR3YXyYtPUUy+qd9i7p+GO9Ko6VIIpWlBrpWwXDv8WLFeHTxz35CfQFUiBMLXlGHhGzys7lqit9gWag==, tarball: https://registry.npmjs.org/@inquirer/type/-/type-2.0.0.tgz}
engines: {node: '>=18'}
- peerDependencies:
- '@types/node': '>=18'
- peerDependenciesMeta:
- '@types/node':
- optional: true
'@isaacs/cliui@8.0.2':
resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==, tarball: https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz}
@@ -1391,8 +1379,8 @@ packages:
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
- '@mswjs/interceptors@0.39.7':
- resolution: {integrity: sha512-sURvQbbKsq5f8INV54YJgJEdk8oxBanqkTiXXd33rKmofFCwZLhLRszPduMZ9TA9b8/1CHc/IJmOlBHJk2Q5AQ==, tarball: https://registry.npmjs.org/@mswjs/interceptors/-/interceptors-0.39.7.tgz}
+ '@mswjs/interceptors@0.35.9':
+ resolution: {integrity: sha512-SSnyl/4ni/2ViHKkiZb8eajA/eN1DNFaHjhGiLUdZvDz6PKF4COSf/17xqSz64nOo2Ia29SA6B2KNCsyCbVmaQ==, tarball: https://registry.npmjs.org/@mswjs/interceptors/-/interceptors-0.35.9.tgz}
engines: {node: '>=18'}
'@mui/core-downloads-tracker@5.18.0':
@@ -1839,8 +1827,8 @@ packages:
'@types/react':
optional: true
- '@radix-ui/react-dialog@1.1.15':
- resolution: {integrity: sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw==, tarball: https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.15.tgz}
+ '@radix-ui/react-dialog@1.1.4':
+ resolution: {integrity: sha512-Ur7EV1IwQGCyaAuyDRiOLA5JIUZxELJljF+MbM/2NC0BYwfuRrbpS30BiQBJrVruscgUkieKkqXYDOoByaxIoA==, tarball: https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.4.tgz}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
@@ -2088,19 +2076,6 @@ packages:
'@types/react-dom':
optional: true
- '@radix-ui/react-presence@1.1.5':
- resolution: {integrity: sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==, tarball: https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.5.tgz}
- peerDependencies:
- '@types/react': '*'
- '@types/react-dom': '*'
- react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
- react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
- peerDependenciesMeta:
- '@types/react':
- optional: true
- '@types/react-dom':
- optional: true
-
'@radix-ui/react-primitive@2.0.0':
resolution: {integrity: sha512-ZSpFm0/uHa8zTvKBDjLFWLo8dkr4MBsiDLz0g3gMUwqgLHz9rTaRRGYDgvZPtBJgYCBKXkS9fzmoySgr8CO6Cw==, tarball: https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.0.tgz}
peerDependencies:
@@ -2970,12 +2945,18 @@ packages:
'@types/ms@2.1.0':
resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==, tarball: https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz}
+ '@types/mute-stream@0.0.4':
+ resolution: {integrity: sha512-CPM9nzrCPPJHQNA9keH9CVkVI+WR5kMa+7XEs5jcGQ0VoAGnLv242w8lIVgwAEfmE4oufJRaTc9PNLQl0ioAow==, tarball: https://registry.npmjs.org/@types/mute-stream/-/mute-stream-0.0.4.tgz}
+
'@types/node@18.19.129':
resolution: {integrity: sha512-hrmi5jWt2w60ayox3iIXwpMEnfUvOLJCRtrOPbHtH15nTjvO7uhnelvrdAs0dO0/zl5DZ3ZbahiaXEVb54ca/A==, tarball: https://registry.npmjs.org/@types/node/-/node-18.19.129.tgz}
'@types/node@20.17.16':
resolution: {integrity: sha512-vOTpLduLkZXePLxHiHsBLp98mHGnl8RptV4YAO3HfKO5UHjDvySGbxKtpYfy8Sx5+WKcgc45qNreJJRVM3L6mw==, tarball: https://registry.npmjs.org/@types/node/-/node-20.17.16.tgz}
+ '@types/node@22.18.8':
+ resolution: {integrity: sha512-pAZSHMiagDR7cARo/cch1f3rXy0AEXwsVsVH09FcyeJVAzCnGgmYis7P3JidtTUjyadhTeSo8TgRPswstghDaw==, tarball: https://registry.npmjs.org/@types/node/-/node-22.18.8.tgz}
+
'@types/parse-json@4.0.2':
resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==, tarball: https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz}
@@ -3053,6 +3034,9 @@ packages:
'@types/tough-cookie@4.0.2':
resolution: {integrity: sha512-Q5vtl1W5ue16D+nIaW8JWebSSraJVlK+EthKn7e7UcD4KWsaSJ8BqGPXNaPghgtcn/fhvrN17Tv8ksUsQpiplw==, tarball: https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.2.tgz}
+ '@types/tough-cookie@4.0.5':
+ resolution: {integrity: sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==, tarball: https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz}
+
'@types/ua-parser-js@0.7.36':
resolution: {integrity: sha512-N1rW+njavs70y2cApeIw1vLMYXRwfBy+7trgavGuuTfOd7j1Yh7QTRc/yqsPl6ncokt72ZXuxEU0PiCp9bSwNQ==, tarball: https://registry.npmjs.org/@types/ua-parser-js/-/ua-parser-js-0.7.36.tgz}
@@ -3068,6 +3052,9 @@ packages:
'@types/uuid@9.0.2':
resolution: {integrity: sha512-kNnC1GFBLuhImSnV7w4njQkUiJi0ZXUycu1rUaouPqiKlXkh77JKgdRnTAp1x5eBwcIwbtI+3otwzuIDEuDoxQ==, tarball: https://registry.npmjs.org/@types/uuid/-/uuid-9.0.2.tgz}
+ '@types/wrap-ansi@3.0.0':
+ resolution: {integrity: sha512-ltIpx+kM7g/MLRZfkbL7EsCEjfzCcScLpkg37eXEtx5kmrAKBkTJwd1GIAjDSL8wTpM6Hzn5YO4pSb91BEwu1g==, tarball: https://registry.npmjs.org/@types/wrap-ansi/-/wrap-ansi-3.0.0.tgz}
+
'@types/yargs-parser@21.0.2':
resolution: {integrity: sha512-5qcvofLPbfjmBfKaLfj/+f+Sbd6pN4zl7w7VSVI5uz7m9QZTuB2aZAa2uo1wHFBNN2x6g/SoTkXmd8mQnQF2Cw==, tarball: https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.2.tgz}
@@ -5224,8 +5211,8 @@ packages:
ms@2.1.3:
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==, tarball: https://registry.npmjs.org/ms/-/ms-2.1.3.tgz}
- msw@2.11.3:
- resolution: {integrity: sha512-878imp8jxIpfzuzxYfX0qqTq1IFQz/1/RBHs/PyirSjzi+xKM/RRfIpIqHSCWjH0GxidrjhgiiXC+DWXNDvT9w==, tarball: https://registry.npmjs.org/msw/-/msw-2.11.3.tgz}
+ msw@2.4.8:
+ resolution: {integrity: sha512-a+FUW1m5yT8cV9GBy0L/cbNg0EA4//SKEzgu3qFrpITrWYeZmqfo7dqtM74T2lAl69jjUjjCaEhZKaxG2Ns8DA==, tarball: https://registry.npmjs.org/msw/-/msw-2.4.8.tgz}
engines: {node: '>=18'}
hasBin: true
peerDependencies:
@@ -5234,9 +5221,9 @@ packages:
typescript:
optional: true
- mute-stream@2.0.0:
- resolution: {integrity: sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==, tarball: https://registry.npmjs.org/mute-stream/-/mute-stream-2.0.0.tgz}
- engines: {node: ^18.17.0 || >=20.5.0}
+ mute-stream@1.0.0:
+ resolution: {integrity: sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==, tarball: https://registry.npmjs.org/mute-stream/-/mute-stream-1.0.0.tgz}
+ engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
mz@2.7.0:
resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==, tarball: https://registry.npmjs.org/mz/-/mz-2.7.0.tgz}
@@ -5876,9 +5863,6 @@ packages:
resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==, tarball: https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz}
engines: {node: '>=8'}
- rettime@0.7.0:
- resolution: {integrity: sha512-LPRKoHnLKd/r3dVxcwO7vhCW+orkOGj9ViueosEBK6ie89CijnfRlhaDhHq/3Hxu4CkWQtxwlBG0mzTQY6uQjw==, tarball: https://registry.npmjs.org/rettime/-/rettime-0.7.0.tgz}
-
reusify@1.1.0:
resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==, tarball: https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz}
engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
@@ -6220,13 +6204,6 @@ packages:
resolution: {integrity: sha512-t2T/WLB2WRgZ9EpE4jgPJ9w+i66UZfDc8wHh0xrwiRNN+UwH98GIJkTeZqX9rg0i0ptwzqW+uYeIF0T4F8LR7A==, tarball: https://registry.npmjs.org/tinyspy/-/tinyspy-4.0.3.tgz}
engines: {node: '>=14.0.0'}
- tldts-core@7.0.16:
- resolution: {integrity: sha512-XHhPmHxphLi+LGbH0G/O7dmUH9V65OY20R7vH8gETHsp5AZCjBk9l8sqmRKLaGOxnETU7XNSDUPtewAy/K6jbA==, tarball: https://registry.npmjs.org/tldts-core/-/tldts-core-7.0.16.tgz}
-
- tldts@7.0.16:
- resolution: {integrity: sha512-5bdPHSwbKTeHmXrgecID4Ljff8rQjv7g8zKQPkCozRo2HWWni+p310FSn5ImI+9kWw9kK4lzOB5q/a6iv0IJsw==, tarball: https://registry.npmjs.org/tldts/-/tldts-7.0.16.tgz}
- hasBin: true
-
tmpl@1.0.5:
resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==, tarball: https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz}
@@ -6245,10 +6222,6 @@ packages:
resolution: {integrity: sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==, tarball: https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz}
engines: {node: '>=6'}
- tough-cookie@6.0.0:
- resolution: {integrity: sha512-kXuRi1mtaKMrsLUxz3sQYvVl37B0Ns6MzfrtV5DvJceE9bPyspOqk9xxv7XbZWcfLWbFmm997vl83qUWVJA64w==, tarball: https://registry.npmjs.org/tough-cookie/-/tough-cookie-6.0.0.tgz}
- engines: {node: '>=16'}
-
tr46@3.0.0:
resolution: {integrity: sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==, tarball: https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz}
engines: {node: '>=12'}
@@ -6355,6 +6328,9 @@ packages:
undici-types@6.19.8:
resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==, tarball: https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz}
+ undici-types@6.21.0:
+ resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==, tarball: https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz}
+
undici@6.21.3:
resolution: {integrity: sha512-gBLkYIlEnSp8pFbT64yFgGE6UIB9tAkhukC23PmMDCe5Nd+cRqKxSjw5y54MK2AZMgZfJWMaNE4nYUHgi1XEOw==, tarball: https://registry.npmjs.org/undici/-/undici-6.21.3.tgz}
engines: {node: '>=18.17'}
@@ -6407,9 +6383,6 @@ packages:
unplugin@1.5.0:
resolution: {integrity: sha512-9ZdRwbh/4gcm1JTOkp9lAkIDrtOyOxgHmY7cjuwI8L/2RTikMcVG25GsZwNAgRuap3iDw2jeq7eoqtAsz5rW3A==, tarball: https://registry.npmjs.org/unplugin/-/unplugin-1.5.0.tgz}
- until-async@3.0.2:
- resolution: {integrity: sha512-IiSk4HlzAMqTUseHHe3VhIGyuFmN90zMTpD3Z3y8jeQbzLIq500MVM7Jq2vUAnTKAFPJrqwkzr6PoTcPhGcOiw==, tarball: https://registry.npmjs.org/until-async/-/until-async-3.0.2.tgz}
-
update-browserslist-db@1.1.1:
resolution: {integrity: sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==, tarball: https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz}
hasBin: true
@@ -7021,13 +6994,18 @@ snapshots:
dependencies:
statuses: 2.0.2
- '@chromatic-com/storybook@4.1.0(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.11.3(@types/node@20.17.16)(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)))':
+ '@bundled-es-modules/tough-cookie@0.1.6':
+ dependencies:
+ '@types/tough-cookie': 4.0.5
+ tough-cookie: 4.1.4
+
+ '@chromatic-com/storybook@4.1.0(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)))':
dependencies:
'@neoconfetti/react': 1.0.0
chromatic: 12.2.0
filesize: 10.1.2
jsonfile: 6.1.0
- storybook: 9.1.2(@testing-library/dom@10.4.0)(msw@2.11.3(@types/node@20.17.16)(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0))
+ storybook: 9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0))
strip-ansi: 7.1.0
transitivePeerDependencies:
- '@chromatic-com/cypress'
@@ -7397,33 +7375,35 @@ snapshots:
dependencies:
react: 19.1.1
- '@inquirer/ansi@1.0.0': {}
-
- '@inquirer/confirm@5.1.18(@types/node@20.17.16)':
+ '@inquirer/confirm@3.2.0':
dependencies:
- '@inquirer/core': 10.2.2(@types/node@20.17.16)
- '@inquirer/type': 3.0.8(@types/node@20.17.16)
- optionalDependencies:
- '@types/node': 20.17.16
+ '@inquirer/core': 9.2.1
+ '@inquirer/type': 1.5.5
- '@inquirer/core@10.2.2(@types/node@20.17.16)':
+ '@inquirer/core@9.2.1':
dependencies:
- '@inquirer/ansi': 1.0.0
'@inquirer/figures': 1.0.13
- '@inquirer/type': 3.0.8(@types/node@20.17.16)
+ '@inquirer/type': 2.0.0
+ '@types/mute-stream': 0.0.4
+ '@types/node': 22.18.8
+ '@types/wrap-ansi': 3.0.0
+ ansi-escapes: 4.3.2
cli-width: 4.1.0
- mute-stream: 2.0.0
+ mute-stream: 1.0.0
signal-exit: 4.1.0
+ strip-ansi: 6.0.1
wrap-ansi: 6.2.0
yoctocolors-cjs: 2.1.3
- optionalDependencies:
- '@types/node': 20.17.16
'@inquirer/figures@1.0.13': {}
- '@inquirer/type@3.0.8(@types/node@20.17.16)':
- optionalDependencies:
- '@types/node': 20.17.16
+ '@inquirer/type@1.5.5':
+ dependencies:
+ mute-stream: 1.0.0
+
+ '@inquirer/type@2.0.0':
+ dependencies:
+ mute-stream: 1.0.0
'@isaacs/cliui@8.0.2':
dependencies:
@@ -7715,7 +7695,7 @@ snapshots:
react: 19.1.1
react-dom: 19.1.1(react@19.1.1)
- '@mswjs/interceptors@0.39.7':
+ '@mswjs/interceptors@0.35.9':
dependencies:
'@open-draft/deferred-promise': 2.2.0
'@open-draft/logger': 0.3.0
@@ -8100,20 +8080,20 @@ snapshots:
optionalDependencies:
'@types/react': 19.1.13
- '@radix-ui/react-dialog@1.1.15(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
+ '@radix-ui/react-dialog@1.1.4(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
dependencies:
- '@radix-ui/primitive': 1.1.3
- '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-context': 1.1.2(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@radix-ui/react-id': 1.1.1(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@radix-ui/react-slot': 1.2.3(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.13)(react@19.1.1)
+ '@radix-ui/primitive': 1.1.1
+ '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.1.13)(react@19.1.1)
+ '@radix-ui/react-context': 1.1.1(@types/react@19.1.13)(react@19.1.1)
+ '@radix-ui/react-dismissable-layer': 1.1.3(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-focus-guards': 1.1.1(@types/react@19.1.13)(react@19.1.1)
+ '@radix-ui/react-focus-scope': 1.1.1(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-id': 1.1.0(@types/react@19.1.13)(react@19.1.1)
+ '@radix-ui/react-portal': 1.1.3(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-presence': 1.1.2(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-primitive': 2.0.1(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-slot': 1.1.1(@types/react@19.1.13)(react@19.1.1)
+ '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.1.13)(react@19.1.1)
aria-hidden: 1.2.6
react: 19.1.1
react-dom: 19.1.1(react@19.1.1)
@@ -8360,16 +8340,6 @@ snapshots:
'@types/react': 19.1.13
'@types/react-dom': 19.1.9(@types/react@19.1.13)
- '@radix-ui/react-presence@1.1.5(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
- dependencies:
- '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.13)(react@19.1.1)
- react: 19.1.1
- react-dom: 19.1.1(react@19.1.1)
- optionalDependencies:
- '@types/react': 19.1.13
- '@types/react-dom': 19.1.9(@types/react@19.1.13)
-
'@radix-ui/react-primitive@2.0.0(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
dependencies:
'@radix-ui/react-slot': 1.1.0(@types/react@19.1.13)(react@19.1.1)
@@ -8803,41 +8773,41 @@ snapshots:
dependencies:
'@sinonjs/commons': 3.0.0
- '@storybook/addon-docs@9.1.2(@types/react@19.1.13)(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.11.3(@types/node@20.17.16)(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)))':
+ '@storybook/addon-docs@9.1.2(@types/react@19.1.13)(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)))':
dependencies:
'@mdx-js/react': 3.0.1(@types/react@19.1.13)(react@19.1.1)
- '@storybook/csf-plugin': 9.1.2(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.11.3(@types/node@20.17.16)(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)))
+ '@storybook/csf-plugin': 9.1.2(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)))
'@storybook/icons': 1.4.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@storybook/react-dom-shim': 9.1.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.11.3(@types/node@20.17.16)(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)))
+ '@storybook/react-dom-shim': 9.1.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)))
react: 19.1.1
react-dom: 19.1.1(react@19.1.1)
- storybook: 9.1.2(@testing-library/dom@10.4.0)(msw@2.11.3(@types/node@20.17.16)(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0))
+ storybook: 9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0))
ts-dedent: 2.2.0
transitivePeerDependencies:
- '@types/react'
- '@storybook/addon-links@9.1.2(react@19.1.1)(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.11.3(@types/node@20.17.16)(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)))':
+ '@storybook/addon-links@9.1.2(react@19.1.1)(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)))':
dependencies:
'@storybook/global': 5.0.0
- storybook: 9.1.2(@testing-library/dom@10.4.0)(msw@2.11.3(@types/node@20.17.16)(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0))
+ storybook: 9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0))
optionalDependencies:
react: 19.1.1
- '@storybook/addon-themes@9.1.2(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.11.3(@types/node@20.17.16)(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)))':
+ '@storybook/addon-themes@9.1.2(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)))':
dependencies:
- storybook: 9.1.2(@testing-library/dom@10.4.0)(msw@2.11.3(@types/node@20.17.16)(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0))
+ storybook: 9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0))
ts-dedent: 2.2.0
- '@storybook/builder-vite@9.1.2(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.11.3(@types/node@20.17.16)(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)))(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0))':
+ '@storybook/builder-vite@9.1.2(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)))(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0))':
dependencies:
- '@storybook/csf-plugin': 9.1.2(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.11.3(@types/node@20.17.16)(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)))
- storybook: 9.1.2(@testing-library/dom@10.4.0)(msw@2.11.3(@types/node@20.17.16)(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0))
+ '@storybook/csf-plugin': 9.1.2(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)))
+ storybook: 9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0))
ts-dedent: 2.2.0
vite: 7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)
- '@storybook/csf-plugin@9.1.2(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.11.3(@types/node@20.17.16)(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)))':
+ '@storybook/csf-plugin@9.1.2(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)))':
dependencies:
- storybook: 9.1.2(@testing-library/dom@10.4.0)(msw@2.11.3(@types/node@20.17.16)(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0))
+ storybook: 9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0))
unplugin: 1.5.0
'@storybook/global@5.0.0': {}
@@ -8847,25 +8817,25 @@ snapshots:
react: 19.1.1
react-dom: 19.1.1(react@19.1.1)
- '@storybook/react-dom-shim@9.1.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.11.3(@types/node@20.17.16)(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)))':
+ '@storybook/react-dom-shim@9.1.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)))':
dependencies:
react: 19.1.1
react-dom: 19.1.1(react@19.1.1)
- storybook: 9.1.2(@testing-library/dom@10.4.0)(msw@2.11.3(@types/node@20.17.16)(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0))
+ storybook: 9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0))
- '@storybook/react-vite@9.1.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(rollup@4.52.3)(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.11.3(@types/node@20.17.16)(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)))(typescript@5.6.3)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0))':
+ '@storybook/react-vite@9.1.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(rollup@4.52.3)(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)))(typescript@5.6.3)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0))':
dependencies:
'@joshwooding/vite-plugin-react-docgen-typescript': 0.6.1(typescript@5.6.3)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0))
'@rollup/pluginutils': 5.0.5(rollup@4.52.3)
- '@storybook/builder-vite': 9.1.2(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.11.3(@types/node@20.17.16)(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)))(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0))
- '@storybook/react': 9.1.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.11.3(@types/node@20.17.16)(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)))(typescript@5.6.3)
+ '@storybook/builder-vite': 9.1.2(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)))(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0))
+ '@storybook/react': 9.1.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)))(typescript@5.6.3)
find-up: 7.0.0
magic-string: 0.30.17
react: 19.1.1
react-docgen: 8.0.0
react-dom: 19.1.1(react@19.1.1)
resolve: 1.22.10
- storybook: 9.1.2(@testing-library/dom@10.4.0)(msw@2.11.3(@types/node@20.17.16)(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0))
+ storybook: 9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0))
tsconfig-paths: 4.2.0
vite: 7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)
transitivePeerDependencies:
@@ -8873,13 +8843,13 @@ snapshots:
- supports-color
- typescript
- '@storybook/react@9.1.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.11.3(@types/node@20.17.16)(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)))(typescript@5.6.3)':
+ '@storybook/react@9.1.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)))(typescript@5.6.3)':
dependencies:
'@storybook/global': 5.0.0
- '@storybook/react-dom-shim': 9.1.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.11.3(@types/node@20.17.16)(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)))
+ '@storybook/react-dom-shim': 9.1.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)))
react: 19.1.1
react-dom: 19.1.1(react@19.1.1)
- storybook: 9.1.2(@testing-library/dom@10.4.0)(msw@2.11.3(@types/node@20.17.16)(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0))
+ storybook: 9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0))
optionalDependencies:
typescript: 5.6.3
@@ -9199,6 +9169,10 @@ snapshots:
'@types/ms@2.1.0': {}
+ '@types/mute-stream@0.0.4':
+ dependencies:
+ '@types/node': 20.17.16
+
'@types/node@18.19.129':
dependencies:
undici-types: 5.26.5
@@ -9207,6 +9181,10 @@ snapshots:
dependencies:
undici-types: 6.19.8
+ '@types/node@22.18.8':
+ dependencies:
+ undici-types: 6.21.0
+
'@types/parse-json@4.0.2': {}
'@types/prop-types@15.7.15': {}
@@ -9284,6 +9262,8 @@ snapshots:
'@types/tough-cookie@4.0.2': {}
+ '@types/tough-cookie@4.0.5': {}
+
'@types/ua-parser-js@0.7.36': {}
'@types/unist@2.0.11': {}
@@ -9294,6 +9274,8 @@ snapshots:
'@types/uuid@9.0.2': {}
+ '@types/wrap-ansi@3.0.0': {}
+
'@types/yargs-parser@21.0.2': {}
'@types/yargs-parser@21.0.3': {}
@@ -9328,13 +9310,13 @@ snapshots:
chai: 5.2.1
tinyrainbow: 2.0.0
- '@vitest/mocker@3.2.4(msw@2.11.3(@types/node@20.17.16)(typescript@5.6.3))(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0))':
+ '@vitest/mocker@3.2.4(msw@2.4.8(typescript@5.6.3))(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0))':
dependencies:
'@vitest/spy': 3.2.4
estree-walker: 3.0.3
magic-string: 0.30.17
optionalDependencies:
- msw: 2.11.3(@types/node@20.17.16)(typescript@5.6.3)
+ msw: 2.4.8(typescript@5.6.3)
vite: 7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)
'@vitest/pretty-format@3.2.4':
@@ -9787,7 +9769,7 @@ snapshots:
cmdk@1.0.4(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1):
dependencies:
- '@radix-ui/react-dialog': 1.1.15(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-dialog': 1.1.4(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
'@radix-ui/react-id': 1.1.0(@types/react@19.1.13)(react@19.1.1)
'@radix-ui/react-primitive': 2.0.1(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
react: 19.1.1
@@ -12078,33 +12060,29 @@ snapshots:
ms@2.1.3: {}
- msw@2.11.3(@types/node@20.17.16)(typescript@5.6.3):
+ msw@2.4.8(typescript@5.6.3):
dependencies:
'@bundled-es-modules/cookie': 2.0.1
'@bundled-es-modules/statuses': 1.0.1
- '@inquirer/confirm': 5.1.18(@types/node@20.17.16)
- '@mswjs/interceptors': 0.39.7
- '@open-draft/deferred-promise': 2.2.0
+ '@bundled-es-modules/tough-cookie': 0.1.6
+ '@inquirer/confirm': 3.2.0
+ '@mswjs/interceptors': 0.35.9
+ '@open-draft/until': 2.1.0
'@types/cookie': 0.6.0
'@types/statuses': 2.0.6
+ chalk: 4.1.2
graphql: 16.11.0
headers-polyfill: 4.0.3
is-node-process: 1.2.0
outvariant: 1.4.3
path-to-regexp: 6.3.0
- picocolors: 1.1.1
- rettime: 0.7.0
strict-event-emitter: 0.5.1
- tough-cookie: 6.0.0
type-fest: 4.41.0
- until-async: 3.0.2
yargs: 17.7.2
optionalDependencies:
typescript: 5.6.3
- transitivePeerDependencies:
- - '@types/node'
- mute-stream@2.0.0: {}
+ mute-stream@1.0.0: {}
mz@2.7.0:
dependencies:
@@ -12812,8 +12790,6 @@ snapshots:
onetime: 5.1.2
signal-exit: 3.0.7
- rettime@0.7.0: {}
-
reusify@1.1.0: {}
rimraf@3.0.2:
@@ -13015,24 +12991,24 @@ snapshots:
dependencies:
internal-slot: 1.0.6
- storybook-addon-remix-react-router@5.0.0(react-dom@19.1.1(react@19.1.1))(react-router@7.8.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react@19.1.1)(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.11.3(@types/node@20.17.16)(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0))):
+ storybook-addon-remix-react-router@5.0.0(react-dom@19.1.1(react@19.1.1))(react-router@7.8.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react@19.1.1)(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0))):
dependencies:
'@mjackson/form-data-parser': 0.4.0
compare-versions: 6.1.0
react-inspector: 6.0.2(react@19.1.1)
react-router: 7.8.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- storybook: 9.1.2(@testing-library/dom@10.4.0)(msw@2.11.3(@types/node@20.17.16)(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0))
+ storybook: 9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0))
optionalDependencies:
react: 19.1.1
react-dom: 19.1.1(react@19.1.1)
- storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.11.3(@types/node@20.17.16)(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)):
+ storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)):
dependencies:
'@storybook/global': 5.0.0
'@testing-library/jest-dom': 6.6.3
'@testing-library/user-event': 14.6.1(@testing-library/dom@10.4.0)
'@vitest/expect': 3.2.4
- '@vitest/mocker': 3.2.4(msw@2.11.3(@types/node@20.17.16)(typescript@5.6.3))(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0))
+ '@vitest/mocker': 3.2.4(msw@2.4.8(typescript@5.6.3))(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0))
'@vitest/spy': 3.2.4
better-opn: 3.0.2
esbuild: 0.25.3
@@ -13211,12 +13187,6 @@ snapshots:
tinyspy@4.0.3: {}
- tldts-core@7.0.16: {}
-
- tldts@7.0.16:
- dependencies:
- tldts-core: 7.0.16
-
tmpl@1.0.5: {}
to-regex-range@5.0.1:
@@ -13234,10 +13204,6 @@ snapshots:
universalify: 0.2.0
url-parse: 1.5.10
- tough-cookie@6.0.0:
- dependencies:
- tldts: 7.0.16
-
tr46@3.0.0:
dependencies:
punycode: 2.3.1
@@ -13334,6 +13300,8 @@ snapshots:
undici-types@6.19.8: {}
+ undici-types@6.21.0: {}
+
undici@6.21.3: {}
unicorn-magic@0.1.0: {}
@@ -13398,8 +13366,6 @@ snapshots:
webpack-sources: 3.2.3
webpack-virtual-modules: 0.5.0
- until-async@3.0.2: {}
-
update-browserslist-db@1.1.1(browserslist@4.24.2):
dependencies:
browserslist: 4.24.2
From f23a6a1140157b20c3b4ba1198e01c8d67c8f7f6 Mon Sep 17 00:00:00 2001
From: Bruno Quaresma
Date: Wed, 1 Oct 2025 15:37:11 -0300
Subject: [PATCH 005/298] feat: add remove task button into the tasks list
(#20036)
**Demo:**
https://github.com/user-attachments/assets/eca91a46-41fb-412c-b476-0cf91c0b69b8
Closes https://github.com/coder/coder/issues/19525
---
.../TaskDeleteDialog.stories.tsx | 50 +++++++++++++
.../TaskDeleteDialog/TaskDeleteDialog.tsx | 58 ++++++++++++++
.../TasksSidebar/TasksSidebar.stories.tsx | 52 +------------
.../tasks/TasksSidebar/TasksSidebar.tsx | 46 +++---------
.../src/pages/TasksPage/TasksPage.stories.tsx | 14 ++++
site/src/pages/TasksPage/TasksTable.tsx | 75 ++++++++++++++-----
6 files changed, 189 insertions(+), 106 deletions(-)
create mode 100644 site/src/modules/tasks/TaskDeleteDialog/TaskDeleteDialog.stories.tsx
create mode 100644 site/src/modules/tasks/TaskDeleteDialog/TaskDeleteDialog.tsx
diff --git a/site/src/modules/tasks/TaskDeleteDialog/TaskDeleteDialog.stories.tsx b/site/src/modules/tasks/TaskDeleteDialog/TaskDeleteDialog.stories.tsx
new file mode 100644
index 0000000000000..e595c26a7884e
--- /dev/null
+++ b/site/src/modules/tasks/TaskDeleteDialog/TaskDeleteDialog.stories.tsx
@@ -0,0 +1,50 @@
+import { MockTasks, MockWorkspace } from "testHelpers/entities";
+import { withGlobalSnackbar } from "testHelpers/storybook";
+import type { Meta, StoryObj } from "@storybook/react-vite";
+import { API } from "api/api";
+import { expect, spyOn, userEvent, waitFor, within } from "storybook/test";
+import { TaskDeleteDialog } from "./TaskDeleteDialog";
+
+const meta: Meta = {
+ title: "modules/tasks/TaskDeleteDialog",
+ component: TaskDeleteDialog,
+ decorators: [withGlobalSnackbar],
+};
+
+export default meta;
+type Story = StoryObj;
+
+export const DeleteTaskSuccess: Story = {
+ decorators: [withGlobalSnackbar],
+ args: {
+ open: true,
+ task: { prompt: "My Task", workspace: MockWorkspace },
+ onClose: () => {},
+ },
+ parameters: {
+ chromatic: {
+ disableSnapshot: false,
+ },
+ },
+ beforeEach: () => {
+ spyOn(API.experimental, "deleteTask").mockResolvedValue();
+ },
+ play: async ({ canvasElement, step }) => {
+ const body = within(canvasElement.ownerDocument.body);
+
+ await step("Confirm delete", async () => {
+ const confirmButton = await body.findByRole("button", {
+ name: /delete/i,
+ });
+ await userEvent.click(confirmButton);
+ await step("Confirm delete", async () => {
+ await waitFor(() => {
+ expect(API.experimental.deleteTask).toHaveBeenCalledWith(
+ MockTasks[0].workspace.owner_name,
+ MockTasks[0].workspace.id,
+ );
+ });
+ });
+ });
+ },
+};
diff --git a/site/src/modules/tasks/TaskDeleteDialog/TaskDeleteDialog.tsx b/site/src/modules/tasks/TaskDeleteDialog/TaskDeleteDialog.tsx
new file mode 100644
index 0000000000000..b5bac134a66e4
--- /dev/null
+++ b/site/src/modules/tasks/TaskDeleteDialog/TaskDeleteDialog.tsx
@@ -0,0 +1,58 @@
+import { API } from "api/api";
+import { getErrorDetail, getErrorMessage } from "api/errors";
+import { ConfirmDialog } from "components/Dialogs/ConfirmDialog/ConfirmDialog";
+import { displayError, displaySuccess } from "components/GlobalSnackbar/utils";
+import type { FC } from "react";
+import { QueryClient, useMutation } from "react-query";
+import type { Task } from "../tasks";
+
+type TaskDeleteDialogProps = {
+ open: boolean;
+ task: Task;
+ onClose: () => void;
+ onSuccess?: () => void;
+};
+
+export const TaskDeleteDialog: FC = ({
+ task,
+ onSuccess,
+ ...props
+}) => {
+ const queryClient = new QueryClient();
+ const deleteTaskMutation = useMutation({
+ mutationFn: () =>
+ API.experimental.deleteTask(task.workspace.owner_name, task.workspace.id),
+ onSuccess: async () => {
+ await queryClient.invalidateQueries({ queryKey: ["tasks"] });
+ },
+ });
+
+ return (
+ {
+ try {
+ await deleteTaskMutation.mutateAsync();
+ displaySuccess("Task deleted successfully");
+ onSuccess?.();
+ } catch (error) {
+ displayError(
+ getErrorMessage(error, "Failed to delete task"),
+ getErrorDetail(error),
+ );
+ } finally {
+ props.onClose();
+ }
+ }}
+ description={
+
+ This action is irreversible and removes all workspace resources and
+ data.
+
+ }
+ />
+ );
+};
diff --git a/site/src/modules/tasks/TasksSidebar/TasksSidebar.stories.tsx b/site/src/modules/tasks/TasksSidebar/TasksSidebar.stories.tsx
index 333b3db13cbf4..11fb2c54bbbb1 100644
--- a/site/src/modules/tasks/TasksSidebar/TasksSidebar.stories.tsx
+++ b/site/src/modules/tasks/TasksSidebar/TasksSidebar.stories.tsx
@@ -1,9 +1,9 @@
import { MockTasks, MockUserOwner, mockApiError } from "testHelpers/entities";
-import { withAuthProvider, withGlobalSnackbar } from "testHelpers/storybook";
+import { withAuthProvider } from "testHelpers/storybook";
import type { Meta, StoryObj } from "@storybook/react-vite";
import { API } from "api/api";
import { MockUsers } from "pages/UsersPage/storybookData/users";
-import { expect, spyOn, userEvent, waitFor, within } from "storybook/test";
+import { spyOn, userEvent, within } from "storybook/test";
import { reactRouterParameters } from "storybook-addon-remix-react-router";
import { TasksSidebar } from "./TasksSidebar";
@@ -93,7 +93,7 @@ export const OpenOptionsMenu: Story = {
},
};
-export const DeleteTaskDialog: Story = {
+export const OpenDeleteDialog: Story = {
beforeEach: () => {
spyOn(API.experimental, "getTasks").mockResolvedValue(MockTasks);
},
@@ -114,49 +114,3 @@ export const DeleteTaskDialog: Story = {
});
},
};
-
-export const DeleteTaskSuccess: Story = {
- decorators: [withGlobalSnackbar],
- parameters: {
- chromatic: {
- disableSnapshot: false,
- },
- },
- beforeEach: () => {
- spyOn(API.experimental, "getTasks").mockResolvedValue(MockTasks);
- spyOn(API.experimental, "deleteTask").mockResolvedValue();
- },
- play: async ({ canvasElement, step }) => {
- const body = within(canvasElement.ownerDocument.body);
- const canvas = within(canvasElement);
-
- await step("Open menu", async () => {
- const optionButtons = await canvas.findAllByRole("button", {
- name: /task options/i,
- });
- await userEvent.click(optionButtons[0]);
- });
-
- await step("Open delete dialog", async () => {
- const deleteButton = await body.findByRole("menuitem", {
- name: /delete/i,
- });
- await userEvent.click(deleteButton);
- });
-
- await step("Confirm delete", async () => {
- const confirmButton = await body.findByRole("button", {
- name: /delete/i,
- });
- await userEvent.click(confirmButton);
- await step("Confirm delete", async () => {
- await waitFor(() => {
- expect(API.experimental.deleteTask).toHaveBeenCalledWith(
- MockTasks[0].workspace.owner_name,
- MockTasks[0].workspace.id,
- );
- });
- });
- });
- },
-};
diff --git a/site/src/modules/tasks/TasksSidebar/TasksSidebar.tsx b/site/src/modules/tasks/TasksSidebar/TasksSidebar.tsx
index 0c440e6432aa5..b63366e1b98cc 100644
--- a/site/src/modules/tasks/TasksSidebar/TasksSidebar.tsx
+++ b/site/src/modules/tasks/TasksSidebar/TasksSidebar.tsx
@@ -1,8 +1,7 @@
import { API } from "api/api";
-import { getErrorDetail, getErrorMessage } from "api/errors";
+import { getErrorMessage } from "api/errors";
import { cva } from "class-variance-authority";
import { Button } from "components/Button/Button";
-import { ConfirmDialog } from "components/Dialogs/ConfirmDialog/ConfirmDialog";
import {
DropdownMenu,
DropdownMenuContent,
@@ -10,7 +9,6 @@ import {
DropdownMenuItem,
DropdownMenuTrigger,
} from "components/DropdownMenu/DropdownMenu";
-import { displayError, displaySuccess } from "components/GlobalSnackbar/utils";
import { CoderIcon } from "components/Icons/CoderIcon";
import { ScrollArea } from "components/ScrollArea/ScrollArea";
import { Skeleton } from "components/Skeleton/Skeleton";
@@ -25,9 +23,10 @@ import { useSearchParamsKey } from "hooks/useSearchParamsKey";
import { EditIcon, EllipsisIcon, PanelLeftIcon, TrashIcon } from "lucide-react";
import type { Task } from "modules/tasks/tasks";
import { type FC, useState } from "react";
-import { QueryClient, useMutation, useQuery } from "react-query";
+import { useQuery } from "react-query";
import { Link as RouterLink, useNavigate, useParams } from "react-router";
import { cn } from "utils/cn";
+import { TaskDeleteDialog } from "../TaskDeleteDialog/TaskDeleteDialog";
import { UserCombobox } from "./UserCombobox";
export const TasksSidebar: FC = () => {
@@ -180,14 +179,6 @@ const TaskSidebarMenuItem: FC = ({ task }) => {
const isActive = task.workspace.name === workspace;
const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false);
const navigate = useNavigate();
- const queryClient = new QueryClient();
- const deleteTaskMutation = useMutation({
- mutationFn: () =>
- API.experimental.deleteTask(task.workspace.owner_name, task.workspace.id),
- onSuccess: async () => {
- await queryClient.invalidateQueries({ queryKey: ["tasks"] });
- },
- });
return (
<>
@@ -249,36 +240,17 @@ const TaskSidebarMenuItem: FC = ({ task }) => {
- {
+ task={task}
+ onClose={() => {
setIsDeleteDialogOpen(false);
}}
- onConfirm={async () => {
- try {
- await deleteTaskMutation.mutateAsync();
- displaySuccess("Task deleted successfully");
- if (isActive) {
- navigate("/tasks");
- }
- } catch (error) {
- displayError(
- getErrorMessage(error, "Failed to delete task"),
- getErrorDetail(error),
- );
- } finally {
- setIsDeleteDialogOpen(false);
+ onSuccess={() => {
+ if (isActive) {
+ navigate("/tasks");
}
}}
- description={
-
- This action is irreversible and removes all workspace resources and
- data.
-
- }
/>
>
);
diff --git a/site/src/pages/TasksPage/TasksPage.stories.tsx b/site/src/pages/TasksPage/TasksPage.stories.tsx
index b0510bb6f4cab..7f4818bf00f4f 100644
--- a/site/src/pages/TasksPage/TasksPage.stories.tsx
+++ b/site/src/pages/TasksPage/TasksPage.stories.tsx
@@ -424,3 +424,17 @@ export const NonAdmin: Story = {
});
},
};
+
+export const OpenDeleteDialog: Story = {
+ beforeEach: () => {
+ spyOn(API, "getTemplates").mockResolvedValue([MockTemplate]);
+ spyOn(API.experimental, "getTasks").mockResolvedValue(MockTasks);
+ },
+ play: async ({ canvasElement }) => {
+ const canvas = within(canvasElement);
+ const deleteButtons = await canvas.findAllByRole("button", {
+ name: /delete task/i,
+ });
+ await userEvent.click(deleteButtons[0]);
+ },
+};
diff --git a/site/src/pages/TasksPage/TasksTable.tsx b/site/src/pages/TasksPage/TasksTable.tsx
index 883f3dd84cb5e..c1cddb75a8e8f 100644
--- a/site/src/pages/TasksPage/TasksTable.tsx
+++ b/site/src/pages/TasksPage/TasksTable.tsx
@@ -16,10 +16,17 @@ import {
TableLoaderSkeleton,
TableRowSkeleton,
} from "components/TableLoader/TableLoader";
-import { RotateCcwIcon } from "lucide-react";
+import {
+ Tooltip,
+ TooltipContent,
+ TooltipProvider,
+ TooltipTrigger,
+} from "components/Tooltip/Tooltip";
+import { RotateCcwIcon, TrashIcon } from "lucide-react";
+import { TaskDeleteDialog } from "modules/tasks/TaskDeleteDialog/TaskDeleteDialog";
import type { Task } from "modules/tasks/tasks";
import { WorkspaceAppStatus } from "modules/workspaces/WorkspaceAppStatus/WorkspaceAppStatus";
-import type { FC, ReactNode } from "react";
+import { type FC, type ReactNode, useState } from "react";
import { Link as RouterLink } from "react-router";
import { relativeTime } from "utils/time";
@@ -39,7 +46,7 @@ export const TasksTable: FC = ({ tasks, error, onRetry }) => {
} else if (tasks.length === 0) {
body = ;
} else {
- body = ;
+ body = tasks.map((task) => );
}
return (
@@ -49,6 +56,7 @@ export const TasksTable: FC = ({ tasks, error, onRetry }) => {
Task
Status
Created by
+
{body}
@@ -103,24 +111,25 @@ const TasksEmpty: FC = () => {
);
};
-type TasksProps = { tasks: Task[] };
+type TaskRowProps = { task: Task };
-const Tasks: FC = ({ tasks }) => {
- return tasks.map(({ workspace, prompt }) => {
- const templateDisplayName =
- workspace.template_display_name ?? workspace.template_name;
+const TaskRow: FC = ({ task }) => {
+ const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false);
+ const templateDisplayName =
+ task.workspace.template_display_name ?? task.workspace.template_name;
- return (
-
+ return (
+ <>
+
- {prompt}
+ {task.prompt}
Access task
@@ -132,7 +141,7 @@ const Tasks: FC = ({ tasks }) => {
}
@@ -140,24 +149,50 @@ const Tasks: FC = ({ tasks }) => {
- {relativeTime(new Date(workspace.created_at))}
+ {relativeTime(new Date(task.workspace.created_at))}
}
- src={workspace.owner_avatar_url}
+ src={task.workspace.owner_avatar_url}
/>
+
+
+
+
+ setIsDeleteDialogOpen(true)}
+ >
+ Delete task
+
+
+
+ Delete task
+
+
+
- );
- });
+
+ {
+ setIsDeleteDialogOpen(false);
+ }}
+ />
+ >
+ );
};
const TasksSkeleton: FC = () => {
From 718f712c1818dc86646665c7d4b0e1d446d94264 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 1 Oct 2025 18:38:25 +0000
Subject: [PATCH 006/298] chore: bump the react group across 1 directory with 2
updates (#20102)
Bumps the react group with 2 updates in the /site directory:
[@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react)
and
[@types/react-dom](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react-dom).
Updates `@types/react` from 19.1.13 to 19.1.17
Commits
Updates `@types/react-dom` from 19.1.9 to 19.1.11
Commits
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore ` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore ` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore ` will
remove the ignore condition of the specified dependency and ignore
conditions
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
site/package.json | 4 +-
site/pnpm-lock.yaml | 1072 ++++++++++++++++++++++---------------------
2 files changed, 540 insertions(+), 536 deletions(-)
diff --git a/site/package.json b/site/package.json
index 11ed58a05838a..14e3365fc6d54 100644
--- a/site/package.json
+++ b/site/package.json
@@ -145,10 +145,10 @@
"@types/jest": "29.5.14",
"@types/lodash": "4.17.15",
"@types/node": "20.17.16",
- "@types/react": "19.1.13",
+ "@types/react": "19.1.17",
"@types/react-color": "3.0.13",
"@types/react-date-range": "1.4.4",
- "@types/react-dom": "19.1.9",
+ "@types/react-dom": "19.1.11",
"@types/react-syntax-highlighter": "15.5.13",
"@types/react-virtualized-auto-sizer": "1.0.4",
"@types/react-window": "1.8.8",
diff --git a/site/pnpm-lock.yaml b/site/pnpm-lock.yaml
index 676011c935c76..f36ffa639e6d9 100644
--- a/site/pnpm-lock.yaml
+++ b/site/pnpm-lock.yaml
@@ -33,10 +33,10 @@ importers:
version: 11.13.5
'@emotion/react':
specifier: 11.14.0
- version: 11.14.0(@types/react@19.1.13)(react@19.1.1)
+ version: 11.14.0(@types/react@19.1.17)(react@19.1.1)
'@emotion/styled':
specifier: 11.14.1
- version: 11.14.1(@emotion/react@11.14.0(@types/react@19.1.13)(react@19.1.1))(@types/react@19.1.13)(react@19.1.1)
+ version: 11.14.1(@emotion/react@11.14.0(@types/react@19.1.17)(react@19.1.1))(@types/react@19.1.17)(react@19.1.1)
'@fontsource-variable/inter':
specifier: 5.1.1
version: 5.1.1
@@ -57,64 +57,64 @@ importers:
version: 4.7.0(monaco-editor@0.52.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
'@mui/icons-material':
specifier: 5.18.0
- version: 5.18.0(@mui/material@5.18.0(@emotion/react@11.14.0(@types/react@19.1.13)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.13)(react@19.1.1))(@types/react@19.1.13)(react@19.1.1))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@types/react@19.1.13)(react@19.1.1)
+ version: 5.18.0(@mui/material@5.18.0(@emotion/react@11.14.0(@types/react@19.1.17)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.17)(react@19.1.1))(@types/react@19.1.17)(react@19.1.1))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@types/react@19.1.17)(react@19.1.1)
'@mui/material':
specifier: 5.18.0
- version: 5.18.0(@emotion/react@11.14.0(@types/react@19.1.13)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.13)(react@19.1.1))(@types/react@19.1.13)(react@19.1.1))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ version: 5.18.0(@emotion/react@11.14.0(@types/react@19.1.17)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.17)(react@19.1.1))(@types/react@19.1.17)(react@19.1.1))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
'@mui/system':
specifier: 5.18.0
- version: 5.18.0(@emotion/react@11.14.0(@types/react@19.1.13)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.13)(react@19.1.1))(@types/react@19.1.13)(react@19.1.1))(@types/react@19.1.13)(react@19.1.1)
+ version: 5.18.0(@emotion/react@11.14.0(@types/react@19.1.17)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.17)(react@19.1.1))(@types/react@19.1.17)(react@19.1.1))(@types/react@19.1.17)(react@19.1.1)
'@mui/utils':
specifier: 5.17.1
- version: 5.17.1(@types/react@19.1.13)(react@19.1.1)
+ version: 5.17.1(@types/react@19.1.17)(react@19.1.1)
'@mui/x-tree-view':
specifier: 7.29.10
- version: 7.29.10(@emotion/react@11.14.0(@types/react@19.1.13)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.13)(react@19.1.1))(@types/react@19.1.13)(react@19.1.1))(@mui/material@5.18.0(@emotion/react@11.14.0(@types/react@19.1.13)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.13)(react@19.1.1))(@types/react@19.1.13)(react@19.1.1))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@mui/system@5.18.0(@emotion/react@11.14.0(@types/react@19.1.13)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.13)(react@19.1.1))(@types/react@19.1.13)(react@19.1.1))(@types/react@19.1.13)(react@19.1.1))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ version: 7.29.10(@emotion/react@11.14.0(@types/react@19.1.17)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.17)(react@19.1.1))(@types/react@19.1.17)(react@19.1.1))(@mui/material@5.18.0(@emotion/react@11.14.0(@types/react@19.1.17)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.17)(react@19.1.1))(@types/react@19.1.17)(react@19.1.1))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@mui/system@5.18.0(@emotion/react@11.14.0(@types/react@19.1.17)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.17)(react@19.1.1))(@types/react@19.1.17)(react@19.1.1))(@types/react@19.1.17)(react@19.1.1))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
'@radix-ui/react-avatar':
specifier: 1.1.2
- version: 1.1.2(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ version: 1.1.2(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
'@radix-ui/react-checkbox':
specifier: 1.1.4
- version: 1.1.4(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ version: 1.1.4(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
'@radix-ui/react-collapsible':
specifier: 1.1.2
- version: 1.1.2(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ version: 1.1.2(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
'@radix-ui/react-dialog':
specifier: 1.1.4
- version: 1.1.4(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ version: 1.1.4(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
'@radix-ui/react-dropdown-menu':
specifier: 2.1.4
- version: 2.1.4(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ version: 2.1.4(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
'@radix-ui/react-label':
specifier: 2.1.0
- version: 2.1.0(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ version: 2.1.0(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
'@radix-ui/react-popover':
specifier: 1.1.5
- version: 1.1.5(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ version: 1.1.5(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
'@radix-ui/react-radio-group':
specifier: 1.2.3
- version: 1.2.3(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ version: 1.2.3(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
'@radix-ui/react-scroll-area':
specifier: 1.2.3
- version: 1.2.3(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ version: 1.2.3(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
'@radix-ui/react-select':
specifier: 2.2.6
- version: 2.2.6(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ version: 2.2.6(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
'@radix-ui/react-separator':
specifier: 1.1.7
- version: 1.1.7(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ version: 1.1.7(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
'@radix-ui/react-slider':
specifier: 1.2.2
- version: 1.2.2(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ version: 1.2.2(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
'@radix-ui/react-slot':
specifier: 1.2.3
- version: 1.2.3(@types/react@19.1.13)(react@19.1.1)
+ version: 1.2.3(@types/react@19.1.17)(react@19.1.1)
'@radix-ui/react-switch':
specifier: 1.1.1
- version: 1.1.1(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ version: 1.1.1(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
'@radix-ui/react-tooltip':
specifier: 1.1.7
- version: 1.1.7(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ version: 1.1.7(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
'@tanstack/react-query-devtools':
specifier: 5.77.0
version: 5.77.0(@tanstack/react-query@5.77.0(react@19.1.1))(react@19.1.1)
@@ -153,7 +153,7 @@ importers:
version: 2.1.1
cmdk:
specifier: 1.0.4
- version: 1.0.4(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ version: 1.0.4(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
color-convert:
specifier: 2.0.1
version: 2.0.1
@@ -213,7 +213,7 @@ importers:
version: 19.1.1(react@19.1.1)
react-markdown:
specifier: 9.1.0
- version: 9.1.0(@types/react@19.1.13)(react@19.1.1)
+ version: 9.1.0(@types/react@19.1.17)(react@19.1.1)
react-query:
specifier: npm:@tanstack/react-query@5.77.0
version: '@tanstack/react-query@5.77.0(react@19.1.1)'
@@ -228,7 +228,7 @@ importers:
version: 15.6.1(react@19.1.1)
react-textarea-autosize:
specifier: 8.5.9
- version: 8.5.9(@types/react@19.1.13)(react@19.1.1)
+ version: 8.5.9(@types/react@19.1.17)(react@19.1.1)
react-virtualized-auto-sizer:
specifier: 1.0.24
version: 1.0.24(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
@@ -292,7 +292,7 @@ importers:
version: 1.55.1
'@storybook/addon-docs':
specifier: 9.1.2
- version: 9.1.2(@types/react@19.1.13)(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)))
+ version: 9.1.2(@types/react@19.1.17)(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)))
'@storybook/addon-links':
specifier: 9.1.2
version: 9.1.2(react@19.1.1)(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)))
@@ -316,7 +316,7 @@ importers:
version: 6.6.3
'@testing-library/react':
specifier: 14.3.1
- version: 14.3.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ version: 14.3.1(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
'@testing-library/user-event':
specifier: 14.6.1
version: 14.6.1(@testing-library/dom@10.4.0)
@@ -345,17 +345,17 @@ importers:
specifier: 20.17.16
version: 20.17.16
'@types/react':
- specifier: 19.1.13
- version: 19.1.13
+ specifier: 19.1.17
+ version: 19.1.17
'@types/react-color':
specifier: 3.0.13
- version: 3.0.13(@types/react@19.1.13)
+ version: 3.0.13(@types/react@19.1.17)
'@types/react-date-range':
specifier: 1.4.4
version: 1.4.4
'@types/react-dom':
- specifier: 19.1.9
- version: 19.1.9(@types/react@19.1.13)
+ specifier: 19.1.11
+ version: 19.1.11(@types/react@19.1.17)
'@types/react-syntax-highlighter':
specifier: 15.5.13
version: 15.5.13
@@ -2977,11 +2977,13 @@ packages:
'@types/react-date-range@1.4.4':
resolution: {integrity: sha512-9Y9NyNgaCsEVN/+O4HKuxzPbVjRVBGdOKRxMDcsTRWVG62lpYgnxefNckTXDWup8FvczoqPW0+ESZR6R1yymDg==, tarball: https://registry.npmjs.org/@types/react-date-range/-/react-date-range-1.4.4.tgz}
- '@types/react-dom@18.3.1':
- resolution: {integrity: sha512-qW1Mfv8taImTthu4KoXgDfLuk4bydU6Q/TkADnDWWHwi4NX4BR+LWfTp2sVmTqRrsHvyDDTelgelxJ+SsejKKQ==, tarball: https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.1.tgz}
+ '@types/react-dom@18.3.7':
+ resolution: {integrity: sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==, tarball: https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz}
+ peerDependencies:
+ '@types/react': ^18.0.0
- '@types/react-dom@19.1.9':
- resolution: {integrity: sha512-qXRuZaOsAdXKFyOhRBg6Lqqc0yay13vN7KrIg4L7N4aaHN68ma9OK3NE1BoDFgFOTfM7zg+3/8+2n8rLUH3OKQ==, tarball: https://registry.npmjs.org/@types/react-dom/-/react-dom-19.1.9.tgz}
+ '@types/react-dom@19.1.11':
+ resolution: {integrity: sha512-3BKc/yGdNTYQVVw4idqHtSOcFsgGuBbMveKCOgF8wQ5QtrYOc3jDIlzg3jef04zcXFIHLelyGlj0T+BJ8+KN+w==, tarball: https://registry.npmjs.org/@types/react-dom/-/react-dom-19.1.11.tgz}
peerDependencies:
'@types/react': ^19.0.0
@@ -2999,8 +3001,8 @@ packages:
'@types/react-window@1.8.8':
resolution: {integrity: sha512-8Ls660bHR1AUA2kuRvVG9D/4XpRC6wjAaPT9dil7Ckc76eP9TKWZwwmgfq8Q1LANX3QNDnoU4Zp48A3w+zK69Q==, tarball: https://registry.npmjs.org/@types/react-window/-/react-window-1.8.8.tgz}
- '@types/react@19.1.13':
- resolution: {integrity: sha512-hHkbU/eoO3EG5/MZkuFSKmYqPbSVk5byPFa3e7y/8TybHiLMACgI8seVYlicwk7H5K/rI2px9xrQp/C+AUDTiQ==, tarball: https://registry.npmjs.org/@types/react/-/react-19.1.13.tgz}
+ '@types/react@19.1.17':
+ resolution: {integrity: sha512-Qec1E3mhALmaspIrhWt9jkQMNdw6bReVu64mjvhbhq2NFPftLPVr+l1SZgmw/66WwBNpDh7ao5AT6gF5v41PFA==, tarball: https://registry.npmjs.org/@types/react/-/react-19.1.17.tgz}
'@types/reactcss@1.2.13':
resolution: {integrity: sha512-gi3S+aUi6kpkF5vdhUsnkwbiSEIU/BEJyD7kBy2SudWBUuKmJk8AQKE0OVcQQeEy40Azh0lV6uynxlikYIJuwg==, tarball: https://registry.npmjs.org/@types/reactcss/-/reactcss-1.2.13.tgz}
@@ -7081,7 +7083,7 @@ snapshots:
'@emotion/memoize@0.9.0': {}
- '@emotion/react@11.14.0(@types/react@19.1.13)(react@19.1.1)':
+ '@emotion/react@11.14.0(@types/react@19.1.17)(react@19.1.1)':
dependencies:
'@babel/runtime': 7.26.10
'@emotion/babel-plugin': 11.13.5
@@ -7093,7 +7095,7 @@ snapshots:
hoist-non-react-statics: 3.3.2
react: 19.1.1
optionalDependencies:
- '@types/react': 19.1.13
+ '@types/react': 19.1.17
transitivePeerDependencies:
- supports-color
@@ -7107,18 +7109,18 @@ snapshots:
'@emotion/sheet@1.4.0': {}
- '@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.13)(react@19.1.1))(@types/react@19.1.13)(react@19.1.1)':
+ '@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.17)(react@19.1.1))(@types/react@19.1.17)(react@19.1.1)':
dependencies:
'@babel/runtime': 7.26.10
'@emotion/babel-plugin': 11.13.5
'@emotion/is-prop-valid': 1.4.0
- '@emotion/react': 11.14.0(@types/react@19.1.13)(react@19.1.1)
+ '@emotion/react': 11.14.0(@types/react@19.1.17)(react@19.1.1)
'@emotion/serialize': 1.3.3
'@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@19.1.1)
'@emotion/utils': 1.4.2
react: 19.1.1
optionalDependencies:
- '@types/react': 19.1.13
+ '@types/react': 19.1.17
transitivePeerDependencies:
- supports-color
@@ -7668,10 +7670,10 @@ snapshots:
'@leeoniya/ufuzzy@1.0.10': {}
- '@mdx-js/react@3.0.1(@types/react@19.1.13)(react@19.1.1)':
+ '@mdx-js/react@3.0.1(@types/react@19.1.17)(react@19.1.1)':
dependencies:
'@types/mdx': 2.0.9
- '@types/react': 19.1.13
+ '@types/react': 19.1.17
react: 19.1.1
'@mjackson/form-data-parser@0.4.0':
@@ -7706,23 +7708,23 @@ snapshots:
'@mui/core-downloads-tracker@5.18.0': {}
- '@mui/icons-material@5.18.0(@mui/material@5.18.0(@emotion/react@11.14.0(@types/react@19.1.13)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.13)(react@19.1.1))(@types/react@19.1.13)(react@19.1.1))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@types/react@19.1.13)(react@19.1.1)':
+ '@mui/icons-material@5.18.0(@mui/material@5.18.0(@emotion/react@11.14.0(@types/react@19.1.17)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.17)(react@19.1.1))(@types/react@19.1.17)(react@19.1.1))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@types/react@19.1.17)(react@19.1.1)':
dependencies:
'@babel/runtime': 7.26.10
- '@mui/material': 5.18.0(@emotion/react@11.14.0(@types/react@19.1.13)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.13)(react@19.1.1))(@types/react@19.1.13)(react@19.1.1))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@mui/material': 5.18.0(@emotion/react@11.14.0(@types/react@19.1.17)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.17)(react@19.1.1))(@types/react@19.1.17)(react@19.1.1))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
react: 19.1.1
optionalDependencies:
- '@types/react': 19.1.13
+ '@types/react': 19.1.17
- '@mui/material@5.18.0(@emotion/react@11.14.0(@types/react@19.1.13)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.13)(react@19.1.1))(@types/react@19.1.13)(react@19.1.1))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
+ '@mui/material@5.18.0(@emotion/react@11.14.0(@types/react@19.1.17)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.17)(react@19.1.1))(@types/react@19.1.17)(react@19.1.1))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
dependencies:
'@babel/runtime': 7.26.10
'@mui/core-downloads-tracker': 5.18.0
- '@mui/system': 5.18.0(@emotion/react@11.14.0(@types/react@19.1.13)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.13)(react@19.1.1))(@types/react@19.1.13)(react@19.1.1))(@types/react@19.1.13)(react@19.1.1)
- '@mui/types': 7.2.24(@types/react@19.1.13)
- '@mui/utils': 5.17.1(@types/react@19.1.13)(react@19.1.1)
+ '@mui/system': 5.18.0(@emotion/react@11.14.0(@types/react@19.1.17)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.17)(react@19.1.1))(@types/react@19.1.17)(react@19.1.1))(@types/react@19.1.17)(react@19.1.1)
+ '@mui/types': 7.2.24(@types/react@19.1.17)
+ '@mui/utils': 5.17.1(@types/react@19.1.17)(react@19.1.1)
'@popperjs/core': 2.11.8
- '@types/react-transition-group': 4.4.12(@types/react@19.1.13)
+ '@types/react-transition-group': 4.4.12(@types/react@19.1.17)
clsx: 2.1.1
csstype: 3.1.3
prop-types: 15.8.1
@@ -7731,20 +7733,20 @@ snapshots:
react-is: 19.1.1
react-transition-group: 4.4.5(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
optionalDependencies:
- '@emotion/react': 11.14.0(@types/react@19.1.13)(react@19.1.1)
- '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.1.13)(react@19.1.1))(@types/react@19.1.13)(react@19.1.1)
- '@types/react': 19.1.13
+ '@emotion/react': 11.14.0(@types/react@19.1.17)(react@19.1.1)
+ '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.1.17)(react@19.1.1))(@types/react@19.1.17)(react@19.1.1)
+ '@types/react': 19.1.17
- '@mui/private-theming@5.17.1(@types/react@19.1.13)(react@19.1.1)':
+ '@mui/private-theming@5.17.1(@types/react@19.1.17)(react@19.1.1)':
dependencies:
'@babel/runtime': 7.26.10
- '@mui/utils': 5.17.1(@types/react@19.1.13)(react@19.1.1)
+ '@mui/utils': 5.17.1(@types/react@19.1.17)(react@19.1.1)
prop-types: 15.8.1
react: 19.1.1
optionalDependencies:
- '@types/react': 19.1.13
+ '@types/react': 19.1.17
- '@mui/styled-engine@5.18.0(@emotion/react@11.14.0(@types/react@19.1.13)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.13)(react@19.1.1))(@types/react@19.1.13)(react@19.1.1))(react@19.1.1)':
+ '@mui/styled-engine@5.18.0(@emotion/react@11.14.0(@types/react@19.1.17)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.17)(react@19.1.1))(@types/react@19.1.17)(react@19.1.1))(react@19.1.1)':
dependencies:
'@babel/runtime': 7.26.10
'@emotion/cache': 11.14.0
@@ -7753,65 +7755,65 @@ snapshots:
prop-types: 15.8.1
react: 19.1.1
optionalDependencies:
- '@emotion/react': 11.14.0(@types/react@19.1.13)(react@19.1.1)
- '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.1.13)(react@19.1.1))(@types/react@19.1.13)(react@19.1.1)
+ '@emotion/react': 11.14.0(@types/react@19.1.17)(react@19.1.1)
+ '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.1.17)(react@19.1.1))(@types/react@19.1.17)(react@19.1.1)
- '@mui/system@5.18.0(@emotion/react@11.14.0(@types/react@19.1.13)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.13)(react@19.1.1))(@types/react@19.1.13)(react@19.1.1))(@types/react@19.1.13)(react@19.1.1)':
+ '@mui/system@5.18.0(@emotion/react@11.14.0(@types/react@19.1.17)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.17)(react@19.1.1))(@types/react@19.1.17)(react@19.1.1))(@types/react@19.1.17)(react@19.1.1)':
dependencies:
'@babel/runtime': 7.26.10
- '@mui/private-theming': 5.17.1(@types/react@19.1.13)(react@19.1.1)
- '@mui/styled-engine': 5.18.0(@emotion/react@11.14.0(@types/react@19.1.13)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.13)(react@19.1.1))(@types/react@19.1.13)(react@19.1.1))(react@19.1.1)
- '@mui/types': 7.2.24(@types/react@19.1.13)
- '@mui/utils': 5.17.1(@types/react@19.1.13)(react@19.1.1)
+ '@mui/private-theming': 5.17.1(@types/react@19.1.17)(react@19.1.1)
+ '@mui/styled-engine': 5.18.0(@emotion/react@11.14.0(@types/react@19.1.17)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.17)(react@19.1.1))(@types/react@19.1.17)(react@19.1.1))(react@19.1.1)
+ '@mui/types': 7.2.24(@types/react@19.1.17)
+ '@mui/utils': 5.17.1(@types/react@19.1.17)(react@19.1.1)
clsx: 2.1.1
csstype: 3.1.3
prop-types: 15.8.1
react: 19.1.1
optionalDependencies:
- '@emotion/react': 11.14.0(@types/react@19.1.13)(react@19.1.1)
- '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.1.13)(react@19.1.1))(@types/react@19.1.13)(react@19.1.1)
- '@types/react': 19.1.13
+ '@emotion/react': 11.14.0(@types/react@19.1.17)(react@19.1.1)
+ '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.1.17)(react@19.1.1))(@types/react@19.1.17)(react@19.1.1)
+ '@types/react': 19.1.17
- '@mui/types@7.2.24(@types/react@19.1.13)':
+ '@mui/types@7.2.24(@types/react@19.1.17)':
optionalDependencies:
- '@types/react': 19.1.13
+ '@types/react': 19.1.17
- '@mui/utils@5.17.1(@types/react@19.1.13)(react@19.1.1)':
+ '@mui/utils@5.17.1(@types/react@19.1.17)(react@19.1.1)':
dependencies:
'@babel/runtime': 7.26.10
- '@mui/types': 7.2.24(@types/react@19.1.13)
+ '@mui/types': 7.2.24(@types/react@19.1.17)
'@types/prop-types': 15.7.15
clsx: 2.1.1
prop-types: 15.8.1
react: 19.1.1
react-is: 19.1.1
optionalDependencies:
- '@types/react': 19.1.13
+ '@types/react': 19.1.17
- '@mui/x-internals@7.29.0(@types/react@19.1.13)(react@19.1.1)':
+ '@mui/x-internals@7.29.0(@types/react@19.1.17)(react@19.1.1)':
dependencies:
'@babel/runtime': 7.26.10
- '@mui/utils': 5.17.1(@types/react@19.1.13)(react@19.1.1)
+ '@mui/utils': 5.17.1(@types/react@19.1.17)(react@19.1.1)
react: 19.1.1
transitivePeerDependencies:
- '@types/react'
- '@mui/x-tree-view@7.29.10(@emotion/react@11.14.0(@types/react@19.1.13)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.13)(react@19.1.1))(@types/react@19.1.13)(react@19.1.1))(@mui/material@5.18.0(@emotion/react@11.14.0(@types/react@19.1.13)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.13)(react@19.1.1))(@types/react@19.1.13)(react@19.1.1))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@mui/system@5.18.0(@emotion/react@11.14.0(@types/react@19.1.13)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.13)(react@19.1.1))(@types/react@19.1.13)(react@19.1.1))(@types/react@19.1.13)(react@19.1.1))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
+ '@mui/x-tree-view@7.29.10(@emotion/react@11.14.0(@types/react@19.1.17)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.17)(react@19.1.1))(@types/react@19.1.17)(react@19.1.1))(@mui/material@5.18.0(@emotion/react@11.14.0(@types/react@19.1.17)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.17)(react@19.1.1))(@types/react@19.1.17)(react@19.1.1))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@mui/system@5.18.0(@emotion/react@11.14.0(@types/react@19.1.17)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.17)(react@19.1.1))(@types/react@19.1.17)(react@19.1.1))(@types/react@19.1.17)(react@19.1.1))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
dependencies:
'@babel/runtime': 7.26.10
- '@mui/material': 5.18.0(@emotion/react@11.14.0(@types/react@19.1.13)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.13)(react@19.1.1))(@types/react@19.1.13)(react@19.1.1))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@mui/system': 5.18.0(@emotion/react@11.14.0(@types/react@19.1.13)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.13)(react@19.1.1))(@types/react@19.1.13)(react@19.1.1))(@types/react@19.1.13)(react@19.1.1)
- '@mui/utils': 5.17.1(@types/react@19.1.13)(react@19.1.1)
- '@mui/x-internals': 7.29.0(@types/react@19.1.13)(react@19.1.1)
- '@types/react-transition-group': 4.4.12(@types/react@19.1.13)
+ '@mui/material': 5.18.0(@emotion/react@11.14.0(@types/react@19.1.17)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.17)(react@19.1.1))(@types/react@19.1.17)(react@19.1.1))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@mui/system': 5.18.0(@emotion/react@11.14.0(@types/react@19.1.17)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.17)(react@19.1.1))(@types/react@19.1.17)(react@19.1.1))(@types/react@19.1.17)(react@19.1.1)
+ '@mui/utils': 5.17.1(@types/react@19.1.17)(react@19.1.1)
+ '@mui/x-internals': 7.29.0(@types/react@19.1.17)(react@19.1.1)
+ '@types/react-transition-group': 4.4.12(@types/react@19.1.17)
clsx: 2.1.1
prop-types: 15.8.1
react: 19.1.1
react-dom: 19.1.1(react@19.1.1)
react-transition-group: 4.4.5(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
optionalDependencies:
- '@emotion/react': 11.14.0(@types/react@19.1.13)(react@19.1.1)
- '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.1.13)(react@19.1.1))(@types/react@19.1.13)(react@19.1.1)
+ '@emotion/react': 11.14.0(@types/react@19.1.17)(react@19.1.1)
+ '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.1.17)(react@19.1.1))(@types/react@19.1.17)(react@19.1.1)
transitivePeerDependencies:
- '@types/react'
@@ -7952,736 +7954,736 @@ snapshots:
'@radix-ui/primitive@1.1.3': {}
- '@radix-ui/react-arrow@1.1.1(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
+ '@radix-ui/react-arrow@1.1.1(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
dependencies:
- '@radix-ui/react-primitive': 2.0.1(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-primitive': 2.0.1(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
react: 19.1.1
react-dom: 19.1.1(react@19.1.1)
optionalDependencies:
- '@types/react': 19.1.13
- '@types/react-dom': 19.1.9(@types/react@19.1.13)
+ '@types/react': 19.1.17
+ '@types/react-dom': 19.1.11(@types/react@19.1.17)
- '@radix-ui/react-arrow@1.1.7(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
+ '@radix-ui/react-arrow@1.1.7(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
dependencies:
- '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
react: 19.1.1
react-dom: 19.1.1(react@19.1.1)
optionalDependencies:
- '@types/react': 19.1.13
- '@types/react-dom': 19.1.9(@types/react@19.1.13)
+ '@types/react': 19.1.17
+ '@types/react-dom': 19.1.11(@types/react@19.1.17)
- '@radix-ui/react-avatar@1.1.2(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
+ '@radix-ui/react-avatar@1.1.2(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
dependencies:
- '@radix-ui/react-context': 1.1.1(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-primitive': 2.0.1(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.1.13)(react@19.1.1)
+ '@radix-ui/react-context': 1.1.1(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-primitive': 2.0.1(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.1.17)(react@19.1.1)
react: 19.1.1
react-dom: 19.1.1(react@19.1.1)
optionalDependencies:
- '@types/react': 19.1.13
- '@types/react-dom': 19.1.9(@types/react@19.1.13)
+ '@types/react': 19.1.17
+ '@types/react-dom': 19.1.11(@types/react@19.1.17)
- '@radix-ui/react-checkbox@1.1.4(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
+ '@radix-ui/react-checkbox@1.1.4(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
dependencies:
'@radix-ui/primitive': 1.1.1
- '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-context': 1.1.1(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-presence': 1.1.2(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-use-previous': 1.1.0(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-use-size': 1.1.0(@types/react@19.1.13)(react@19.1.1)
+ '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-context': 1.1.1(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-presence': 1.1.2(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-use-previous': 1.1.0(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-use-size': 1.1.0(@types/react@19.1.17)(react@19.1.1)
react: 19.1.1
react-dom: 19.1.1(react@19.1.1)
optionalDependencies:
- '@types/react': 19.1.13
- '@types/react-dom': 19.1.9(@types/react@19.1.13)
+ '@types/react': 19.1.17
+ '@types/react-dom': 19.1.11(@types/react@19.1.17)
- '@radix-ui/react-collapsible@1.1.2(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
+ '@radix-ui/react-collapsible@1.1.2(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
dependencies:
'@radix-ui/primitive': 1.1.1
- '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-context': 1.1.1(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-id': 1.1.0(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-presence': 1.1.2(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@radix-ui/react-primitive': 2.0.1(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.1.13)(react@19.1.1)
+ '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-context': 1.1.1(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-id': 1.1.0(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-presence': 1.1.2(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-primitive': 2.0.1(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.1.17)(react@19.1.1)
react: 19.1.1
react-dom: 19.1.1(react@19.1.1)
optionalDependencies:
- '@types/react': 19.1.13
- '@types/react-dom': 19.1.9(@types/react@19.1.13)
+ '@types/react': 19.1.17
+ '@types/react-dom': 19.1.11(@types/react@19.1.17)
- '@radix-ui/react-collection@1.1.1(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
+ '@radix-ui/react-collection@1.1.1(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
dependencies:
- '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-context': 1.1.1(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-primitive': 2.0.1(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@radix-ui/react-slot': 1.1.1(@types/react@19.1.13)(react@19.1.1)
+ '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-context': 1.1.1(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-primitive': 2.0.1(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-slot': 1.1.1(@types/react@19.1.17)(react@19.1.1)
react: 19.1.1
react-dom: 19.1.1(react@19.1.1)
optionalDependencies:
- '@types/react': 19.1.13
- '@types/react-dom': 19.1.9(@types/react@19.1.13)
+ '@types/react': 19.1.17
+ '@types/react-dom': 19.1.11(@types/react@19.1.17)
- '@radix-ui/react-collection@1.1.2(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
+ '@radix-ui/react-collection@1.1.2(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
dependencies:
- '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-context': 1.1.1(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@radix-ui/react-slot': 1.1.2(@types/react@19.1.13)(react@19.1.1)
+ '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-context': 1.1.1(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-slot': 1.1.2(@types/react@19.1.17)(react@19.1.1)
react: 19.1.1
react-dom: 19.1.1(react@19.1.1)
optionalDependencies:
- '@types/react': 19.1.13
- '@types/react-dom': 19.1.9(@types/react@19.1.13)
+ '@types/react': 19.1.17
+ '@types/react-dom': 19.1.11(@types/react@19.1.17)
- '@radix-ui/react-collection@1.1.7(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
+ '@radix-ui/react-collection@1.1.7(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
dependencies:
- '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-context': 1.1.2(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@radix-ui/react-slot': 1.2.3(@types/react@19.1.13)(react@19.1.1)
+ '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-context': 1.1.2(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-slot': 1.2.3(@types/react@19.1.17)(react@19.1.1)
react: 19.1.1
react-dom: 19.1.1(react@19.1.1)
optionalDependencies:
- '@types/react': 19.1.13
- '@types/react-dom': 19.1.9(@types/react@19.1.13)
+ '@types/react': 19.1.17
+ '@types/react-dom': 19.1.11(@types/react@19.1.17)
- '@radix-ui/react-compose-refs@1.1.0(@types/react@19.1.13)(react@19.1.1)':
+ '@radix-ui/react-compose-refs@1.1.0(@types/react@19.1.17)(react@19.1.1)':
dependencies:
react: 19.1.1
optionalDependencies:
- '@types/react': 19.1.13
+ '@types/react': 19.1.17
- '@radix-ui/react-compose-refs@1.1.1(@types/react@19.1.13)(react@19.1.1)':
+ '@radix-ui/react-compose-refs@1.1.1(@types/react@19.1.17)(react@19.1.1)':
dependencies:
react: 19.1.1
optionalDependencies:
- '@types/react': 19.1.13
+ '@types/react': 19.1.17
- '@radix-ui/react-compose-refs@1.1.2(@types/react@19.1.13)(react@19.1.1)':
+ '@radix-ui/react-compose-refs@1.1.2(@types/react@19.1.17)(react@19.1.1)':
dependencies:
react: 19.1.1
optionalDependencies:
- '@types/react': 19.1.13
+ '@types/react': 19.1.17
- '@radix-ui/react-context@1.1.1(@types/react@19.1.13)(react@19.1.1)':
+ '@radix-ui/react-context@1.1.1(@types/react@19.1.17)(react@19.1.1)':
dependencies:
react: 19.1.1
optionalDependencies:
- '@types/react': 19.1.13
+ '@types/react': 19.1.17
- '@radix-ui/react-context@1.1.2(@types/react@19.1.13)(react@19.1.1)':
+ '@radix-ui/react-context@1.1.2(@types/react@19.1.17)(react@19.1.1)':
dependencies:
react: 19.1.1
optionalDependencies:
- '@types/react': 19.1.13
+ '@types/react': 19.1.17
- '@radix-ui/react-dialog@1.1.4(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
+ '@radix-ui/react-dialog@1.1.4(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
dependencies:
'@radix-ui/primitive': 1.1.1
- '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-context': 1.1.1(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-dismissable-layer': 1.1.3(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@radix-ui/react-focus-guards': 1.1.1(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-focus-scope': 1.1.1(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@radix-ui/react-id': 1.1.0(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-portal': 1.1.3(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@radix-ui/react-presence': 1.1.2(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@radix-ui/react-primitive': 2.0.1(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@radix-ui/react-slot': 1.1.1(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.1.13)(react@19.1.1)
+ '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-context': 1.1.1(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-dismissable-layer': 1.1.3(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-focus-guards': 1.1.1(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-focus-scope': 1.1.1(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-id': 1.1.0(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-portal': 1.1.3(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-presence': 1.1.2(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-primitive': 2.0.1(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-slot': 1.1.1(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.1.17)(react@19.1.1)
aria-hidden: 1.2.6
react: 19.1.1
react-dom: 19.1.1(react@19.1.1)
- react-remove-scroll: 2.7.1(@types/react@19.1.13)(react@19.1.1)
+ react-remove-scroll: 2.7.1(@types/react@19.1.17)(react@19.1.1)
optionalDependencies:
- '@types/react': 19.1.13
- '@types/react-dom': 19.1.9(@types/react@19.1.13)
+ '@types/react': 19.1.17
+ '@types/react-dom': 19.1.11(@types/react@19.1.17)
- '@radix-ui/react-direction@1.1.0(@types/react@19.1.13)(react@19.1.1)':
+ '@radix-ui/react-direction@1.1.0(@types/react@19.1.17)(react@19.1.1)':
dependencies:
react: 19.1.1
optionalDependencies:
- '@types/react': 19.1.13
+ '@types/react': 19.1.17
- '@radix-ui/react-direction@1.1.1(@types/react@19.1.13)(react@19.1.1)':
+ '@radix-ui/react-direction@1.1.1(@types/react@19.1.17)(react@19.1.1)':
dependencies:
react: 19.1.1
optionalDependencies:
- '@types/react': 19.1.13
+ '@types/react': 19.1.17
- '@radix-ui/react-dismissable-layer@1.1.11(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
+ '@radix-ui/react-dismissable-layer@1.1.11(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
dependencies:
'@radix-ui/primitive': 1.1.3
- '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.1.13)(react@19.1.1)
+ '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.1.17)(react@19.1.1)
react: 19.1.1
react-dom: 19.1.1(react@19.1.1)
optionalDependencies:
- '@types/react': 19.1.13
- '@types/react-dom': 19.1.9(@types/react@19.1.13)
+ '@types/react': 19.1.17
+ '@types/react-dom': 19.1.11(@types/react@19.1.17)
- '@radix-ui/react-dismissable-layer@1.1.3(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
+ '@radix-ui/react-dismissable-layer@1.1.3(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
dependencies:
'@radix-ui/primitive': 1.1.1
- '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-primitive': 2.0.1(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-use-escape-keydown': 1.1.0(@types/react@19.1.13)(react@19.1.1)
+ '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-primitive': 2.0.1(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-use-escape-keydown': 1.1.0(@types/react@19.1.17)(react@19.1.1)
react: 19.1.1
react-dom: 19.1.1(react@19.1.1)
optionalDependencies:
- '@types/react': 19.1.13
- '@types/react-dom': 19.1.9(@types/react@19.1.13)
+ '@types/react': 19.1.17
+ '@types/react-dom': 19.1.11(@types/react@19.1.17)
- '@radix-ui/react-dismissable-layer@1.1.4(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
+ '@radix-ui/react-dismissable-layer@1.1.4(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
dependencies:
'@radix-ui/primitive': 1.1.1
- '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-primitive': 2.0.1(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-use-escape-keydown': 1.1.0(@types/react@19.1.13)(react@19.1.1)
+ '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-primitive': 2.0.1(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-use-escape-keydown': 1.1.0(@types/react@19.1.17)(react@19.1.1)
react: 19.1.1
react-dom: 19.1.1(react@19.1.1)
optionalDependencies:
- '@types/react': 19.1.13
- '@types/react-dom': 19.1.9(@types/react@19.1.13)
+ '@types/react': 19.1.17
+ '@types/react-dom': 19.1.11(@types/react@19.1.17)
- '@radix-ui/react-dropdown-menu@2.1.4(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
+ '@radix-ui/react-dropdown-menu@2.1.4(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
dependencies:
'@radix-ui/primitive': 1.1.1
- '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-context': 1.1.1(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-id': 1.1.0(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-menu': 2.1.4(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@radix-ui/react-primitive': 2.0.1(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.1.13)(react@19.1.1)
+ '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-context': 1.1.1(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-id': 1.1.0(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-menu': 2.1.4(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-primitive': 2.0.1(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.1.17)(react@19.1.1)
react: 19.1.1
react-dom: 19.1.1(react@19.1.1)
optionalDependencies:
- '@types/react': 19.1.13
- '@types/react-dom': 19.1.9(@types/react@19.1.13)
+ '@types/react': 19.1.17
+ '@types/react-dom': 19.1.11(@types/react@19.1.17)
- '@radix-ui/react-focus-guards@1.1.1(@types/react@19.1.13)(react@19.1.1)':
+ '@radix-ui/react-focus-guards@1.1.1(@types/react@19.1.17)(react@19.1.1)':
dependencies:
react: 19.1.1
optionalDependencies:
- '@types/react': 19.1.13
+ '@types/react': 19.1.17
- '@radix-ui/react-focus-guards@1.1.3(@types/react@19.1.13)(react@19.1.1)':
+ '@radix-ui/react-focus-guards@1.1.3(@types/react@19.1.17)(react@19.1.1)':
dependencies:
react: 19.1.1
optionalDependencies:
- '@types/react': 19.1.13
+ '@types/react': 19.1.17
- '@radix-ui/react-focus-scope@1.1.1(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
+ '@radix-ui/react-focus-scope@1.1.1(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
dependencies:
- '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-primitive': 2.0.1(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.1.13)(react@19.1.1)
+ '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-primitive': 2.0.1(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.1.17)(react@19.1.1)
react: 19.1.1
react-dom: 19.1.1(react@19.1.1)
optionalDependencies:
- '@types/react': 19.1.13
- '@types/react-dom': 19.1.9(@types/react@19.1.13)
+ '@types/react': 19.1.17
+ '@types/react-dom': 19.1.11(@types/react@19.1.17)
- '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
+ '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
dependencies:
- '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.13)(react@19.1.1)
+ '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.17)(react@19.1.1)
react: 19.1.1
react-dom: 19.1.1(react@19.1.1)
optionalDependencies:
- '@types/react': 19.1.13
- '@types/react-dom': 19.1.9(@types/react@19.1.13)
+ '@types/react': 19.1.17
+ '@types/react-dom': 19.1.11(@types/react@19.1.17)
- '@radix-ui/react-id@1.1.0(@types/react@19.1.13)(react@19.1.1)':
+ '@radix-ui/react-id@1.1.0(@types/react@19.1.17)(react@19.1.1)':
dependencies:
- '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.1.13)(react@19.1.1)
+ '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.1.17)(react@19.1.1)
react: 19.1.1
optionalDependencies:
- '@types/react': 19.1.13
+ '@types/react': 19.1.17
- '@radix-ui/react-id@1.1.1(@types/react@19.1.13)(react@19.1.1)':
+ '@radix-ui/react-id@1.1.1(@types/react@19.1.17)(react@19.1.1)':
dependencies:
- '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.13)(react@19.1.1)
+ '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.17)(react@19.1.1)
react: 19.1.1
optionalDependencies:
- '@types/react': 19.1.13
+ '@types/react': 19.1.17
- '@radix-ui/react-label@2.1.0(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
+ '@radix-ui/react-label@2.1.0(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
dependencies:
- '@radix-ui/react-primitive': 2.0.0(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-primitive': 2.0.0(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
react: 19.1.1
react-dom: 19.1.1(react@19.1.1)
optionalDependencies:
- '@types/react': 19.1.13
- '@types/react-dom': 19.1.9(@types/react@19.1.13)
+ '@types/react': 19.1.17
+ '@types/react-dom': 19.1.11(@types/react@19.1.17)
- '@radix-ui/react-menu@2.1.4(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
+ '@radix-ui/react-menu@2.1.4(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
dependencies:
'@radix-ui/primitive': 1.1.1
- '@radix-ui/react-collection': 1.1.1(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-context': 1.1.1(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-direction': 1.1.0(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-dismissable-layer': 1.1.3(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@radix-ui/react-focus-guards': 1.1.1(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-focus-scope': 1.1.1(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@radix-ui/react-id': 1.1.0(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-popper': 1.2.1(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@radix-ui/react-portal': 1.1.3(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@radix-ui/react-presence': 1.1.2(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@radix-ui/react-primitive': 2.0.1(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@radix-ui/react-roving-focus': 1.1.1(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@radix-ui/react-slot': 1.1.1(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.1.13)(react@19.1.1)
+ '@radix-ui/react-collection': 1.1.1(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-context': 1.1.1(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-direction': 1.1.0(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-dismissable-layer': 1.1.3(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-focus-guards': 1.1.1(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-focus-scope': 1.1.1(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-id': 1.1.0(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-popper': 1.2.1(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-portal': 1.1.3(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-presence': 1.1.2(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-primitive': 2.0.1(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-roving-focus': 1.1.1(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-slot': 1.1.1(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.1.17)(react@19.1.1)
aria-hidden: 1.2.6
react: 19.1.1
react-dom: 19.1.1(react@19.1.1)
- react-remove-scroll: 2.7.1(@types/react@19.1.13)(react@19.1.1)
+ react-remove-scroll: 2.7.1(@types/react@19.1.17)(react@19.1.1)
optionalDependencies:
- '@types/react': 19.1.13
- '@types/react-dom': 19.1.9(@types/react@19.1.13)
+ '@types/react': 19.1.17
+ '@types/react-dom': 19.1.11(@types/react@19.1.17)
- '@radix-ui/react-popover@1.1.5(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
+ '@radix-ui/react-popover@1.1.5(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
dependencies:
'@radix-ui/primitive': 1.1.1
- '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-context': 1.1.1(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-dismissable-layer': 1.1.4(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@radix-ui/react-focus-guards': 1.1.1(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-focus-scope': 1.1.1(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@radix-ui/react-id': 1.1.0(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-popper': 1.2.1(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@radix-ui/react-portal': 1.1.3(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@radix-ui/react-presence': 1.1.2(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@radix-ui/react-primitive': 2.0.1(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@radix-ui/react-slot': 1.1.1(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.1.13)(react@19.1.1)
+ '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-context': 1.1.1(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-dismissable-layer': 1.1.4(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-focus-guards': 1.1.1(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-focus-scope': 1.1.1(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-id': 1.1.0(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-popper': 1.2.1(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-portal': 1.1.3(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-presence': 1.1.2(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-primitive': 2.0.1(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-slot': 1.1.1(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.1.17)(react@19.1.1)
aria-hidden: 1.2.4
react: 19.1.1
react-dom: 19.1.1(react@19.1.1)
- react-remove-scroll: 2.6.3(@types/react@19.1.13)(react@19.1.1)
+ react-remove-scroll: 2.6.3(@types/react@19.1.17)(react@19.1.1)
optionalDependencies:
- '@types/react': 19.1.13
- '@types/react-dom': 19.1.9(@types/react@19.1.13)
+ '@types/react': 19.1.17
+ '@types/react-dom': 19.1.11(@types/react@19.1.17)
- '@radix-ui/react-popper@1.2.1(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
+ '@radix-ui/react-popper@1.2.1(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
dependencies:
'@floating-ui/react-dom': 2.1.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@radix-ui/react-arrow': 1.1.1(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-context': 1.1.1(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-primitive': 2.0.1(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-use-rect': 1.1.0(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-use-size': 1.1.0(@types/react@19.1.13)(react@19.1.1)
+ '@radix-ui/react-arrow': 1.1.1(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-context': 1.1.1(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-primitive': 2.0.1(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-use-rect': 1.1.0(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-use-size': 1.1.0(@types/react@19.1.17)(react@19.1.1)
'@radix-ui/rect': 1.1.0
react: 19.1.1
react-dom: 19.1.1(react@19.1.1)
optionalDependencies:
- '@types/react': 19.1.13
- '@types/react-dom': 19.1.9(@types/react@19.1.13)
+ '@types/react': 19.1.17
+ '@types/react-dom': 19.1.11(@types/react@19.1.17)
- '@radix-ui/react-popper@1.2.8(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
+ '@radix-ui/react-popper@1.2.8(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
dependencies:
'@floating-ui/react-dom': 2.1.6(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@radix-ui/react-arrow': 1.1.7(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-context': 1.1.2(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-use-rect': 1.1.1(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-use-size': 1.1.1(@types/react@19.1.13)(react@19.1.1)
+ '@radix-ui/react-arrow': 1.1.7(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-context': 1.1.2(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-use-rect': 1.1.1(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-use-size': 1.1.1(@types/react@19.1.17)(react@19.1.1)
'@radix-ui/rect': 1.1.1
react: 19.1.1
react-dom: 19.1.1(react@19.1.1)
optionalDependencies:
- '@types/react': 19.1.13
- '@types/react-dom': 19.1.9(@types/react@19.1.13)
+ '@types/react': 19.1.17
+ '@types/react-dom': 19.1.11(@types/react@19.1.17)
- '@radix-ui/react-portal@1.1.3(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
+ '@radix-ui/react-portal@1.1.3(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
dependencies:
- '@radix-ui/react-primitive': 2.0.1(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.1.13)(react@19.1.1)
+ '@radix-ui/react-primitive': 2.0.1(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.1.17)(react@19.1.1)
react: 19.1.1
react-dom: 19.1.1(react@19.1.1)
optionalDependencies:
- '@types/react': 19.1.13
- '@types/react-dom': 19.1.9(@types/react@19.1.13)
+ '@types/react': 19.1.17
+ '@types/react-dom': 19.1.11(@types/react@19.1.17)
- '@radix-ui/react-portal@1.1.9(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
+ '@radix-ui/react-portal@1.1.9(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
dependencies:
- '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.13)(react@19.1.1)
+ '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.17)(react@19.1.1)
react: 19.1.1
react-dom: 19.1.1(react@19.1.1)
optionalDependencies:
- '@types/react': 19.1.13
- '@types/react-dom': 19.1.9(@types/react@19.1.13)
+ '@types/react': 19.1.17
+ '@types/react-dom': 19.1.11(@types/react@19.1.17)
- '@radix-ui/react-presence@1.1.2(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
+ '@radix-ui/react-presence@1.1.2(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
dependencies:
- '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.1.13)(react@19.1.1)
+ '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.1.17)(react@19.1.1)
react: 19.1.1
react-dom: 19.1.1(react@19.1.1)
optionalDependencies:
- '@types/react': 19.1.13
- '@types/react-dom': 19.1.9(@types/react@19.1.13)
+ '@types/react': 19.1.17
+ '@types/react-dom': 19.1.11(@types/react@19.1.17)
- '@radix-ui/react-primitive@2.0.0(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
+ '@radix-ui/react-primitive@2.0.0(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
dependencies:
- '@radix-ui/react-slot': 1.1.0(@types/react@19.1.13)(react@19.1.1)
+ '@radix-ui/react-slot': 1.1.0(@types/react@19.1.17)(react@19.1.1)
react: 19.1.1
react-dom: 19.1.1(react@19.1.1)
optionalDependencies:
- '@types/react': 19.1.13
- '@types/react-dom': 19.1.9(@types/react@19.1.13)
+ '@types/react': 19.1.17
+ '@types/react-dom': 19.1.11(@types/react@19.1.17)
- '@radix-ui/react-primitive@2.0.1(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
+ '@radix-ui/react-primitive@2.0.1(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
dependencies:
- '@radix-ui/react-slot': 1.1.1(@types/react@19.1.13)(react@19.1.1)
+ '@radix-ui/react-slot': 1.1.1(@types/react@19.1.17)(react@19.1.1)
react: 19.1.1
react-dom: 19.1.1(react@19.1.1)
optionalDependencies:
- '@types/react': 19.1.13
- '@types/react-dom': 19.1.9(@types/react@19.1.13)
+ '@types/react': 19.1.17
+ '@types/react-dom': 19.1.11(@types/react@19.1.17)
- '@radix-ui/react-primitive@2.0.2(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
+ '@radix-ui/react-primitive@2.0.2(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
dependencies:
- '@radix-ui/react-slot': 1.1.2(@types/react@19.1.13)(react@19.1.1)
+ '@radix-ui/react-slot': 1.1.2(@types/react@19.1.17)(react@19.1.1)
react: 19.1.1
react-dom: 19.1.1(react@19.1.1)
optionalDependencies:
- '@types/react': 19.1.13
- '@types/react-dom': 19.1.9(@types/react@19.1.13)
+ '@types/react': 19.1.17
+ '@types/react-dom': 19.1.11(@types/react@19.1.17)
- '@radix-ui/react-primitive@2.1.3(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
+ '@radix-ui/react-primitive@2.1.3(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
dependencies:
- '@radix-ui/react-slot': 1.2.3(@types/react@19.1.13)(react@19.1.1)
+ '@radix-ui/react-slot': 1.2.3(@types/react@19.1.17)(react@19.1.1)
react: 19.1.1
react-dom: 19.1.1(react@19.1.1)
optionalDependencies:
- '@types/react': 19.1.13
- '@types/react-dom': 19.1.9(@types/react@19.1.13)
+ '@types/react': 19.1.17
+ '@types/react-dom': 19.1.11(@types/react@19.1.17)
- '@radix-ui/react-radio-group@1.2.3(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
+ '@radix-ui/react-radio-group@1.2.3(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
dependencies:
'@radix-ui/primitive': 1.1.1
- '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-context': 1.1.1(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-direction': 1.1.0(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-presence': 1.1.2(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@radix-ui/react-roving-focus': 1.1.2(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-use-previous': 1.1.0(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-use-size': 1.1.0(@types/react@19.1.13)(react@19.1.1)
+ '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-context': 1.1.1(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-direction': 1.1.0(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-presence': 1.1.2(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-roving-focus': 1.1.2(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-use-previous': 1.1.0(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-use-size': 1.1.0(@types/react@19.1.17)(react@19.1.1)
react: 19.1.1
react-dom: 19.1.1(react@19.1.1)
optionalDependencies:
- '@types/react': 19.1.13
- '@types/react-dom': 19.1.9(@types/react@19.1.13)
+ '@types/react': 19.1.17
+ '@types/react-dom': 19.1.11(@types/react@19.1.17)
- '@radix-ui/react-roving-focus@1.1.1(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
+ '@radix-ui/react-roving-focus@1.1.1(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
dependencies:
'@radix-ui/primitive': 1.1.1
- '@radix-ui/react-collection': 1.1.1(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-context': 1.1.1(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-direction': 1.1.0(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-id': 1.1.0(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-primitive': 2.0.1(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.1.13)(react@19.1.1)
+ '@radix-ui/react-collection': 1.1.1(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-context': 1.1.1(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-direction': 1.1.0(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-id': 1.1.0(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-primitive': 2.0.1(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.1.17)(react@19.1.1)
react: 19.1.1
react-dom: 19.1.1(react@19.1.1)
optionalDependencies:
- '@types/react': 19.1.13
- '@types/react-dom': 19.1.9(@types/react@19.1.13)
+ '@types/react': 19.1.17
+ '@types/react-dom': 19.1.11(@types/react@19.1.17)
- '@radix-ui/react-roving-focus@1.1.2(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
+ '@radix-ui/react-roving-focus@1.1.2(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
dependencies:
'@radix-ui/primitive': 1.1.1
- '@radix-ui/react-collection': 1.1.2(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-context': 1.1.1(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-direction': 1.1.0(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-id': 1.1.0(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.1.13)(react@19.1.1)
+ '@radix-ui/react-collection': 1.1.2(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-context': 1.1.1(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-direction': 1.1.0(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-id': 1.1.0(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.1.17)(react@19.1.1)
react: 19.1.1
react-dom: 19.1.1(react@19.1.1)
optionalDependencies:
- '@types/react': 19.1.13
- '@types/react-dom': 19.1.9(@types/react@19.1.13)
+ '@types/react': 19.1.17
+ '@types/react-dom': 19.1.11(@types/react@19.1.17)
- '@radix-ui/react-scroll-area@1.2.3(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
+ '@radix-ui/react-scroll-area@1.2.3(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
dependencies:
'@radix-ui/number': 1.1.0
'@radix-ui/primitive': 1.1.1
- '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-context': 1.1.1(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-direction': 1.1.0(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-presence': 1.1.2(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.1.13)(react@19.1.1)
+ '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-context': 1.1.1(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-direction': 1.1.0(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-presence': 1.1.2(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.1.17)(react@19.1.1)
react: 19.1.1
react-dom: 19.1.1(react@19.1.1)
optionalDependencies:
- '@types/react': 19.1.13
- '@types/react-dom': 19.1.9(@types/react@19.1.13)
+ '@types/react': 19.1.17
+ '@types/react-dom': 19.1.11(@types/react@19.1.17)
- '@radix-ui/react-select@2.2.6(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
+ '@radix-ui/react-select@2.2.6(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
dependencies:
'@radix-ui/number': 1.1.1
'@radix-ui/primitive': 1.1.3
- '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-context': 1.1.2(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-direction': 1.1.1(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@radix-ui/react-id': 1.1.1(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@radix-ui/react-slot': 1.2.3(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-use-previous': 1.1.1(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-context': 1.1.2(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-direction': 1.1.1(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-id': 1.1.1(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-slot': 1.2.3(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-use-previous': 1.1.1(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
aria-hidden: 1.2.6
react: 19.1.1
react-dom: 19.1.1(react@19.1.1)
- react-remove-scroll: 2.7.1(@types/react@19.1.13)(react@19.1.1)
+ react-remove-scroll: 2.7.1(@types/react@19.1.17)(react@19.1.1)
optionalDependencies:
- '@types/react': 19.1.13
- '@types/react-dom': 19.1.9(@types/react@19.1.13)
+ '@types/react': 19.1.17
+ '@types/react-dom': 19.1.11(@types/react@19.1.17)
- '@radix-ui/react-separator@1.1.7(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
+ '@radix-ui/react-separator@1.1.7(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
dependencies:
- '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
react: 19.1.1
react-dom: 19.1.1(react@19.1.1)
optionalDependencies:
- '@types/react': 19.1.13
- '@types/react-dom': 19.1.9(@types/react@19.1.13)
+ '@types/react': 19.1.17
+ '@types/react-dom': 19.1.11(@types/react@19.1.17)
- '@radix-ui/react-slider@1.2.2(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
+ '@radix-ui/react-slider@1.2.2(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
dependencies:
'@radix-ui/number': 1.1.0
'@radix-ui/primitive': 1.1.1
- '@radix-ui/react-collection': 1.1.1(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-context': 1.1.1(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-direction': 1.1.0(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-primitive': 2.0.1(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-use-previous': 1.1.0(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-use-size': 1.1.0(@types/react@19.1.13)(react@19.1.1)
+ '@radix-ui/react-collection': 1.1.1(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-context': 1.1.1(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-direction': 1.1.0(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-primitive': 2.0.1(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-use-previous': 1.1.0(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-use-size': 1.1.0(@types/react@19.1.17)(react@19.1.1)
react: 19.1.1
react-dom: 19.1.1(react@19.1.1)
optionalDependencies:
- '@types/react': 19.1.13
- '@types/react-dom': 19.1.9(@types/react@19.1.13)
+ '@types/react': 19.1.17
+ '@types/react-dom': 19.1.11(@types/react@19.1.17)
- '@radix-ui/react-slot@1.1.0(@types/react@19.1.13)(react@19.1.1)':
+ '@radix-ui/react-slot@1.1.0(@types/react@19.1.17)(react@19.1.1)':
dependencies:
- '@radix-ui/react-compose-refs': 1.1.0(@types/react@19.1.13)(react@19.1.1)
+ '@radix-ui/react-compose-refs': 1.1.0(@types/react@19.1.17)(react@19.1.1)
react: 19.1.1
optionalDependencies:
- '@types/react': 19.1.13
+ '@types/react': 19.1.17
- '@radix-ui/react-slot@1.1.1(@types/react@19.1.13)(react@19.1.1)':
+ '@radix-ui/react-slot@1.1.1(@types/react@19.1.17)(react@19.1.1)':
dependencies:
- '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.1.13)(react@19.1.1)
+ '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.1.17)(react@19.1.1)
react: 19.1.1
optionalDependencies:
- '@types/react': 19.1.13
+ '@types/react': 19.1.17
- '@radix-ui/react-slot@1.1.2(@types/react@19.1.13)(react@19.1.1)':
+ '@radix-ui/react-slot@1.1.2(@types/react@19.1.17)(react@19.1.1)':
dependencies:
- '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.1.13)(react@19.1.1)
+ '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.1.17)(react@19.1.1)
react: 19.1.1
optionalDependencies:
- '@types/react': 19.1.13
+ '@types/react': 19.1.17
- '@radix-ui/react-slot@1.2.3(@types/react@19.1.13)(react@19.1.1)':
+ '@radix-ui/react-slot@1.2.3(@types/react@19.1.17)(react@19.1.1)':
dependencies:
- '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.13)(react@19.1.1)
+ '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.17)(react@19.1.1)
react: 19.1.1
optionalDependencies:
- '@types/react': 19.1.13
+ '@types/react': 19.1.17
- '@radix-ui/react-switch@1.1.1(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
+ '@radix-ui/react-switch@1.1.1(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
dependencies:
'@radix-ui/primitive': 1.1.0
- '@radix-ui/react-compose-refs': 1.1.0(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-context': 1.1.1(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-primitive': 2.0.0(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-use-previous': 1.1.0(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-use-size': 1.1.0(@types/react@19.1.13)(react@19.1.1)
+ '@radix-ui/react-compose-refs': 1.1.0(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-context': 1.1.1(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-primitive': 2.0.0(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-use-previous': 1.1.0(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-use-size': 1.1.0(@types/react@19.1.17)(react@19.1.1)
react: 19.1.1
react-dom: 19.1.1(react@19.1.1)
optionalDependencies:
- '@types/react': 19.1.13
- '@types/react-dom': 19.1.9(@types/react@19.1.13)
+ '@types/react': 19.1.17
+ '@types/react-dom': 19.1.11(@types/react@19.1.17)
- '@radix-ui/react-tooltip@1.1.7(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
+ '@radix-ui/react-tooltip@1.1.7(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
dependencies:
'@radix-ui/primitive': 1.1.1
- '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-context': 1.1.1(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-dismissable-layer': 1.1.4(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@radix-ui/react-id': 1.1.0(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-popper': 1.2.1(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@radix-ui/react-portal': 1.1.3(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@radix-ui/react-presence': 1.1.2(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@radix-ui/react-primitive': 2.0.1(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@radix-ui/react-slot': 1.1.1(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-visually-hidden': 1.1.1(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-context': 1.1.1(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-dismissable-layer': 1.1.4(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-id': 1.1.0(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-popper': 1.2.1(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-portal': 1.1.3(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-presence': 1.1.2(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-primitive': 2.0.1(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-slot': 1.1.1(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-visually-hidden': 1.1.1(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
react: 19.1.1
react-dom: 19.1.1(react@19.1.1)
optionalDependencies:
- '@types/react': 19.1.13
- '@types/react-dom': 19.1.9(@types/react@19.1.13)
+ '@types/react': 19.1.17
+ '@types/react-dom': 19.1.11(@types/react@19.1.17)
- '@radix-ui/react-use-callback-ref@1.1.0(@types/react@19.1.13)(react@19.1.1)':
+ '@radix-ui/react-use-callback-ref@1.1.0(@types/react@19.1.17)(react@19.1.1)':
dependencies:
react: 19.1.1
optionalDependencies:
- '@types/react': 19.1.13
+ '@types/react': 19.1.17
- '@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.1.13)(react@19.1.1)':
+ '@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.1.17)(react@19.1.1)':
dependencies:
react: 19.1.1
optionalDependencies:
- '@types/react': 19.1.13
+ '@types/react': 19.1.17
- '@radix-ui/react-use-controllable-state@1.1.0(@types/react@19.1.13)(react@19.1.1)':
+ '@radix-ui/react-use-controllable-state@1.1.0(@types/react@19.1.17)(react@19.1.1)':
dependencies:
- '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.1.13)(react@19.1.1)
+ '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.1.17)(react@19.1.1)
react: 19.1.1
optionalDependencies:
- '@types/react': 19.1.13
+ '@types/react': 19.1.17
- '@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.1.13)(react@19.1.1)':
+ '@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.1.17)(react@19.1.1)':
dependencies:
- '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.13)(react@19.1.1)
+ '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.17)(react@19.1.1)
react: 19.1.1
optionalDependencies:
- '@types/react': 19.1.13
+ '@types/react': 19.1.17
- '@radix-ui/react-use-effect-event@0.0.2(@types/react@19.1.13)(react@19.1.1)':
+ '@radix-ui/react-use-effect-event@0.0.2(@types/react@19.1.17)(react@19.1.1)':
dependencies:
- '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.13)(react@19.1.1)
+ '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.17)(react@19.1.1)
react: 19.1.1
optionalDependencies:
- '@types/react': 19.1.13
+ '@types/react': 19.1.17
- '@radix-ui/react-use-escape-keydown@1.1.0(@types/react@19.1.13)(react@19.1.1)':
+ '@radix-ui/react-use-escape-keydown@1.1.0(@types/react@19.1.17)(react@19.1.1)':
dependencies:
- '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.1.13)(react@19.1.1)
+ '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.1.17)(react@19.1.1)
react: 19.1.1
optionalDependencies:
- '@types/react': 19.1.13
+ '@types/react': 19.1.17
- '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@19.1.13)(react@19.1.1)':
+ '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@19.1.17)(react@19.1.1)':
dependencies:
- '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.13)(react@19.1.1)
+ '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.17)(react@19.1.1)
react: 19.1.1
optionalDependencies:
- '@types/react': 19.1.13
+ '@types/react': 19.1.17
- '@radix-ui/react-use-layout-effect@1.1.0(@types/react@19.1.13)(react@19.1.1)':
+ '@radix-ui/react-use-layout-effect@1.1.0(@types/react@19.1.17)(react@19.1.1)':
dependencies:
react: 19.1.1
optionalDependencies:
- '@types/react': 19.1.13
+ '@types/react': 19.1.17
- '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.1.13)(react@19.1.1)':
+ '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.1.17)(react@19.1.1)':
dependencies:
react: 19.1.1
optionalDependencies:
- '@types/react': 19.1.13
+ '@types/react': 19.1.17
- '@radix-ui/react-use-previous@1.1.0(@types/react@19.1.13)(react@19.1.1)':
+ '@radix-ui/react-use-previous@1.1.0(@types/react@19.1.17)(react@19.1.1)':
dependencies:
react: 19.1.1
optionalDependencies:
- '@types/react': 19.1.13
+ '@types/react': 19.1.17
- '@radix-ui/react-use-previous@1.1.1(@types/react@19.1.13)(react@19.1.1)':
+ '@radix-ui/react-use-previous@1.1.1(@types/react@19.1.17)(react@19.1.1)':
dependencies:
react: 19.1.1
optionalDependencies:
- '@types/react': 19.1.13
+ '@types/react': 19.1.17
- '@radix-ui/react-use-rect@1.1.0(@types/react@19.1.13)(react@19.1.1)':
+ '@radix-ui/react-use-rect@1.1.0(@types/react@19.1.17)(react@19.1.1)':
dependencies:
'@radix-ui/rect': 1.1.0
react: 19.1.1
optionalDependencies:
- '@types/react': 19.1.13
+ '@types/react': 19.1.17
- '@radix-ui/react-use-rect@1.1.1(@types/react@19.1.13)(react@19.1.1)':
+ '@radix-ui/react-use-rect@1.1.1(@types/react@19.1.17)(react@19.1.1)':
dependencies:
'@radix-ui/rect': 1.1.1
react: 19.1.1
optionalDependencies:
- '@types/react': 19.1.13
+ '@types/react': 19.1.17
- '@radix-ui/react-use-size@1.1.0(@types/react@19.1.13)(react@19.1.1)':
+ '@radix-ui/react-use-size@1.1.0(@types/react@19.1.17)(react@19.1.1)':
dependencies:
- '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.1.13)(react@19.1.1)
+ '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.1.17)(react@19.1.1)
react: 19.1.1
optionalDependencies:
- '@types/react': 19.1.13
+ '@types/react': 19.1.17
- '@radix-ui/react-use-size@1.1.1(@types/react@19.1.13)(react@19.1.1)':
+ '@radix-ui/react-use-size@1.1.1(@types/react@19.1.17)(react@19.1.1)':
dependencies:
- '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.13)(react@19.1.1)
+ '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.17)(react@19.1.1)
react: 19.1.1
optionalDependencies:
- '@types/react': 19.1.13
+ '@types/react': 19.1.17
- '@radix-ui/react-visually-hidden@1.1.1(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
+ '@radix-ui/react-visually-hidden@1.1.1(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
dependencies:
- '@radix-ui/react-primitive': 2.0.1(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-primitive': 2.0.1(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
react: 19.1.1
react-dom: 19.1.1(react@19.1.1)
optionalDependencies:
- '@types/react': 19.1.13
- '@types/react-dom': 19.1.9(@types/react@19.1.13)
+ '@types/react': 19.1.17
+ '@types/react-dom': 19.1.11(@types/react@19.1.17)
- '@radix-ui/react-visually-hidden@1.2.3(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
+ '@radix-ui/react-visually-hidden@1.2.3(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
dependencies:
- '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
react: 19.1.1
react-dom: 19.1.1(react@19.1.1)
optionalDependencies:
- '@types/react': 19.1.13
- '@types/react-dom': 19.1.9(@types/react@19.1.13)
+ '@types/react': 19.1.17
+ '@types/react-dom': 19.1.11(@types/react@19.1.17)
'@radix-ui/rect@1.1.0': {}
@@ -8773,9 +8775,9 @@ snapshots:
dependencies:
'@sinonjs/commons': 3.0.0
- '@storybook/addon-docs@9.1.2(@types/react@19.1.13)(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)))':
+ '@storybook/addon-docs@9.1.2(@types/react@19.1.17)(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)))':
dependencies:
- '@mdx-js/react': 3.0.1(@types/react@19.1.13)(react@19.1.1)
+ '@mdx-js/react': 3.0.1(@types/react@19.1.17)(react@19.1.1)
'@storybook/csf-plugin': 9.1.2(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)))
'@storybook/icons': 1.4.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
'@storybook/react-dom-shim': 9.1.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)))
@@ -8960,13 +8962,15 @@ snapshots:
lodash: 4.17.21
redent: 3.0.0
- '@testing-library/react@14.3.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
+ '@testing-library/react@14.3.1(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
dependencies:
'@babel/runtime': 7.26.10
'@testing-library/dom': 9.3.3
- '@types/react-dom': 18.3.1
+ '@types/react-dom': 18.3.7(@types/react@19.1.17)
react: 19.1.1
react-dom: 19.1.1(react@19.1.1)
+ transitivePeerDependencies:
+ - '@types/react'
'@testing-library/user-event@14.6.1(@testing-library/dom@10.4.0)':
dependencies:
@@ -9113,7 +9117,7 @@ snapshots:
'@types/hoist-non-react-statics@3.3.5':
dependencies:
- '@types/react': 19.1.13
+ '@types/react': 19.1.17
hoist-non-react-statics: 3.3.2
'@types/http-errors@2.0.1': {}
@@ -9193,47 +9197,47 @@ snapshots:
'@types/range-parser@1.2.4': {}
- '@types/react-color@3.0.13(@types/react@19.1.13)':
+ '@types/react-color@3.0.13(@types/react@19.1.17)':
dependencies:
- '@types/react': 19.1.13
- '@types/reactcss': 1.2.13(@types/react@19.1.13)
+ '@types/react': 19.1.17
+ '@types/reactcss': 1.2.13(@types/react@19.1.17)
'@types/react-date-range@1.4.4':
dependencies:
- '@types/react': 19.1.13
+ '@types/react': 19.1.17
date-fns: 2.30.0
- '@types/react-dom@18.3.1':
+ '@types/react-dom@18.3.7(@types/react@19.1.17)':
dependencies:
- '@types/react': 19.1.13
+ '@types/react': 19.1.17
- '@types/react-dom@19.1.9(@types/react@19.1.13)':
+ '@types/react-dom@19.1.11(@types/react@19.1.17)':
dependencies:
- '@types/react': 19.1.13
+ '@types/react': 19.1.17
'@types/react-syntax-highlighter@15.5.13':
dependencies:
- '@types/react': 19.1.13
+ '@types/react': 19.1.17
- '@types/react-transition-group@4.4.12(@types/react@19.1.13)':
+ '@types/react-transition-group@4.4.12(@types/react@19.1.17)':
dependencies:
- '@types/react': 19.1.13
+ '@types/react': 19.1.17
'@types/react-virtualized-auto-sizer@1.0.4':
dependencies:
- '@types/react': 19.1.13
+ '@types/react': 19.1.17
'@types/react-window@1.8.8':
dependencies:
- '@types/react': 19.1.13
+ '@types/react': 19.1.17
- '@types/react@19.1.13':
+ '@types/react@19.1.17':
dependencies:
csstype: 3.1.3
- '@types/reactcss@1.2.13(@types/react@19.1.13)':
+ '@types/reactcss@1.2.13(@types/react@19.1.17)':
dependencies:
- '@types/react': 19.1.13
+ '@types/react': 19.1.17
'@types/resolve@1.20.4': {}
@@ -9767,11 +9771,11 @@ snapshots:
clsx@2.1.1: {}
- cmdk@1.0.4(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1):
+ cmdk@1.0.4(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1):
dependencies:
- '@radix-ui/react-dialog': 1.1.4(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@radix-ui/react-id': 1.1.0(@types/react@19.1.13)(react@19.1.1)
- '@radix-ui/react-primitive': 2.0.1(@types/react-dom@19.1.9(@types/react@19.1.13))(@types/react@19.1.13)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-dialog': 1.1.4(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-id': 1.1.0(@types/react@19.1.17)(react@19.1.1)
+ '@radix-ui/react-primitive': 2.0.1(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
react: 19.1.1
react-dom: 19.1.1(react@19.1.1)
use-sync-external-store: 1.4.0(react@19.1.1)
@@ -12533,11 +12537,11 @@ snapshots:
prop-types: 15.8.1
react: 19.1.1
- react-markdown@9.1.0(@types/react@19.1.13)(react@19.1.1):
+ react-markdown@9.1.0(@types/react@19.1.17)(react@19.1.1):
dependencies:
'@types/hast': 3.0.4
'@types/mdast': 4.0.4
- '@types/react': 19.1.13
+ '@types/react': 19.1.17
devlop: 1.1.0
hast-util-to-jsx-runtime: 2.3.6
html-url-attributes: 3.0.1
@@ -12553,35 +12557,35 @@ snapshots:
react-refresh@0.17.0: {}
- react-remove-scroll-bar@2.3.8(@types/react@19.1.13)(react@19.1.1):
+ react-remove-scroll-bar@2.3.8(@types/react@19.1.17)(react@19.1.1):
dependencies:
react: 19.1.1
- react-style-singleton: 2.2.3(@types/react@19.1.13)(react@19.1.1)
+ react-style-singleton: 2.2.3(@types/react@19.1.17)(react@19.1.1)
tslib: 2.8.1
optionalDependencies:
- '@types/react': 19.1.13
+ '@types/react': 19.1.17
- react-remove-scroll@2.6.3(@types/react@19.1.13)(react@19.1.1):
+ react-remove-scroll@2.6.3(@types/react@19.1.17)(react@19.1.1):
dependencies:
react: 19.1.1
- react-remove-scroll-bar: 2.3.8(@types/react@19.1.13)(react@19.1.1)
- react-style-singleton: 2.2.3(@types/react@19.1.13)(react@19.1.1)
+ react-remove-scroll-bar: 2.3.8(@types/react@19.1.17)(react@19.1.1)
+ react-style-singleton: 2.2.3(@types/react@19.1.17)(react@19.1.1)
tslib: 2.8.1
- use-callback-ref: 1.3.3(@types/react@19.1.13)(react@19.1.1)
- use-sidecar: 1.1.3(@types/react@19.1.13)(react@19.1.1)
+ use-callback-ref: 1.3.3(@types/react@19.1.17)(react@19.1.1)
+ use-sidecar: 1.1.3(@types/react@19.1.17)(react@19.1.1)
optionalDependencies:
- '@types/react': 19.1.13
+ '@types/react': 19.1.17
- react-remove-scroll@2.7.1(@types/react@19.1.13)(react@19.1.1):
+ react-remove-scroll@2.7.1(@types/react@19.1.17)(react@19.1.1):
dependencies:
react: 19.1.1
- react-remove-scroll-bar: 2.3.8(@types/react@19.1.13)(react@19.1.1)
- react-style-singleton: 2.2.3(@types/react@19.1.13)(react@19.1.1)
+ react-remove-scroll-bar: 2.3.8(@types/react@19.1.17)(react@19.1.1)
+ react-style-singleton: 2.2.3(@types/react@19.1.17)(react@19.1.1)
tslib: 2.8.1
- use-callback-ref: 1.3.3(@types/react@19.1.13)(react@19.1.1)
- use-sidecar: 1.1.3(@types/react@19.1.13)(react@19.1.1)
+ use-callback-ref: 1.3.3(@types/react@19.1.17)(react@19.1.1)
+ use-sidecar: 1.1.3(@types/react@19.1.17)(react@19.1.1)
optionalDependencies:
- '@types/react': 19.1.13
+ '@types/react': 19.1.17
react-resizable-panels@3.0.3(react-dom@19.1.1(react@19.1.1))(react@19.1.1):
dependencies:
@@ -12604,13 +12608,13 @@ snapshots:
react-dom: 19.1.1(react@19.1.1)
react-transition-group: 4.4.5(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- react-style-singleton@2.2.3(@types/react@19.1.13)(react@19.1.1):
+ react-style-singleton@2.2.3(@types/react@19.1.17)(react@19.1.1):
dependencies:
get-nonce: 1.0.1
react: 19.1.1
tslib: 2.8.1
optionalDependencies:
- '@types/react': 19.1.13
+ '@types/react': 19.1.17
react-syntax-highlighter@15.6.1(react@19.1.1):
dependencies:
@@ -12622,12 +12626,12 @@ snapshots:
react: 19.1.1
refractor: 3.6.0
- react-textarea-autosize@8.5.9(@types/react@19.1.13)(react@19.1.1):
+ react-textarea-autosize@8.5.9(@types/react@19.1.17)(react@19.1.1):
dependencies:
'@babel/runtime': 7.26.10
react: 19.1.1
- use-composed-ref: 1.4.0(@types/react@19.1.13)(react@19.1.1)
- use-latest: 1.3.0(@types/react@19.1.13)(react@19.1.1)
+ use-composed-ref: 1.4.0(@types/react@19.1.17)(react@19.1.1)
+ use-latest: 1.3.0(@types/react@19.1.17)(react@19.1.1)
transitivePeerDependencies:
- '@types/react'
@@ -13388,39 +13392,39 @@ snapshots:
querystringify: 2.2.0
requires-port: 1.0.0
- use-callback-ref@1.3.3(@types/react@19.1.13)(react@19.1.1):
+ use-callback-ref@1.3.3(@types/react@19.1.17)(react@19.1.1):
dependencies:
react: 19.1.1
tslib: 2.8.1
optionalDependencies:
- '@types/react': 19.1.13
+ '@types/react': 19.1.17
- use-composed-ref@1.4.0(@types/react@19.1.13)(react@19.1.1):
+ use-composed-ref@1.4.0(@types/react@19.1.17)(react@19.1.1):
dependencies:
react: 19.1.1
optionalDependencies:
- '@types/react': 19.1.13
+ '@types/react': 19.1.17
- use-isomorphic-layout-effect@1.2.1(@types/react@19.1.13)(react@19.1.1):
+ use-isomorphic-layout-effect@1.2.1(@types/react@19.1.17)(react@19.1.1):
dependencies:
react: 19.1.1
optionalDependencies:
- '@types/react': 19.1.13
+ '@types/react': 19.1.17
- use-latest@1.3.0(@types/react@19.1.13)(react@19.1.1):
+ use-latest@1.3.0(@types/react@19.1.17)(react@19.1.1):
dependencies:
react: 19.1.1
- use-isomorphic-layout-effect: 1.2.1(@types/react@19.1.13)(react@19.1.1)
+ use-isomorphic-layout-effect: 1.2.1(@types/react@19.1.17)(react@19.1.1)
optionalDependencies:
- '@types/react': 19.1.13
+ '@types/react': 19.1.17
- use-sidecar@1.1.3(@types/react@19.1.13)(react@19.1.1):
+ use-sidecar@1.1.3(@types/react@19.1.17)(react@19.1.1):
dependencies:
detect-node-es: 1.1.0
react: 19.1.1
tslib: 2.8.1
optionalDependencies:
- '@types/react': 19.1.13
+ '@types/react': 19.1.17
use-sync-external-store@1.4.0(react@19.1.1):
dependencies:
From 6b61c8a32a8778bf2e5a65161ee2362d8aae0183 Mon Sep 17 00:00:00 2001
From: Bruno Quaresma
Date: Wed, 1 Oct 2025 15:49:52 -0300
Subject: [PATCH 007/298] feat: add workspace status on tasks (#20037)
Closes https://github.com/coder/coder/issues/19988
---
.../WorkspaceStatus.stories.tsx | 22 +++++++++++++
.../WorkspaceStatus/WorkspaceStatus.tsx | 27 +++++++++++++++
site/src/pages/TasksPage/TasksTable.tsx | 10 +++++-
.../pages/WorkspacesPage/WorkspacesTable.tsx | 33 +++----------------
4 files changed, 63 insertions(+), 29 deletions(-)
create mode 100644 site/src/modules/workspaces/WorkspaceStatus/WorkspaceStatus.stories.tsx
create mode 100644 site/src/modules/workspaces/WorkspaceStatus/WorkspaceStatus.tsx
diff --git a/site/src/modules/workspaces/WorkspaceStatus/WorkspaceStatus.stories.tsx b/site/src/modules/workspaces/WorkspaceStatus/WorkspaceStatus.stories.tsx
new file mode 100644
index 0000000000000..60313bf116efd
--- /dev/null
+++ b/site/src/modules/workspaces/WorkspaceStatus/WorkspaceStatus.stories.tsx
@@ -0,0 +1,22 @@
+import { MockDormantWorkspace, MockWorkspace } from "testHelpers/entities";
+import type { Meta, StoryObj } from "@storybook/react-vite";
+import { WorkspaceStatus } from "./WorkspaceStatus";
+
+const meta: Meta = {
+ title: "modules/workspaces/WorkspaceStatus",
+ component: WorkspaceStatus,
+ args: {
+ workspace: MockWorkspace,
+ },
+};
+
+export default meta;
+type Story = StoryObj;
+
+export const Running: Story = {};
+
+export const Dormant: Story = {
+ args: {
+ workspace: MockDormantWorkspace,
+ },
+};
diff --git a/site/src/modules/workspaces/WorkspaceStatus/WorkspaceStatus.tsx b/site/src/modules/workspaces/WorkspaceStatus/WorkspaceStatus.tsx
new file mode 100644
index 0000000000000..7888b1c77ef3e
--- /dev/null
+++ b/site/src/modules/workspaces/WorkspaceStatus/WorkspaceStatus.tsx
@@ -0,0 +1,27 @@
+import type { Workspace } from "api/typesGenerated";
+import type { FC } from "react";
+import { lastUsedMessage } from "utils/workspace";
+import { WorkspaceDormantBadge } from "../WorkspaceDormantBadge/WorkspaceDormantBadge";
+import { WorkspaceStatusIndicator } from "../WorkspaceStatusIndicator/WorkspaceStatusIndicator";
+
+type WorkspaceStatusProps = {
+ workspace: Workspace;
+};
+
+export const WorkspaceStatus: FC = ({ workspace }) => {
+ return (
+
+
+ {workspace.dormant_at && (
+
+ )}
+
+
+ {lastUsedMessage(workspace.last_used_at)}
+
+
+ );
+};
diff --git a/site/src/pages/TasksPage/TasksTable.tsx b/site/src/pages/TasksPage/TasksTable.tsx
index c1cddb75a8e8f..c9ff75bb36ddc 100644
--- a/site/src/pages/TasksPage/TasksTable.tsx
+++ b/site/src/pages/TasksPage/TasksTable.tsx
@@ -26,6 +26,7 @@ import { RotateCcwIcon, TrashIcon } from "lucide-react";
import { TaskDeleteDialog } from "modules/tasks/TaskDeleteDialog/TaskDeleteDialog";
import type { Task } from "modules/tasks/tasks";
import { WorkspaceAppStatus } from "modules/workspaces/WorkspaceAppStatus/WorkspaceAppStatus";
+import { WorkspaceStatus } from "modules/workspaces/WorkspaceStatus/WorkspaceStatus";
import { type FC, type ReactNode, useState } from "react";
import { Link as RouterLink } from "react-router";
import { relativeTime } from "utils/time";
@@ -54,7 +55,8 @@ export const TasksTable: FC = ({ tasks, error, onRetry }) => {
Task
- Status
+ Agent status
+ Workspace status
Created by
@@ -153,6 +155,9 @@ const TaskRow: FC = ({ task }) => {
status={task.workspace.latest_app_status}
/>
+
+
+
{
+
+
+
diff --git a/site/src/pages/WorkspacesPage/WorkspacesTable.tsx b/site/src/pages/WorkspacesPage/WorkspacesTable.tsx
index a6ba1e4a43dad..7ab941821d7b1 100644
--- a/site/src/pages/WorkspacesPage/WorkspacesTable.tsx
+++ b/site/src/pages/WorkspacesPage/WorkspacesTable.tsx
@@ -65,10 +65,9 @@ import { useAppLink } from "modules/apps/useAppLink";
import { useDashboard } from "modules/dashboard/useDashboard";
import { abilitiesByWorkspaceStatus } from "modules/workspaces/actions";
import { WorkspaceBuildCancelDialog } from "modules/workspaces/WorkspaceBuildCancelDialog/WorkspaceBuildCancelDialog";
-import { WorkspaceDormantBadge } from "modules/workspaces/WorkspaceDormantBadge/WorkspaceDormantBadge";
import { WorkspaceMoreActions } from "modules/workspaces/WorkspaceMoreActions/WorkspaceMoreActions";
import { WorkspaceOutdatedTooltip } from "modules/workspaces/WorkspaceOutdatedTooltip/WorkspaceOutdatedTooltip";
-import { WorkspaceStatusIndicator } from "modules/workspaces/WorkspaceStatusIndicator/WorkspaceStatusIndicator";
+import { WorkspaceStatus } from "modules/workspaces/WorkspaceStatus/WorkspaceStatus";
import {
useWorkspaceUpdate,
WorkspaceUpdateDialogs,
@@ -83,10 +82,7 @@ import {
import { useMutation, useQuery, useQueryClient } from "react-query";
import { useNavigate } from "react-router";
import { cn } from "utils/cn";
-import {
- getDisplayWorkspaceTemplateName,
- lastUsedMessage,
-} from "utils/workspace";
+import { getDisplayWorkspaceTemplateName } from "utils/workspace";
import { WorkspacesEmpty } from "./WorkspacesEmpty";
interface WorkspacesTableProps {
@@ -256,7 +252,9 @@ export const WorkspacesTable: FC = ({
/>
-
+
+
+
{
return ["deleting", "pending"].includes(workspace.latest_build.status);
};
-type WorkspaceStatusCellProps = {
- workspace: Workspace;
-};
-
-const WorkspaceStatusCell: FC = ({ workspace }) => {
- return (
-
-
-
- {workspace.dormant_at && (
-
- )}
-
-
- {lastUsedMessage(workspace.last_used_at)}
-
-
-
- );
-};
-
type WorkspaceActionsCellProps = {
workspace: Workspace;
onActionSuccess: () => Promise;
From b3f1492f146c4f487034fba088b37ff848b76fda Mon Sep 17 00:00:00 2001
From: Cian Johnston
Date: Wed, 1 Oct 2025 19:53:58 +0100
Subject: [PATCH 008/298] ci(.github/workflows/traiage.yaml): set default
inputs on trigger by label assignment (#20100)
When not triggering via `workflow_dispatch`, it looks like the default
values are simply empty.
This PR creates an intermediate step to conditionally set defaults based
on `github.event_name`.
I'm also adding a commented-out step for installing `gh` that's required
for local testing via `nektos/act`. It's not required in a 'real'
runner.
---
.github/workflows/traiage.yaml | 93 +++++++++++++++++++++-------------
1 file changed, 58 insertions(+), 35 deletions(-)
diff --git a/.github/workflows/traiage.yaml b/.github/workflows/traiage.yaml
index 24192fc2d1812..09881ff2ee46a 100644
--- a/.github/workflows/traiage.yaml
+++ b/.github/workflows/traiage.yaml
@@ -40,25 +40,57 @@ jobs:
env:
CODER_URL: ${{ secrets.TRAIAGE_CODER_URL }}
CODER_SESSION_TOKEN: ${{ secrets.TRAIAGE_CODER_SESSION_TOKEN }}
- TEMPLATE_NAME: ${{ inputs.template_name }}
permissions:
contents: read
issues: write
actions: write
steps:
- - name: Get GitHub user ID
- id: github-user-id
+ # This is only required for testing locally using nektos/act, so leaving commented out.
+ # An alternative is to use a larger or custom image.
+ # - name: Install Github CLI
+ # id: install-gh
+ # run: |
+ # (type -p wget >/dev/null || (sudo apt update && sudo apt install wget -y)) \
+ # && sudo mkdir -p -m 755 /etc/apt/keyrings \
+ # && out=$(mktemp) && wget -nv -O$out https://cli.github.com/packages/githubcli-archive-keyring.gpg \
+ # && cat $out | sudo tee /etc/apt/keyrings/githubcli-archive-keyring.gpg > /dev/null \
+ # && sudo chmod go+r /etc/apt/keyrings/githubcli-archive-keyring.gpg \
+ # && sudo mkdir -p -m 755 /etc/apt/sources.list.d \
+ # && echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null \
+ # && sudo apt update \
+ # && sudo apt install gh -y
+
+ - name: Determine Inputs
+ id: determine-inputs
if: always()
env:
GITHUB_ACTOR: ${{ github.actor }}
+ GITHUB_EVENT_ISSUE_HTML_URL: ${{ github.event.issue.html_url }}
GITHUB_EVENT_NAME: ${{ github.event_name }}
GITHUB_EVENT_USER_ID: ${{ github.event.sender.id }}
GITHUB_EVENT_USER_LOGIN: ${{ github.event.sender.login }}
+ INPUTS_CLEANUP: ${{ inputs.cleanup || false }}
+ INPUTS_ISSUE_URL: ${{ inputs.issue_url }}
+ INPUTS_TEMPLATE_NAME: ${{ inputs.template_name || 'traiage' }}
+ INPUTS_TEMPLATE_PRESET: ${{ inputs.template_preset || 'Default'}}
+ INPUTS_PREFIX: ${{ inputs.prefix || 'traiage' }}
GH_TOKEN: ${{ github.token }}
run: |
+ echo "Using template name: ${INPUTS_TEMPLATE_NAME}"
+ echo "template_name=${INPUTS_TEMPLATE_NAME}" >> "${GITHUB_OUTPUT}"
+
+ echo "Using template preset: ${INPUTS_TEMPLATE_PRESET}"
+ echo "template_preset=${INPUTS_TEMPLATE_PRESET}" >> "${GITHUB_OUTPUT}"
+
+ echo "Using prefix: ${INPUTS_PREFIX}"
+ echo "prefix=${INPUTS_PREFIX}" >> "${GITHUB_OUTPUT}"
+
+ echo "Using cleanup: ${INPUTS_CLEANUP}"
+ echo "cleanup=${INPUTS_CLEANUP}" >> "${GITHUB_OUTPUT}"
+
# For workflow_dispatch, use the actor who triggered it
- # For issues events, use the issue author
+ # For issues events, use the issue author.
if [[ "${GITHUB_EVENT_NAME}" == "workflow_dispatch" ]]; then
if ! GITHUB_USER_ID=$(gh api "users/${GITHUB_ACTOR}" --jq '.id'); then
echo "::error::Failed to get GitHub user ID for actor ${GITHUB_ACTOR}"
@@ -67,12 +99,20 @@ jobs:
echo "Using workflow_dispatch actor: ${GITHUB_ACTOR} (ID: ${GITHUB_USER_ID})"
echo "github_user_id=${GITHUB_USER_ID}" >> "${GITHUB_OUTPUT}"
echo "github_username=${GITHUB_ACTOR}" >> "${GITHUB_OUTPUT}"
+
+ echo "Using issue URL: ${INPUTS_ISSUE_URL}"
+ echo "issue_url=${INPUTS_ISSUE_URL}" >> "${GITHUB_OUTPUT}"
+
exit 0
elif [[ "${GITHUB_EVENT_NAME}" == "issues" ]]; then
GITHUB_USER_ID=${GITHUB_EVENT_USER_ID}
echo "Using issue author: ${GITHUB_EVENT_USER_LOGIN} (ID: ${GITHUB_USER_ID})"
echo "github_user_id=${GITHUB_USER_ID}" >> "${GITHUB_OUTPUT}"
echo "github_username=${GITHUB_EVENT_USER_LOGIN}" >> "${GITHUB_OUTPUT}"
+
+ echo "Using issue URL: ${GITHUB_EVENT_ISSUE_HTML_URL}"
+ echo "issue_url=${GITHUB_EVENT_ISSUE_HTML_URL}" >> "${GITHUB_OUTPUT}"
+
exit 0
else
echo "::error::Unsupported event type: ${GITHUB_EVENT_NAME}"
@@ -83,8 +123,8 @@ jobs:
env:
GITHUB_ORG: ${{ github.repository_owner }}
GH_TOKEN: ${{ github.token }}
- GITHUB_USERNAME: ${{ steps.github-user-id.outputs.github_username }}
- GITHUB_USER_ID: ${{ steps.github-user-id.outputs.github_user_id }}
+ GITHUB_USERNAME: ${{ steps.determine-inputs.outputs.github_username }}
+ GITHUB_USER_ID: ${{ steps.determine-inputs.outputs.github_user_id }}
run: |
# Check if the actor is a member of the organization
if ! gh api "orgs/${GITHUB_ORG}/members/${GITHUB_USERNAME}" --silent 2>/dev/null; then
@@ -94,28 +134,10 @@ jobs:
fi
echo "::notice::User ${GITHUB_USERNAME} verified as member of ${GITHUB_ORG} organization"
- - name: Determine issue URL
- id: determine-issue-url
- env:
- INPUTS_ISSUE_URL: ${{ inputs.issue_url }}
- GITHUB_EVENT_ISSUE_HTML_URL: ${{ github.event.issue.html_url }}
- GITHUB_EVENT_NAME: ${{ github.event_name }}
- run: |
- if [[ "${GITHUB_EVENT_NAME}" == "workflow_dispatch" ]]; then
- echo "issue_url=${INPUTS_ISSUE_URL}" >> "${GITHUB_OUTPUT}"
- exit 0
- elif [[ "${GITHUB_EVENT_NAME}" == "issues" ]]; then
- echo "issue_url=${GITHUB_EVENT_ISSUE_HTML_URL}" >> "${GITHUB_OUTPUT}"
- exit 0
- else
- echo "::error::Unsupported event type: ${GITHUB_EVENT_NAME}"
- exit 1
- fi
-
- name: Extract context key from issue
id: extract-context
env:
- ISSUE_URL: ${{ steps.determine-issue-url.outputs.issue_url }}
+ ISSUE_URL: ${{ steps.determine-inputs.outputs.issue_url }}
GH_TOKEN: ${{ github.token }}
run: |
issue_number="$(gh issue view "${ISSUE_URL}" --json number --jq '.number')"
@@ -146,7 +168,7 @@ jobs:
env:
CODER_SESSION_TOKEN: ${{ secrets.TRAIAGE_CODER_SESSION_TOKEN }}
GH_TOKEN: ${{ github.token }}
- GITHUB_USER_ID: ${{ steps.github-user-id.outputs.github_user_id }}
+ GITHUB_USER_ID: ${{ steps.determine-inputs.outputs.github_user_id }}
run: |
user_json=$(
coder users list --github-user-id="${GITHUB_USER_ID}" --output=json
@@ -169,11 +191,12 @@ jobs:
CONTEXT_KEY: ${{ steps.extract-context.outputs.context_key }}
GH_TOKEN: ${{ github.token }}
GITHUB_REPOSITORY: ${{ github.repository }}
- ISSUE_URL: ${{ steps.determine-issue-url.outputs.issue_url }}
- PREFIX: ${{ inputs.prefix }}
+ ISSUE_URL: ${{ steps.determine-inputs.outputs.issue_url }}
+ PREFIX: ${{ steps.determine-inputs.outputs.prefix }}
RUN_ID: ${{ github.run_id }}
+ TEMPLATE_NAME: ${{ steps.determine-inputs.outputs.template_name }}
TEMPLATE_PARAMETERS: ${{ secrets.TRAIAGE_TEMPLATE_PARAMETERS }}
- TEMPLATE_PRESET: ${{ inputs.template_preset }}
+ TEMPLATE_PRESET: ${{ steps.determine-inputs.outputs.template_preset }}
run: |
# Fetch issue description using `gh` CLI
issue_description=$(gh issue view "${ISSUE_URL}")
@@ -203,21 +226,21 @@ jobs:
- name: Create and upload archive
id: create-archive
- if: inputs.cleanup
+ if: steps.determine-inputs.outputs.cleanup == 'true'
env:
BUCKET_PREFIX: "gs://coder-traiage-outputs/traiage"
CODER_USERNAME: ${{ steps.get-coder-username.outputs.coder_username }}
TASK_NAME: ${{ steps.create-task.outputs.TASK_NAME }}
run: |
echo "Waiting for task to complete..."
- coder exp task status "${CODER_USERNAME}/$TASK_NAME" --watch
- echo "Creating archive for workspace: $TASK_NAME"
+ coder exp task status "${TASK_NAME}" --watch
+ echo "Creating archive for workspace: ${TASK_NAME}"
./scripts/traiage.sh archive
echo "archive_url=${BUCKET_PREFIX%%/}/$TASK_NAME.tar.gz" >> "${GITHUB_OUTPUT}"
- name: Generate a summary of the changes and post a comment on GitHub.
id: generate-summary
- if: inputs.cleanup
+ if: steps.determine-inputs.outputs.cleanup == 'true'
env:
ARCHIVE_URL: ${{ steps.create-archive.outputs.archive_url }}
BUCKET_PREFIX: "gs://coder-traiage-outputs/traiage"
@@ -225,7 +248,7 @@ jobs:
CONTEXT_KEY: ${{ steps.extract-context.outputs.context_key }}
GH_TOKEN: ${{ github.token }}
GITHUB_REPOSITORY: ${{ github.repository }}
- ISSUE_URL: ${{ steps.determine-issue-url.outputs.issue_url }}
+ ISSUE_URL: ${{ steps.determine-inputs.outputs.issue_url }}
TASK_NAME: ${{ steps.create-task.outputs.TASK_NAME }}
run: |
SUMMARY_FILE=$(mktemp)
@@ -256,7 +279,7 @@ jobs:
cat "${SUMMARY_FILE}" >> "${GITHUB_STEP_SUMMARY}"
- name: Cleanup task
- if: inputs.cleanup && steps.create-task.outputs.TASK_NAME != '' && steps.create-archive.outputs.archive_url != ''
+ if: steps.determine-inputs.outputs.cleanup == 'true' && steps.create-task.outputs.TASK_NAME != '' && steps.create-archive.outputs.archive_url != ''
run: |
echo "Cleaning up task: $TASK_NAME"
./scripts/traiage.sh delete || true
From 3afab824f5ce227543788ad65474fb39c63b740a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=82=B1=E3=82=A4=E3=83=A9?=
Date: Wed, 1 Oct 2025 13:26:49 -0600
Subject: [PATCH 009/298] fix: revert playwright update and update dependabot
config (#20103)
---
.github/dependabot.yaml | 4 ++++
site/package.json | 2 +-
site/pnpm-lock.yaml | 26 +++++++++++++-------------
3 files changed, 18 insertions(+), 14 deletions(-)
diff --git a/.github/dependabot.yaml b/.github/dependabot.yaml
index 67d1f1342dcaf..fbf713d16b5bd 100644
--- a/.github/dependabot.yaml
+++ b/.github/dependabot.yaml
@@ -80,6 +80,9 @@ updates:
mui:
patterns:
- "@mui*"
+ radix:
+ patterns:
+ - "@radix-ui/*"
react:
patterns:
- "react"
@@ -104,6 +107,7 @@ updates:
- dependency-name: "*"
update-types:
- version-update:semver-major
+ - dependency-name: "@playwright/test"
open-pull-requests-limit: 15
- package-ecosystem: "terraform"
diff --git a/site/package.json b/site/package.json
index 14e3365fc6d54..d18b8f1d5a0d4 100644
--- a/site/package.json
+++ b/site/package.json
@@ -126,7 +126,7 @@
"@biomejs/biome": "2.2.0",
"@chromatic-com/storybook": "4.1.0",
"@octokit/types": "12.3.0",
- "@playwright/test": "1.55.1",
+ "@playwright/test": "1.50.1",
"@storybook/addon-docs": "9.1.2",
"@storybook/addon-links": "9.1.2",
"@storybook/addon-themes": "9.1.2",
diff --git a/site/pnpm-lock.yaml b/site/pnpm-lock.yaml
index f36ffa639e6d9..e49af3a101ba3 100644
--- a/site/pnpm-lock.yaml
+++ b/site/pnpm-lock.yaml
@@ -288,8 +288,8 @@ importers:
specifier: 12.3.0
version: 12.3.0
'@playwright/test':
- specifier: 1.55.1
- version: 1.55.1
+ specifier: 1.50.1
+ version: 1.50.1
'@storybook/addon-docs':
specifier: 9.1.2
version: 9.1.2(@types/react@19.1.17)(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)))
@@ -1625,8 +1625,8 @@ packages:
resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==, tarball: https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz}
engines: {node: '>=14'}
- '@playwright/test@1.55.1':
- resolution: {integrity: sha512-IVAh/nOJaw6W9g+RJVlIQJ6gSiER+ae6mKQ5CX1bERzQgbC1VSeBlwdvczT7pxb0GWiyrxH4TGKbMfDb4Sq/ig==, tarball: https://registry.npmjs.org/@playwright/test/-/test-1.55.1.tgz}
+ '@playwright/test@1.50.1':
+ resolution: {integrity: sha512-Jii3aBg+CEDpgnuDxEp/h7BimHcUTDlpEtce89xEumlJ5ef2hqepZ+PWp1DDpYC/VO9fmWVI1IlEaoI5fK9FXQ==, tarball: https://registry.npmjs.org/@playwright/test/-/test-1.50.1.tgz}
engines: {node: '>=18'}
hasBin: true
@@ -5459,13 +5459,13 @@ packages:
resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==, tarball: https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz}
engines: {node: '>=8'}
- playwright-core@1.55.1:
- resolution: {integrity: sha512-Z6Mh9mkwX+zxSlHqdr5AOcJnfp+xUWLCt9uKV18fhzA8eyxUd8NUWzAjxUh55RZKSYwDGX0cfaySdhZJGMoJ+w==, tarball: https://registry.npmjs.org/playwright-core/-/playwright-core-1.55.1.tgz}
+ playwright-core@1.50.1:
+ resolution: {integrity: sha512-ra9fsNWayuYumt+NiM069M6OkcRb1FZSK8bgi66AtpFoWkg2+y0bJSNmkFrWhMbEBbVKC/EruAHH3g0zmtwGmQ==, tarball: https://registry.npmjs.org/playwright-core/-/playwright-core-1.50.1.tgz}
engines: {node: '>=18'}
hasBin: true
- playwright@1.55.1:
- resolution: {integrity: sha512-cJW4Xd/G3v5ovXtJJ52MAOclqeac9S/aGGgRzLabuF8TnIb6xHvMzKIa6JmrRzUkeXJgfL1MhukP0NK6l39h3A==, tarball: https://registry.npmjs.org/playwright/-/playwright-1.55.1.tgz}
+ playwright@1.50.1:
+ resolution: {integrity: sha512-G8rwsOQJ63XG6BbKj2w5rHeavFjy5zynBA9zsJMMtBoe/Uf757oG12NXz6e6OirF7RCrTVAKFXbLmn1RbL7Qaw==, tarball: https://registry.npmjs.org/playwright/-/playwright-1.50.1.tgz}
engines: {node: '>=18'}
hasBin: true
@@ -7915,9 +7915,9 @@ snapshots:
'@pkgjs/parseargs@0.11.0':
optional: true
- '@playwright/test@1.55.1':
+ '@playwright/test@1.50.1':
dependencies:
- playwright: 1.55.1
+ playwright: 1.50.1
'@popperjs/core@2.11.8': {}
@@ -12322,11 +12322,11 @@ snapshots:
dependencies:
find-up: 4.1.0
- playwright-core@1.55.1: {}
+ playwright-core@1.50.1: {}
- playwright@1.55.1:
+ playwright@1.50.1:
dependencies:
- playwright-core: 1.55.1
+ playwright-core: 1.50.1
optionalDependencies:
fsevents: 2.3.2
From 7c3e24f3be4519f6a33fa10ac61ee7576722e693 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 1 Oct 2025 19:33:42 +0000
Subject: [PATCH 010/298] chore: bump ubuntu from `0e5e4a5` to `4e0171b` in
/dogfood/coder (#20105)
Bumps ubuntu from `0e5e4a5` to `4e0171b`.
[](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
dogfood/coder/Dockerfile | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/dogfood/coder/Dockerfile b/dogfood/coder/Dockerfile
index 90bdcb71aaacb..f64c47819d799 100644
--- a/dogfood/coder/Dockerfile
+++ b/dogfood/coder/Dockerfile
@@ -8,7 +8,7 @@ RUN sed -i 's|http://deb.debian.org/debian|http://mirrors.edge.kernel.org/debian
RUN apt-get update && apt-get install -y libssl-dev openssl pkg-config build-essential
RUN cargo install jj-cli typos-cli watchexec-cli
-FROM ubuntu:jammy@sha256:0e5e4a57c2499249aafc3b40fcd541e9a456aab7296681a3994d631587203f97 AS go
+FROM ubuntu:jammy@sha256:4e0171b9275e12d375863f2b3ae9ce00a4c53ddda176bd55868df97ac6f21a6e AS go
# Install Go manually, so that we can control the version
ARG GO_VERSION=1.24.6
@@ -97,7 +97,7 @@ RUN curl -L -o protoc.zip https://github.com/protocolbuffers/protobuf/releases/d
unzip protoc.zip && \
rm protoc.zip
-FROM ubuntu:jammy@sha256:0e5e4a57c2499249aafc3b40fcd541e9a456aab7296681a3994d631587203f97
+FROM ubuntu:jammy@sha256:4e0171b9275e12d375863f2b3ae9ce00a4c53ddda176bd55868df97ac6f21a6e
SHELL ["/bin/bash", "-c"]
From b05033897aa32ee2620adc7b940a28f56d5724e6 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 1 Oct 2025 19:33:54 +0000
Subject: [PATCH 011/298] chore: bump rust from `3f391b0` to `1219c0b` in
/dogfood/coder (#20108)
Bumps rust from `3f391b0` to `1219c0b`.
[](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
dogfood/coder/Dockerfile | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dogfood/coder/Dockerfile b/dogfood/coder/Dockerfile
index f64c47819d799..7f1eda55a6c58 100644
--- a/dogfood/coder/Dockerfile
+++ b/dogfood/coder/Dockerfile
@@ -1,5 +1,5 @@
# 1.86.0
-FROM rust:slim@sha256:3f391b0678a6e0c88fd26f13e399c9c515ac47354e3cadfee7daee3b21651a4f AS rust-utils
+FROM rust:slim@sha256:1219c0b5980e8310eb8e08a7fec9e2159ffc9f166cc9999ddb13604c43cd0eb6 AS rust-utils
# Install rust helper programs
ENV CARGO_INSTALL_ROOT=/tmp/
# Use more reliable mirrors for Debian packages
From 3eb6e1cc9771e7fea2313b2d4c78cd4730148d0b Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 1 Oct 2025 19:34:11 +0000
Subject: [PATCH 012/298] chore: bump coder/claude-code/coder from 3.0.0 to
3.0.1 in /dogfood/coder (#20104)
[](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
dogfood/coder/main.tf | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dogfood/coder/main.tf b/dogfood/coder/main.tf
index 6762f2bcbee27..614b25cdb9ec8 100644
--- a/dogfood/coder/main.tf
+++ b/dogfood/coder/main.tf
@@ -866,7 +866,7 @@ locals {
module "claude-code" {
count = local.has_ai_prompt ? data.coder_workspace.me.start_count : 0
source = "dev.registry.coder.com/coder/claude-code/coder"
- version = "3.0.0"
+ version = "3.0.1"
agent_id = coder_agent.dev.id
workdir = local.repo_dir
claude_code_version = "latest"
From c6c9fa1e3972b8ea19fa73c9179137ff47b3cafd Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 1 Oct 2025 19:34:28 +0000
Subject: [PATCH 013/298] chore: bump alpine from 3.21.3 to 3.22.1 in /scripts
(#20107)
Bumps alpine from 3.21.3 to 3.22.1.
[](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
scripts/Dockerfile.base | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/scripts/Dockerfile.base b/scripts/Dockerfile.base
index 53c999301e410..e13b5ffa666e0 100644
--- a/scripts/Dockerfile.base
+++ b/scripts/Dockerfile.base
@@ -1,7 +1,7 @@
# This is the base image used for Coder images. It's a multi-arch image that is
# built in depot.dev for all supported architectures. Since it's built on real
# hardware and not cross-compiled, it can have "RUN" commands.
-FROM alpine:3.21.3@sha256:a8560b36e8b8210634f77d9f7f9efd7ffa463e380b75e2e74aff4511df3ef88c
+FROM alpine:3.22.1@sha256:4bcff63911fcb4448bd4fdacec207030997caf25e9bea4045fa6c8c44de311d1
# We use a single RUN command to reduce the number of layers in the image.
# NOTE: Keep the Terraform version in sync with minTerraformVersion and
From 7328fa5c0866ca46587b5e39a50ea9a241330a03 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 1 Oct 2025 19:37:23 +0000
Subject: [PATCH 014/298] chore: bump typescript from 5.7.3 to 5.9.3 in
/offlinedocs (#20112)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Bumps [typescript](https://github.com/microsoft/TypeScript) from 5.7.3
to 5.9.3.
Release notes
Sourced from typescript's
releases .
TypeScript 5.9.3
Note: this tag was recreated to point at the correct commit. The npm
package contained the correct content.
For release notes, check out the release
announcement
Downloads are available on:
TypeScript 5.9
For release notes, check out the release
announcement
Downloads are available on:
TypeScript 5.9 RC
For release notes, check out the release
announcement
Downloads are available on:
TypeScript 5.9 Beta
For release notes, check out the release
announcement .
Downloads are available on:
TypeScript 5.8.3
For release notes, check out the release
announcement .
Downloads are available on:
... (truncated)
Commits
c63de15
Bump version to 5.9.3 and LKG
8428ca4
🤖 Pick PR #62438
(Fix incorrectly ignored dts file fr...) into release-5.9 (#...
a131cac
🤖 Pick PR #62351
(Add missing Float16Array constructo...) into release-5.9 (#...
0424333
🤖 Pick PR #62423
(Revert PR 61928) into release-5.9 (#62425 )
bdb641a
🤖 Pick PR #62311
(Fix parenthesizer rules for manuall...) into release-5.9 (#...
0d9b9b9
🤖 Pick PR #61978
(Restructure CI to prepare for requi...) into release-5.9 (#...
2dce0c5
Intentionally regress one buggy declaration output to an older version
(#62163 )
5be3346
Bump version to 5.9.2 and LKG
ad825f2
Bump version to 5.9.1-rc and LKG
463a5bf
Update LKG
Additional commits viewable in compare
view
[](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
offlinedocs/package.json | 2 +-
offlinedocs/pnpm-lock.yaml | 92 +++++++++++++++++++-------------------
2 files changed, 47 insertions(+), 47 deletions(-)
diff --git a/offlinedocs/package.json b/offlinedocs/package.json
index 15c5ce793b135..26073286ddb65 100644
--- a/offlinedocs/package.json
+++ b/offlinedocs/package.json
@@ -38,7 +38,7 @@
"eslint": "8.57.1",
"eslint-config-next": "14.2.33",
"prettier": "3.6.2",
- "typescript": "5.7.3"
+ "typescript": "5.9.3"
},
"engines": {
"npm": ">=9.0.0 <10.0.0",
diff --git a/offlinedocs/pnpm-lock.yaml b/offlinedocs/pnpm-lock.yaml
index 368b8515c6b54..7c4466814364c 100644
--- a/offlinedocs/pnpm-lock.yaml
+++ b/offlinedocs/pnpm-lock.yaml
@@ -78,13 +78,13 @@ importers:
version: 8.57.1
eslint-config-next:
specifier: 14.2.33
- version: 14.2.33(eslint@8.57.1)(typescript@5.7.3)
+ version: 14.2.33(eslint@8.57.1)(typescript@5.9.3)
prettier:
specifier: 3.6.2
version: 3.6.2
typescript:
- specifier: 5.7.3
- version: 5.7.3
+ specifier: 5.9.3
+ version: 5.9.3
packages:
@@ -2465,8 +2465,8 @@ packages:
resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==}
engines: {node: '>= 0.4'}
- typescript@5.7.3:
- resolution: {integrity: sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==}
+ typescript@5.9.3:
+ resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==}
engines: {node: '>=14.17'}
hasBin: true
@@ -3101,41 +3101,41 @@ snapshots:
'@types/unist@3.0.3': {}
- '@typescript-eslint/eslint-plugin@8.45.0(@typescript-eslint/parser@8.45.0(eslint@8.57.1)(typescript@5.7.3))(eslint@8.57.1)(typescript@5.7.3)':
+ '@typescript-eslint/eslint-plugin@8.45.0(@typescript-eslint/parser@8.45.0(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1)(typescript@5.9.3)':
dependencies:
'@eslint-community/regexpp': 4.12.1
- '@typescript-eslint/parser': 8.45.0(eslint@8.57.1)(typescript@5.7.3)
+ '@typescript-eslint/parser': 8.45.0(eslint@8.57.1)(typescript@5.9.3)
'@typescript-eslint/scope-manager': 8.45.0
- '@typescript-eslint/type-utils': 8.45.0(eslint@8.57.1)(typescript@5.7.3)
- '@typescript-eslint/utils': 8.45.0(eslint@8.57.1)(typescript@5.7.3)
+ '@typescript-eslint/type-utils': 8.45.0(eslint@8.57.1)(typescript@5.9.3)
+ '@typescript-eslint/utils': 8.45.0(eslint@8.57.1)(typescript@5.9.3)
'@typescript-eslint/visitor-keys': 8.45.0
eslint: 8.57.1
graphemer: 1.4.0
ignore: 7.0.5
natural-compare: 1.4.0
- ts-api-utils: 2.1.0(typescript@5.7.3)
- typescript: 5.7.3
+ ts-api-utils: 2.1.0(typescript@5.9.3)
+ typescript: 5.9.3
transitivePeerDependencies:
- supports-color
- '@typescript-eslint/parser@8.45.0(eslint@8.57.1)(typescript@5.7.3)':
+ '@typescript-eslint/parser@8.45.0(eslint@8.57.1)(typescript@5.9.3)':
dependencies:
'@typescript-eslint/scope-manager': 8.45.0
'@typescript-eslint/types': 8.45.0
- '@typescript-eslint/typescript-estree': 8.45.0(typescript@5.7.3)
+ '@typescript-eslint/typescript-estree': 8.45.0(typescript@5.9.3)
'@typescript-eslint/visitor-keys': 8.45.0
debug: 4.4.3
eslint: 8.57.1
- typescript: 5.7.3
+ typescript: 5.9.3
transitivePeerDependencies:
- supports-color
- '@typescript-eslint/project-service@8.45.0(typescript@5.7.3)':
+ '@typescript-eslint/project-service@8.45.0(typescript@5.9.3)':
dependencies:
- '@typescript-eslint/tsconfig-utils': 8.45.0(typescript@5.7.3)
+ '@typescript-eslint/tsconfig-utils': 8.45.0(typescript@5.9.3)
'@typescript-eslint/types': 8.45.0
debug: 4.4.3
- typescript: 5.7.3
+ typescript: 5.9.3
transitivePeerDependencies:
- supports-color
@@ -3144,28 +3144,28 @@ snapshots:
'@typescript-eslint/types': 8.45.0
'@typescript-eslint/visitor-keys': 8.45.0
- '@typescript-eslint/tsconfig-utils@8.45.0(typescript@5.7.3)':
+ '@typescript-eslint/tsconfig-utils@8.45.0(typescript@5.9.3)':
dependencies:
- typescript: 5.7.3
+ typescript: 5.9.3
- '@typescript-eslint/type-utils@8.45.0(eslint@8.57.1)(typescript@5.7.3)':
+ '@typescript-eslint/type-utils@8.45.0(eslint@8.57.1)(typescript@5.9.3)':
dependencies:
'@typescript-eslint/types': 8.45.0
- '@typescript-eslint/typescript-estree': 8.45.0(typescript@5.7.3)
- '@typescript-eslint/utils': 8.45.0(eslint@8.57.1)(typescript@5.7.3)
+ '@typescript-eslint/typescript-estree': 8.45.0(typescript@5.9.3)
+ '@typescript-eslint/utils': 8.45.0(eslint@8.57.1)(typescript@5.9.3)
debug: 4.4.3
eslint: 8.57.1
- ts-api-utils: 2.1.0(typescript@5.7.3)
- typescript: 5.7.3
+ ts-api-utils: 2.1.0(typescript@5.9.3)
+ typescript: 5.9.3
transitivePeerDependencies:
- supports-color
'@typescript-eslint/types@8.45.0': {}
- '@typescript-eslint/typescript-estree@8.45.0(typescript@5.7.3)':
+ '@typescript-eslint/typescript-estree@8.45.0(typescript@5.9.3)':
dependencies:
- '@typescript-eslint/project-service': 8.45.0(typescript@5.7.3)
- '@typescript-eslint/tsconfig-utils': 8.45.0(typescript@5.7.3)
+ '@typescript-eslint/project-service': 8.45.0(typescript@5.9.3)
+ '@typescript-eslint/tsconfig-utils': 8.45.0(typescript@5.9.3)
'@typescript-eslint/types': 8.45.0
'@typescript-eslint/visitor-keys': 8.45.0
debug: 4.4.3
@@ -3173,19 +3173,19 @@ snapshots:
is-glob: 4.0.3
minimatch: 9.0.5
semver: 7.7.2
- ts-api-utils: 2.1.0(typescript@5.7.3)
- typescript: 5.7.3
+ ts-api-utils: 2.1.0(typescript@5.9.3)
+ typescript: 5.9.3
transitivePeerDependencies:
- supports-color
- '@typescript-eslint/utils@8.45.0(eslint@8.57.1)(typescript@5.7.3)':
+ '@typescript-eslint/utils@8.45.0(eslint@8.57.1)(typescript@5.9.3)':
dependencies:
'@eslint-community/eslint-utils': 4.9.0(eslint@8.57.1)
'@typescript-eslint/scope-manager': 8.45.0
'@typescript-eslint/types': 8.45.0
- '@typescript-eslint/typescript-estree': 8.45.0(typescript@5.7.3)
+ '@typescript-eslint/typescript-estree': 8.45.0(typescript@5.9.3)
eslint: 8.57.1
- typescript: 5.7.3
+ typescript: 5.9.3
transitivePeerDependencies:
- supports-color
@@ -3732,21 +3732,21 @@ snapshots:
escape-string-regexp@5.0.0: {}
- eslint-config-next@14.2.33(eslint@8.57.1)(typescript@5.7.3):
+ eslint-config-next@14.2.33(eslint@8.57.1)(typescript@5.9.3):
dependencies:
'@next/eslint-plugin-next': 14.2.33
'@rushstack/eslint-patch': 1.12.0
- '@typescript-eslint/eslint-plugin': 8.45.0(@typescript-eslint/parser@8.45.0(eslint@8.57.1)(typescript@5.7.3))(eslint@8.57.1)(typescript@5.7.3)
- '@typescript-eslint/parser': 8.45.0(eslint@8.57.1)(typescript@5.7.3)
+ '@typescript-eslint/eslint-plugin': 8.45.0(@typescript-eslint/parser@8.45.0(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1)(typescript@5.9.3)
+ '@typescript-eslint/parser': 8.45.0(eslint@8.57.1)(typescript@5.9.3)
eslint: 8.57.1
eslint-import-resolver-node: 0.3.9
eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@8.57.1)
- eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.45.0(eslint@8.57.1)(typescript@5.7.3))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1)
+ eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.45.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1)
eslint-plugin-jsx-a11y: 6.10.2(eslint@8.57.1)
eslint-plugin-react: 7.37.5(eslint@8.57.1)
eslint-plugin-react-hooks: 5.0.0-canary-7118f5dd7-20230705(eslint@8.57.1)
optionalDependencies:
- typescript: 5.7.3
+ typescript: 5.9.3
transitivePeerDependencies:
- eslint-import-resolver-webpack
- eslint-plugin-import-x
@@ -3771,22 +3771,22 @@ snapshots:
tinyglobby: 0.2.15
unrs-resolver: 1.11.1
optionalDependencies:
- eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.45.0(eslint@8.57.1)(typescript@5.7.3))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1)
+ eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.45.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1)
transitivePeerDependencies:
- supports-color
- eslint-module-utils@2.12.1(@typescript-eslint/parser@8.45.0(eslint@8.57.1)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1):
+ eslint-module-utils@2.12.1(@typescript-eslint/parser@8.45.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1):
dependencies:
debug: 3.2.7
optionalDependencies:
- '@typescript-eslint/parser': 8.45.0(eslint@8.57.1)(typescript@5.7.3)
+ '@typescript-eslint/parser': 8.45.0(eslint@8.57.1)(typescript@5.9.3)
eslint: 8.57.1
eslint-import-resolver-node: 0.3.9
eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@8.57.1)
transitivePeerDependencies:
- supports-color
- eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.45.0(eslint@8.57.1)(typescript@5.7.3))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1):
+ eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.45.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1):
dependencies:
'@rtsao/scc': 1.1.0
array-includes: 3.1.9
@@ -3797,7 +3797,7 @@ snapshots:
doctrine: 2.1.0
eslint: 8.57.1
eslint-import-resolver-node: 0.3.9
- eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.45.0(eslint@8.57.1)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1)
+ eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.45.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1)
hasown: 2.0.2
is-core-module: 2.16.1
is-glob: 4.0.3
@@ -3809,7 +3809,7 @@ snapshots:
string.prototype.trimend: 1.0.9
tsconfig-paths: 3.15.0
optionalDependencies:
- '@typescript-eslint/parser': 8.45.0(eslint@8.57.1)(typescript@5.7.3)
+ '@typescript-eslint/parser': 8.45.0(eslint@8.57.1)(typescript@5.9.3)
transitivePeerDependencies:
- eslint-import-resolver-typescript
- eslint-import-resolver-webpack
@@ -5506,9 +5506,9 @@ snapshots:
trough@2.2.0: {}
- ts-api-utils@2.1.0(typescript@5.7.3):
+ ts-api-utils@2.1.0(typescript@5.9.3):
dependencies:
- typescript: 5.7.3
+ typescript: 5.9.3
tsconfig-paths@3.15.0:
dependencies:
@@ -5562,7 +5562,7 @@ snapshots:
possible-typed-array-names: 1.1.0
reflect.getprototypeof: 1.0.10
- typescript@5.7.3: {}
+ typescript@5.9.3: {}
unbox-primitive@1.1.0:
dependencies:
From f7388f3dfc5d346831dde385a14b3e0351dbf11e Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 1 Oct 2025 19:41:20 +0000
Subject: [PATCH 015/298] chore: bump github.com/anthropics/anthropic-sdk-go
from 1.12.0 to 1.13.0 (#20109)
Bumps
[github.com/anthropics/anthropic-sdk-go](https://github.com/anthropics/anthropic-sdk-go)
from 1.12.0 to 1.13.0.
Release notes
Sourced from github.com/anthropics/anthropic-sdk-go's
releases .
v1.13.0
1.13.0 (2025-09-29)
Full Changelog: v1.12.0...v1.13.0
Features
api: adds support for Claude Sonnet 4.5 and context
management features (3d5d51a )
Bug Fixes
bugfix for setting JSON keys with special characters (c868b92 )
internal: unmarshal correctly when there are
multiple discriminators (ecc3ce3 )
use slices.Concat instead of sometimes modifying r.Options (88e7186 )
Chores
bump minimum go version to 1.22 (87af8f3 )
do not install brew dependencies in ./scripts/bootstrap by default
(c689348 )
internal: fix tests (bfc6eaf )
update more docs for 1.22 (d67c50d )
Changelog
Sourced from github.com/anthropics/anthropic-sdk-go's
changelog .
1.13.0 (2025-09-29)
Full Changelog: v1.12.0...v1.13.0
Features
api: adds support for Claude Sonnet 4.5 and context
management features (3d5d51a )
Bug Fixes
bugfix for setting JSON keys with special characters (c868b92 )
internal: unmarshal correctly when there are
multiple discriminators (ecc3ce3 )
use slices.Concat instead of sometimes modifying r.Options (88e7186 )
Chores
bump minimum go version to 1.22 (87af8f3 )
do not install brew dependencies in ./scripts/bootstrap by default
(c689348 )
internal: fix tests (bfc6eaf )
update more docs for 1.22 (d67c50d )
Commits
e8befdc
release: 1.13.0
1de6d47
feat(api): adds support for Claude Sonnet 4.5 and context management
features
a9aab31
fix: bugfix for setting JSON keys with special characters
41a7454
codegen metadata
31633bd
chore: do not install brew dependencies in ./scripts/bootstrap by
default
2deaed6
fix: use slices.Concat instead of sometimes modifying r.Options
9f35b68
chore: update more docs for 1.22
287a399
chore: bump minimum go version to 1.22
aa4540a
chore(internal): fix tests
73e5532
codegen metadata
Additional commits viewable in compare
view
[](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
go.mod | 2 +-
go.sum | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/go.mod b/go.mod
index b0c3360913ceb..581f1beaeecff 100644
--- a/go.mod
+++ b/go.mod
@@ -475,7 +475,7 @@ require (
)
require (
- github.com/anthropics/anthropic-sdk-go v1.12.0
+ github.com/anthropics/anthropic-sdk-go v1.13.0
github.com/brianvoe/gofakeit/v7 v7.7.1
github.com/coder/agentapi-sdk-go v0.0.0-20250505131810-560d1d88d225
github.com/coder/aibridge v0.1.3
diff --git a/go.sum b/go.sum
index 2842cbcc7baa2..c1151e853041d 100644
--- a/go.sum
+++ b/go.sum
@@ -722,8 +722,8 @@ github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwTo
github.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY=
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
-github.com/anthropics/anthropic-sdk-go v1.12.0 h1:xPqlGnq7rWrTiHazIvCiumA0u7mGQnwDQtvA1M82h9U=
-github.com/anthropics/anthropic-sdk-go v1.12.0/go.mod h1:WTz31rIUHUHqai2UslPpw5CwXrQP3geYBioRV4WOLvE=
+github.com/anthropics/anthropic-sdk-go v1.13.0 h1:Bhbe8sRoDPtipttg8bQYrMCKe2b79+q6rFW1vOKEUKI=
+github.com/anthropics/anthropic-sdk-go v1.13.0/go.mod h1:WTz31rIUHUHqai2UslPpw5CwXrQP3geYBioRV4WOLvE=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/apache/arrow/go/v10 v10.0.1/go.mod h1:YvhnlEePVnBS4+0z3fhPfUy7W1Ikj0Ih0vcRo/gZ1M0=
github.com/apache/arrow/go/v11 v11.0.0/go.mod h1:Eg5OsL5H+e299f7u5ssuXsuHQVEGC4xei5aX110hRiI=
From 0765970d4905e4a7b6b3b9a39a4efc1cfe28d11c Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 1 Oct 2025 19:42:04 +0000
Subject: [PATCH 016/298] chore: bump jest-fixed-jsdom from 0.0.9 to 0.0.10 in
/site (#20114)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Bumps [jest-fixed-jsdom](https://github.com/mswjs/jest-fixed-jsdom) from
0.0.9 to 0.0.10.
Release notes
Sourced from jest-fixed-jsdom's
releases .
v0.0.10 (2025-08-30)
Bug Fixes
using node's global AbortController and AbortSignal (#35 )
(1e63cde866d5575f42ec5fc4520ebb9c487101e2) @stevematney
Commits
[](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
site/package.json | 2 +-
site/pnpm-lock.yaml | 10 +++++-----
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/site/package.json b/site/package.json
index d18b8f1d5a0d4..eb3ff1a828ee4 100644
--- a/site/package.json
+++ b/site/package.json
@@ -164,7 +164,7 @@
"jest": "29.7.0",
"jest-canvas-mock": "2.5.2",
"jest-environment-jsdom": "29.5.0",
- "jest-fixed-jsdom": "0.0.9",
+ "jest-fixed-jsdom": "0.0.10",
"jest-location-mock": "2.0.0",
"jest-websocket-mock": "2.5.0",
"jest_workaround": "0.1.14",
diff --git a/site/pnpm-lock.yaml b/site/pnpm-lock.yaml
index e49af3a101ba3..85ab5b0469cd2 100644
--- a/site/pnpm-lock.yaml
+++ b/site/pnpm-lock.yaml
@@ -402,8 +402,8 @@ importers:
specifier: 29.5.0
version: 29.5.0
jest-fixed-jsdom:
- specifier: 0.0.9
- version: 0.0.9(jest-environment-jsdom@29.5.0)
+ specifier: 0.0.10
+ version: 0.0.10(jest-environment-jsdom@29.5.0)
jest-location-mock:
specifier: 2.0.0
version: 2.0.0
@@ -4643,8 +4643,8 @@ packages:
resolution: {integrity: sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==, tarball: https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
- jest-fixed-jsdom@0.0.9:
- resolution: {integrity: sha512-KPfqh2+sn5q2B+7LZktwDcwhCpOpUSue8a1I+BcixWLOQoEVyAjAGfH+IYZGoxZsziNojoHGRTC8xRbB1wDD4g==, tarball: https://registry.npmjs.org/jest-fixed-jsdom/-/jest-fixed-jsdom-0.0.9.tgz}
+ jest-fixed-jsdom@0.0.10:
+ resolution: {integrity: sha512-WaEVX+FripJh+Hn/7dysIgqP66h0KT1NNC22NGmNYANExtCoYNk1q2yjwwcdSboBMkkhn0NtmvKad/cmisnCLg==, tarball: https://registry.npmjs.org/jest-fixed-jsdom/-/jest-fixed-jsdom-0.0.10.tgz}
engines: {node: '>=18.0.0'}
peerDependencies:
jest-environment-jsdom: '>=28.0.0'
@@ -11066,7 +11066,7 @@ snapshots:
jest-mock: 29.7.0
jest-util: 29.7.0
- jest-fixed-jsdom@0.0.9(jest-environment-jsdom@29.5.0):
+ jest-fixed-jsdom@0.0.10(jest-environment-jsdom@29.5.0):
dependencies:
jest-environment-jsdom: 29.5.0
From f68495aa6eca9282a83e83c6bcb63d03def3395f Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 1 Oct 2025 19:42:17 +0000
Subject: [PATCH 017/298] chore: bump ua-parser-js from 1.0.40 to 1.0.41 in
/site (#20116)
Bumps [ua-parser-js](https://github.com/faisalman/ua-parser-js) from
1.0.40 to 1.0.41.
Release notes
Sourced from ua-parser-js's
releases .
v1.0.41
Version 0.7.41 / 1.0.41
Add new browser: Daum, Ladybird
Add new device vendor: HMD
Add new engine: LibWeb
Add new os: Windows IoT, Ubuntu Touch
Improve cpu detection: ARM, x86
Improve device vendor detection: Apple, Archos, Generic, Google,
Honor, Huawei, Infinix, Nvidia, Lenovo, Nokia, OnePlus, Xiaomi
Improve device type detection: smarttv, wearables
Improve os detection: Linux, Symbian
Full Changelog : https://github.com/faisalman/ua-parser-js/compare/1.0.40...1.0.41
Changelog
Sourced from ua-parser-js's
changelog .
Version 0.7.41 / 1.0.41
Add new browser: Daum, Ladybird
Add new device vendor: HMD
Add new engine: LibWeb
Add new os: Windows IoT, Ubuntu Touch
Improve cpu detection: ARM, x86
Improve device vendor detection: Apple, Archos, Generic, Google,
Honor, Huawei, Infinix, Nvidia, Lenovo, Nokia, OnePlus, Xiaomi
Improve device type detection: smarttv, wearables
Improve os detection: Linux, Symbian
Commits
90017c9
Bump version 1.0.41 (mirror of 0.7.41)
af825ff
Bump version 0.7.41
5925954
Backport - Improve detection for Nokia device & Symbian OS
fc668ef
Backport - Improve device detection for Generic device: capture its
device mo...
0543fb2
Backport - Improve CPU detection: ARM
98f1c00
Backport - Improve device detection for unidentified SmartTV
vendors
d66c971
Backport - Improve detection for Nvidia devices
cbe6038
Backport - Add Daum app user agent (#773 )
e665bd5
Backport - Add new OS: Ubuntu Touch
20c3040
Backport - Add new device: Apple HomePod
Additional commits viewable in compare
view
[](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
site/package.json | 2 +-
site/pnpm-lock.yaml | 10 +++++-----
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/site/package.json b/site/package.json
index eb3ff1a828ee4..d44089b0624d6 100644
--- a/site/package.json
+++ b/site/package.json
@@ -114,7 +114,7 @@
"tailwind-merge": "2.6.0",
"tailwindcss-animate": "1.0.7",
"tzdata": "1.0.46",
- "ua-parser-js": "1.0.40",
+ "ua-parser-js": "1.0.41",
"ufuzzy": "npm:@leeoniya/ufuzzy@1.0.10",
"undici": "6.21.3",
"unique-names-generator": "4.7.1",
diff --git a/site/pnpm-lock.yaml b/site/pnpm-lock.yaml
index 85ab5b0469cd2..6d8a1395f0962 100644
--- a/site/pnpm-lock.yaml
+++ b/site/pnpm-lock.yaml
@@ -257,8 +257,8 @@ importers:
specifier: 1.0.46
version: 1.0.46
ua-parser-js:
- specifier: 1.0.40
- version: 1.0.40
+ specifier: 1.0.41
+ version: 1.0.41
ufuzzy:
specifier: npm:@leeoniya/ufuzzy@1.0.10
version: '@leeoniya/ufuzzy@1.0.10'
@@ -6320,8 +6320,8 @@ packages:
tzdata@1.0.46:
resolution: {integrity: sha512-zJ4Jv3KCgN3dFeSADpIfHKt9bdIY7TjK3ELaij6oFvyyQBuIZ9LwMlR51vJvMQvRWQ9cS2v92xeZ0sQW4hXCWA==, tarball: https://registry.npmjs.org/tzdata/-/tzdata-1.0.46.tgz}
- ua-parser-js@1.0.40:
- resolution: {integrity: sha512-z6PJ8Lml+v3ichVojCiB8toQJBuwR42ySM4ezjXIqXK3M0HczmKQ3LF4rhU55PfD99KEEXQG6yb7iOMyvYuHew==, tarball: https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.40.tgz}
+ ua-parser-js@1.0.41:
+ resolution: {integrity: sha512-LbBDqdIC5s8iROCUjMbW1f5dJQTEFB1+KO9ogbvlb3nm9n4YHa5p4KTvFPWvh2Hs8gZMBuiB1/8+pdfe/tDPug==, tarball: https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.41.tgz}
hasBin: true
undici-types@5.26.5:
@@ -13298,7 +13298,7 @@ snapshots:
tzdata@1.0.46: {}
- ua-parser-js@1.0.40: {}
+ ua-parser-js@1.0.41: {}
undici-types@5.26.5: {}
From a191ff9aa29e2a36d0eb8a920432a925433986fa Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 1 Oct 2025 19:42:26 +0000
Subject: [PATCH 018/298] chore: bump dayjs from 1.11.13 to 1.11.18 in /site
(#20115)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Bumps [dayjs](https://github.com/iamkun/dayjs) from 1.11.13 to 1.11.18.
Release notes
Sourced from dayjs's
releases .
v1.11.18
Bug Fixes
error semantic-release dependency (8cfb313 )
v1.11.17
Bug Fixes
[en-AU] locale use the same ordinal as moment (#2878 )
(1b95ecd )
v1.11.16
Bug Fixes
test release workflow (no code changes) (c38c428 )
v1.11.15
Bug Fixes
Fix misspellings in Irish or Irish Gaelic [ga] (#2861 )
(9c14a42 )
v1.11.14
Bug Fixes
.utcOffset(0, true) result and its clone are different bug (#2505 )
(fefdcd4 )
Changelog
Sourced from dayjs's
changelog .
Bug Fixes
error semantic-release dependency (8cfb313 )
Bug Fixes
[en-AU] locale use the same ordinal as moment (#2878 )
(1b95ecd )
Bug Fixes
test release workflow (no code changes) (c38c428 )
Bug Fixes
Fix misspellings in Irish or Irish Gaelic [ga] (#2861 )
(9c14a42 )
Bug Fixes
.utcOffset(0, true) result and its clone are different bug (#2505 )
(fefdcd4 )
Commits
[](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
site/package.json | 2 +-
site/pnpm-lock.yaml | 10 +++++-----
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/site/package.json b/site/package.json
index d44089b0624d6..3a974c5b0348e 100644
--- a/site/package.json
+++ b/site/package.json
@@ -83,7 +83,7 @@
"color-convert": "2.0.1",
"cron-parser": "4.9.0",
"cronstrue": "2.50.0",
- "dayjs": "1.11.13",
+ "dayjs": "1.11.18",
"emoji-mart": "5.6.0",
"file-saver": "2.0.5",
"formik": "2.4.6",
diff --git a/site/pnpm-lock.yaml b/site/pnpm-lock.yaml
index 6d8a1395f0962..6fdcf50cfd5b3 100644
--- a/site/pnpm-lock.yaml
+++ b/site/pnpm-lock.yaml
@@ -164,8 +164,8 @@ importers:
specifier: 2.50.0
version: 2.50.0
dayjs:
- specifier: 1.11.13
- version: 1.11.13
+ specifier: 1.11.18
+ version: 1.11.18
emoji-mart:
specifier: 5.6.0
version: 5.6.0
@@ -3707,8 +3707,8 @@ packages:
resolution: {integrity: sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==, tarball: https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz}
engines: {node: '>=0.11'}
- dayjs@1.11.13:
- resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==, tarball: https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz}
+ dayjs@1.11.18:
+ resolution: {integrity: sha512-zFBQ7WFRvVRhKcWoUh+ZA1g2HVgUbsZm9sbddh8EC5iv93sui8DVVz1Npvz+r6meo9VKfa8NyLWBsQK1VvIKPA==, tarball: https://registry.npmjs.org/dayjs/-/dayjs-1.11.18.tgz}
debug@2.6.9:
resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==, tarball: https://registry.npmjs.org/debug/-/debug-2.6.9.tgz}
@@ -9935,7 +9935,7 @@ snapshots:
dependencies:
'@babel/runtime': 7.26.10
- dayjs@1.11.13: {}
+ dayjs@1.11.18: {}
debug@2.6.9:
dependencies:
From 30f81edbceabe11261989fae6509ff76c245f95d Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 1 Oct 2025 19:42:34 +0000
Subject: [PATCH 019/298] chore: bump google.golang.org/api from 0.250.0 to
0.251.0 (#20110)
Bumps
[google.golang.org/api](https://github.com/googleapis/google-api-go-client)
from 0.250.0 to 0.251.0.
Release notes
Sourced from google.golang.org/api's
releases .
v0.251.0
Features
Changelog
Sourced from google.golang.org/api's
changelog .
Features
Commits
[](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
go.mod | 6 +++---
go.sum | 12 ++++++------
2 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/go.mod b/go.mod
index 581f1beaeecff..34967b03a7060 100644
--- a/go.mod
+++ b/go.mod
@@ -74,7 +74,7 @@ replace github.com/spf13/afero => github.com/aslilac/afero v0.0.0-20250403163713
require (
cdr.dev/slog v1.6.2-0.20250703074222-9df5e0a6c145
- cloud.google.com/go/compute/metadata v0.8.4
+ cloud.google.com/go/compute/metadata v0.9.0
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d
github.com/adrg/xdg v0.5.0
github.com/ammario/tlru v0.4.0
@@ -206,7 +206,7 @@ require (
golang.org/x/text v0.29.0
golang.org/x/tools v0.37.0
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da
- google.golang.org/api v0.250.0
+ google.golang.org/api v0.251.0
google.golang.org/grpc v1.75.1
google.golang.org/protobuf v1.36.9
gopkg.in/DataDog/dd-trace-go.v1 v1.74.0
@@ -454,7 +454,7 @@ require (
google.golang.org/appengine v1.6.8 // indirect
google.golang.org/genproto v0.0.0-20250715232539-7130f93afb79 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250715232539-7130f93afb79 // indirect
- google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090 // indirect
+ google.golang.org/genproto/googleapis/rpc v0.0.0-20250929231259-57b25ae835d4 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
howett.net/plist v1.0.0 // indirect
diff --git a/go.sum b/go.sum
index c1151e853041d..ecc9506cbe700 100644
--- a/go.sum
+++ b/go.sum
@@ -184,8 +184,8 @@ cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZ
cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM=
cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
-cloud.google.com/go/compute/metadata v0.8.4 h1:oXMa1VMQBVCyewMIOm3WQsnVd9FbKBtm8reqWRaXnHQ=
-cloud.google.com/go/compute/metadata v0.8.4/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10=
+cloud.google.com/go/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdBtwLoEkH9Zs=
+cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10=
cloud.google.com/go/contactcenterinsights v1.3.0/go.mod h1:Eu2oemoePuEFc/xKFPjbTuPSj0fYJcPls9TFlPNnHHY=
cloud.google.com/go/contactcenterinsights v1.4.0/go.mod h1:L2YzkGbPsv+vMQMCADxJoT9YiTTnSEd6fEvCeHTYVck=
cloud.google.com/go/contactcenterinsights v1.6.0/go.mod h1:IIDlT6CLcDoyv79kDv8iWxMSTZhLxSCofVV5W6YFM/w=
@@ -2534,8 +2534,8 @@ google.golang.org/api v0.108.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/
google.golang.org/api v0.110.0/go.mod h1:7FC4Vvx1Mooxh8C5HWjzZHcavuS2f6pmJpZx60ca7iI=
google.golang.org/api v0.111.0/go.mod h1:qtFHvU9mhgTJegR31csQ+rwxyUTHOKFqCKWp1J0fdw0=
google.golang.org/api v0.114.0/go.mod h1:ifYI2ZsFK6/uGddGfAD5BMxlnkBqCmqHSDUVi45N5Yg=
-google.golang.org/api v0.250.0 h1:qvkwrf/raASj82UegU2RSDGWi/89WkLckn4LuO4lVXM=
-google.golang.org/api v0.250.0/go.mod h1:Y9Uup8bDLJJtMzJyQnu+rLRJLA0wn+wTtc6vTlOvfXo=
+google.golang.org/api v0.251.0 h1:6lea5nHRT8RUmpy9kkC2PJYnhnDAB13LqrLSVQlMIE8=
+google.golang.org/api v0.251.0/go.mod h1:Rwy0lPf/TD7+T2VhYcffCHhyyInyuxGjICxdfLqT7KI=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
@@ -2680,8 +2680,8 @@ google.golang.org/genproto v0.0.0-20250715232539-7130f93afb79 h1:Nt6z9UHqSlIdIGJ
google.golang.org/genproto v0.0.0-20250715232539-7130f93afb79/go.mod h1:kTmlBHMPqR5uCZPBvwa2B18mvubkjyY3CRLI0c6fj0s=
google.golang.org/genproto/googleapis/api v0.0.0-20250715232539-7130f93afb79 h1:iOye66xuaAK0WnkPuhQPUFy8eJcmwUXqGGP3om6IxX8=
google.golang.org/genproto/googleapis/api v0.0.0-20250715232539-7130f93afb79/go.mod h1:HKJDgKsFUnv5VAGeQjz8kxcgDP0HoE0iZNp0OdZNlhE=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090 h1:/OQuEa4YWtDt7uQWHd3q3sUMb+QOLQUg1xa8CEsRv5w=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090/go.mod h1:GmFNa4BdJZ2a8G+wCe9Bg3wwThLrJun751XstdJt5Og=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20250929231259-57b25ae835d4 h1:i8QOKZfYg6AbGVZzUAY3LrNWCKF8O6zFisU9Wl9RER4=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20250929231259-57b25ae835d4/go.mod h1:HSkG/KdJWusxU1F6CNrwNDjBMgisKxGnc5dAZfT0mjQ=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
From 29aa1cc57254adf3afb2a77fc8ed2ee7076ff6fd Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 1 Oct 2025 19:42:53 +0000
Subject: [PATCH 020/298] chore: bump tailwindcss from 3.4.17 to 3.4.18 in
/site (#20117)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
[//]: # (dependabot-start)
⚠️ **Dependabot is rebasing this PR** ⚠️
Rebasing might not happen immediately, so don't worry if this takes some
time.
Note: if you make any changes to this PR yourself, they will take
precedence over the rebase.
---
[//]: # (dependabot-end)
Bumps
[tailwindcss](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss)
from 3.4.17 to 3.4.18.
Release notes
Sourced from tailwindcss's
releases .
v3.4.18
Fixed
Improve support for raw supports-[…] queries in
arbitrary values (#13605 )
Fix require.cache error when loaded through a
TypeScript file in Node 22.18+ (#18665 )
Support import.meta.resolve(…) in configs for new
enough Node.js versions (#18938 )
Allow using newer versions of postcss-load-config for
better ESM and TypeScript PostCSS config support with the CLI (#18938 )
Remove irrelevant utility rules when matching important classes (#19030 )
Changelog
Sourced from tailwindcss's
changelog .
[3.4.18] - 2024-10-01
Fixed
Improve support for raw supports-[…] queries in
arbitrary values (#13605 )
Fix require.cache error when loaded through a
TypeScript file in Node 22.18+ (#18665 )
Support import.meta.resolve(…) in configs for new
enough Node.js versions (#18938 )
Allow using newer versions of postcss-load-config for
better ESM and TypeScript PostCSS config support with the CLI (#18938 )
Remove irrelevant utility rules when matching important classes (#19030 )
Commits
[](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
site/package.json | 2 +-
site/pnpm-lock.yaml | 192 +++++++++++++++++++++-----------------------
2 files changed, 93 insertions(+), 101 deletions(-)
diff --git a/site/package.json b/site/package.json
index 3a974c5b0348e..e90e860dd6a17 100644
--- a/site/package.json
+++ b/site/package.json
@@ -177,7 +177,7 @@
"ssh2": "1.17.0",
"storybook": "9.1.2",
"storybook-addon-remix-react-router": "5.0.0",
- "tailwindcss": "3.4.17",
+ "tailwindcss": "3.4.18",
"ts-proto": "1.164.0",
"typescript": "5.6.3",
"vite": "7.1.7",
diff --git a/site/pnpm-lock.yaml b/site/pnpm-lock.yaml
index 6fdcf50cfd5b3..e2fdf68962550 100644
--- a/site/pnpm-lock.yaml
+++ b/site/pnpm-lock.yaml
@@ -252,7 +252,7 @@ importers:
version: 2.6.0
tailwindcss-animate:
specifier: 1.0.7
- version: 1.0.7(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.3.38)(@types/node@20.17.16)(typescript@5.6.3)))
+ version: 1.0.7(tailwindcss@3.4.18(yaml@2.7.0))
tzdata:
specifier: 1.0.46
version: 1.0.46
@@ -283,7 +283,7 @@ importers:
version: 2.2.0
'@chromatic-com/storybook':
specifier: 4.1.0
- version: 4.1.0(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)))
+ version: 4.1.0(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@1.21.7)(yaml@2.7.0)))
'@octokit/types':
specifier: 12.3.0
version: 12.3.0
@@ -292,16 +292,16 @@ importers:
version: 1.50.1
'@storybook/addon-docs':
specifier: 9.1.2
- version: 9.1.2(@types/react@19.1.17)(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)))
+ version: 9.1.2(@types/react@19.1.17)(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@1.21.7)(yaml@2.7.0)))
'@storybook/addon-links':
specifier: 9.1.2
- version: 9.1.2(react@19.1.1)(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)))
+ version: 9.1.2(react@19.1.1)(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@1.21.7)(yaml@2.7.0)))
'@storybook/addon-themes':
specifier: 9.1.2
- version: 9.1.2(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)))
+ version: 9.1.2(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@1.21.7)(yaml@2.7.0)))
'@storybook/react-vite':
specifier: 9.1.2
- version: 9.1.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(rollup@4.52.3)(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)))(typescript@5.6.3)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0))
+ version: 9.1.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(rollup@4.52.3)(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@1.21.7)(yaml@2.7.0)))(typescript@5.6.3)(vite@7.1.7(@types/node@20.17.16)(jiti@1.21.7)(yaml@2.7.0))
'@swc/core':
specifier: 1.3.38
version: 1.3.38
@@ -310,7 +310,7 @@ importers:
version: 0.2.37(@swc/core@1.3.38)
'@tailwindcss/typography':
specifier: 0.5.16
- version: 0.5.16(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.3.38)(@types/node@20.17.16)(typescript@5.6.3)))
+ version: 0.5.16(tailwindcss@3.4.18(yaml@2.7.0))
'@testing-library/jest-dom':
specifier: 6.6.3
version: 6.6.3
@@ -379,7 +379,7 @@ importers:
version: 9.0.2
'@vitejs/plugin-react':
specifier: 5.0.4
- version: 5.0.4(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0))
+ version: 5.0.4(vite@7.1.7(@types/node@20.17.16)(jiti@1.21.7)(yaml@2.7.0))
autoprefixer:
specifier: 10.4.20
version: 10.4.20(postcss@8.5.1)
@@ -436,13 +436,13 @@ importers:
version: 1.17.0
storybook:
specifier: 9.1.2
- version: 9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0))
+ version: 9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@1.21.7)(yaml@2.7.0))
storybook-addon-remix-react-router:
specifier: 5.0.0
- version: 5.0.0(react-dom@19.1.1(react@19.1.1))(react-router@7.8.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react@19.1.1)(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)))
+ version: 5.0.0(react-dom@19.1.1(react@19.1.1))(react-router@7.8.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react@19.1.1)(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@1.21.7)(yaml@2.7.0)))
tailwindcss:
- specifier: 3.4.17
- version: 3.4.17(ts-node@10.9.2(@swc/core@1.3.38)(@types/node@20.17.16)(typescript@5.6.3))
+ specifier: 3.4.18
+ version: 3.4.18(yaml@2.7.0)
ts-proto:
specifier: 1.164.0
version: 1.164.0
@@ -451,10 +451,10 @@ importers:
version: 5.6.3
vite:
specifier: 7.1.7
- version: 7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)
+ version: 7.1.7(@types/node@20.17.16)(jiti@1.21.7)(yaml@2.7.0)
vite-plugin-checker:
specifier: 0.11.0
- version: 0.11.0(@biomejs/biome@2.2.0)(eslint@8.52.0)(optionator@0.9.3)(typescript@5.6.3)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0))
+ version: 0.11.0(@biomejs/biome@2.2.0)(eslint@8.52.0)(optionator@0.9.3)(typescript@5.6.3)(vite@7.1.7(@types/node@20.17.16)(jiti@1.21.7)(yaml@2.7.0))
packages:
@@ -1321,10 +1321,6 @@ packages:
'@jridgewell/gen-mapping@0.3.13':
resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==, tarball: https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz}
- '@jridgewell/gen-mapping@0.3.8':
- resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==, tarball: https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz}
- engines: {node: '>=6.0.0'}
-
'@jridgewell/remapping@2.3.5':
resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==, tarball: https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz}
@@ -1332,10 +1328,6 @@ packages:
resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==, tarball: https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz}
engines: {node: '>=6.0.0'}
- '@jridgewell/set-array@1.2.1':
- resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==, tarball: https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz}
- engines: {node: '>=6.0.0'}
-
'@jridgewell/sourcemap-codec@1.5.0':
resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==, tarball: https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz}
@@ -5451,8 +5443,8 @@ packages:
resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==, tarball: https://registry.npmjs.org/pify/-/pify-2.3.0.tgz}
engines: {node: '>=0.10.0'}
- pirates@4.0.6:
- resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==, tarball: https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz}
+ pirates@4.0.7:
+ resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==, tarball: https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz}
engines: {node: '>= 6'}
pkg-dir@4.2.0:
@@ -5479,22 +5471,28 @@ packages:
peerDependencies:
postcss: ^8.0.0
- postcss-js@4.0.1:
- resolution: {integrity: sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==, tarball: https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz}
+ postcss-js@4.1.0:
+ resolution: {integrity: sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==, tarball: https://registry.npmjs.org/postcss-js/-/postcss-js-4.1.0.tgz}
engines: {node: ^12 || ^14 || >= 16}
peerDependencies:
postcss: ^8.4.21
- postcss-load-config@4.0.2:
- resolution: {integrity: sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==, tarball: https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz}
- engines: {node: '>= 14'}
+ postcss-load-config@6.0.1:
+ resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==, tarball: https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz}
+ engines: {node: '>= 18'}
peerDependencies:
+ jiti: '>=1.21.0'
postcss: '>=8.0.9'
- ts-node: '>=9.0.0'
+ tsx: ^4.8.1
+ yaml: ^2.4.2
peerDependenciesMeta:
+ jiti:
+ optional: true
postcss:
optional: true
- ts-node:
+ tsx:
+ optional: true
+ yaml:
optional: true
postcss-nested@6.2.0:
@@ -6163,8 +6161,8 @@ packages:
peerDependencies:
tailwindcss: '>=3.0.0 || insiders'
- tailwindcss@3.4.17:
- resolution: {integrity: sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==, tarball: https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.17.tgz}
+ tailwindcss@3.4.18:
+ resolution: {integrity: sha512-6A2rnmW5xZMdw11LYjhcI5846rt9pbLSabY5XPxo+XWdxwZaFEn47Go4NzFiHu9sNNmr/kXivP1vStfvMaK1GQ==, tarball: https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.18.tgz}
engines: {node: '>=14.0.0'}
hasBin: true
@@ -7001,13 +6999,13 @@ snapshots:
'@types/tough-cookie': 4.0.5
tough-cookie: 4.1.4
- '@chromatic-com/storybook@4.1.0(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)))':
+ '@chromatic-com/storybook@4.1.0(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@1.21.7)(yaml@2.7.0)))':
dependencies:
'@neoconfetti/react': 1.0.0
chromatic: 12.2.0
filesize: 10.1.2
jsonfile: 6.1.0
- storybook: 9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0))
+ storybook: 9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@1.21.7)(yaml@2.7.0))
strip-ansi: 7.1.0
transitivePeerDependencies:
- '@chromatic-com/cypress'
@@ -7595,7 +7593,7 @@ snapshots:
jest-regex-util: 29.6.3
jest-util: 29.7.0
micromatch: 4.0.8
- pirates: 4.0.6
+ pirates: 4.0.7
slash: 3.0.0
write-file-atomic: 4.0.2
transitivePeerDependencies:
@@ -7619,12 +7617,12 @@ snapshots:
'@types/yargs': 17.0.33
chalk: 4.1.2
- '@joshwooding/vite-plugin-react-docgen-typescript@0.6.1(typescript@5.6.3)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0))':
+ '@joshwooding/vite-plugin-react-docgen-typescript@0.6.1(typescript@5.6.3)(vite@7.1.7(@types/node@20.17.16)(jiti@1.21.7)(yaml@2.7.0))':
dependencies:
glob: 10.4.5
magic-string: 0.30.17
react-docgen-typescript: 2.2.2(typescript@5.6.3)
- vite: 7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)
+ vite: 7.1.7(@types/node@20.17.16)(jiti@1.21.7)(yaml@2.7.0)
optionalDependencies:
typescript: 5.6.3
@@ -7633,12 +7631,6 @@ snapshots:
'@jridgewell/sourcemap-codec': 1.5.5
'@jridgewell/trace-mapping': 0.3.31
- '@jridgewell/gen-mapping@0.3.8':
- dependencies:
- '@jridgewell/set-array': 1.2.1
- '@jridgewell/sourcemap-codec': 1.5.0
- '@jridgewell/trace-mapping': 0.3.25
-
'@jridgewell/remapping@2.3.5':
dependencies:
'@jridgewell/gen-mapping': 0.3.13
@@ -7646,8 +7638,6 @@ snapshots:
'@jridgewell/resolve-uri@3.1.2': {}
- '@jridgewell/set-array@1.2.1': {}
-
'@jridgewell/sourcemap-codec@1.5.0': {}
'@jridgewell/sourcemap-codec@1.5.5': {}
@@ -7655,7 +7645,7 @@ snapshots:
'@jridgewell/trace-mapping@0.3.25':
dependencies:
'@jridgewell/resolve-uri': 3.1.2
- '@jridgewell/sourcemap-codec': 1.5.0
+ '@jridgewell/sourcemap-codec': 1.5.5
'@jridgewell/trace-mapping@0.3.31':
dependencies:
@@ -8775,41 +8765,41 @@ snapshots:
dependencies:
'@sinonjs/commons': 3.0.0
- '@storybook/addon-docs@9.1.2(@types/react@19.1.17)(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)))':
+ '@storybook/addon-docs@9.1.2(@types/react@19.1.17)(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@1.21.7)(yaml@2.7.0)))':
dependencies:
'@mdx-js/react': 3.0.1(@types/react@19.1.17)(react@19.1.1)
- '@storybook/csf-plugin': 9.1.2(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)))
+ '@storybook/csf-plugin': 9.1.2(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@1.21.7)(yaml@2.7.0)))
'@storybook/icons': 1.4.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- '@storybook/react-dom-shim': 9.1.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)))
+ '@storybook/react-dom-shim': 9.1.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@1.21.7)(yaml@2.7.0)))
react: 19.1.1
react-dom: 19.1.1(react@19.1.1)
- storybook: 9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0))
+ storybook: 9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@1.21.7)(yaml@2.7.0))
ts-dedent: 2.2.0
transitivePeerDependencies:
- '@types/react'
- '@storybook/addon-links@9.1.2(react@19.1.1)(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)))':
+ '@storybook/addon-links@9.1.2(react@19.1.1)(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@1.21.7)(yaml@2.7.0)))':
dependencies:
'@storybook/global': 5.0.0
- storybook: 9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0))
+ storybook: 9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@1.21.7)(yaml@2.7.0))
optionalDependencies:
react: 19.1.1
- '@storybook/addon-themes@9.1.2(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)))':
+ '@storybook/addon-themes@9.1.2(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@1.21.7)(yaml@2.7.0)))':
dependencies:
- storybook: 9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0))
+ storybook: 9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@1.21.7)(yaml@2.7.0))
ts-dedent: 2.2.0
- '@storybook/builder-vite@9.1.2(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)))(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0))':
+ '@storybook/builder-vite@9.1.2(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@1.21.7)(yaml@2.7.0)))(vite@7.1.7(@types/node@20.17.16)(jiti@1.21.7)(yaml@2.7.0))':
dependencies:
- '@storybook/csf-plugin': 9.1.2(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)))
- storybook: 9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0))
+ '@storybook/csf-plugin': 9.1.2(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@1.21.7)(yaml@2.7.0)))
+ storybook: 9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@1.21.7)(yaml@2.7.0))
ts-dedent: 2.2.0
- vite: 7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)
+ vite: 7.1.7(@types/node@20.17.16)(jiti@1.21.7)(yaml@2.7.0)
- '@storybook/csf-plugin@9.1.2(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)))':
+ '@storybook/csf-plugin@9.1.2(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@1.21.7)(yaml@2.7.0)))':
dependencies:
- storybook: 9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0))
+ storybook: 9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@1.21.7)(yaml@2.7.0))
unplugin: 1.5.0
'@storybook/global@5.0.0': {}
@@ -8819,39 +8809,39 @@ snapshots:
react: 19.1.1
react-dom: 19.1.1(react@19.1.1)
- '@storybook/react-dom-shim@9.1.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)))':
+ '@storybook/react-dom-shim@9.1.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@1.21.7)(yaml@2.7.0)))':
dependencies:
react: 19.1.1
react-dom: 19.1.1(react@19.1.1)
- storybook: 9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0))
+ storybook: 9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@1.21.7)(yaml@2.7.0))
- '@storybook/react-vite@9.1.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(rollup@4.52.3)(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)))(typescript@5.6.3)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0))':
+ '@storybook/react-vite@9.1.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(rollup@4.52.3)(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@1.21.7)(yaml@2.7.0)))(typescript@5.6.3)(vite@7.1.7(@types/node@20.17.16)(jiti@1.21.7)(yaml@2.7.0))':
dependencies:
- '@joshwooding/vite-plugin-react-docgen-typescript': 0.6.1(typescript@5.6.3)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0))
+ '@joshwooding/vite-plugin-react-docgen-typescript': 0.6.1(typescript@5.6.3)(vite@7.1.7(@types/node@20.17.16)(jiti@1.21.7)(yaml@2.7.0))
'@rollup/pluginutils': 5.0.5(rollup@4.52.3)
- '@storybook/builder-vite': 9.1.2(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)))(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0))
- '@storybook/react': 9.1.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)))(typescript@5.6.3)
+ '@storybook/builder-vite': 9.1.2(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@1.21.7)(yaml@2.7.0)))(vite@7.1.7(@types/node@20.17.16)(jiti@1.21.7)(yaml@2.7.0))
+ '@storybook/react': 9.1.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@1.21.7)(yaml@2.7.0)))(typescript@5.6.3)
find-up: 7.0.0
magic-string: 0.30.17
react: 19.1.1
react-docgen: 8.0.0
react-dom: 19.1.1(react@19.1.1)
resolve: 1.22.10
- storybook: 9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0))
+ storybook: 9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@1.21.7)(yaml@2.7.0))
tsconfig-paths: 4.2.0
- vite: 7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)
+ vite: 7.1.7(@types/node@20.17.16)(jiti@1.21.7)(yaml@2.7.0)
transitivePeerDependencies:
- rollup
- supports-color
- typescript
- '@storybook/react@9.1.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)))(typescript@5.6.3)':
+ '@storybook/react@9.1.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@1.21.7)(yaml@2.7.0)))(typescript@5.6.3)':
dependencies:
'@storybook/global': 5.0.0
- '@storybook/react-dom-shim': 9.1.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)))
+ '@storybook/react-dom-shim': 9.1.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@1.21.7)(yaml@2.7.0)))
react: 19.1.1
react-dom: 19.1.1(react@19.1.1)
- storybook: 9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0))
+ storybook: 9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@1.21.7)(yaml@2.7.0))
optionalDependencies:
typescript: 5.6.3
@@ -8907,13 +8897,13 @@ snapshots:
'@swc/counter': 0.1.3
jsonc-parser: 3.2.0
- '@tailwindcss/typography@0.5.16(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.3.38)(@types/node@20.17.16)(typescript@5.6.3)))':
+ '@tailwindcss/typography@0.5.16(tailwindcss@3.4.18(yaml@2.7.0))':
dependencies:
lodash.castarray: 4.4.0
lodash.isplainobject: 4.0.6
lodash.merge: 4.6.2
postcss-selector-parser: 6.0.10
- tailwindcss: 3.4.17(ts-node@10.9.2(@swc/core@1.3.38)(@types/node@20.17.16)(typescript@5.6.3))
+ tailwindcss: 3.4.18(yaml@2.7.0)
'@tanstack/query-core@5.77.0': {}
@@ -9294,7 +9284,7 @@ snapshots:
'@ungap/structured-clone@1.3.0': {}
- '@vitejs/plugin-react@5.0.4(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0))':
+ '@vitejs/plugin-react@5.0.4(vite@7.1.7(@types/node@20.17.16)(jiti@1.21.7)(yaml@2.7.0))':
dependencies:
'@babel/core': 7.28.4
'@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.4)
@@ -9302,7 +9292,7 @@ snapshots:
'@rolldown/pluginutils': 1.0.0-beta.38
'@types/babel__core': 7.20.5
react-refresh: 0.17.0
- vite: 7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)
+ vite: 7.1.7(@types/node@20.17.16)(jiti@1.21.7)(yaml@2.7.0)
transitivePeerDependencies:
- supports-color
@@ -9314,14 +9304,14 @@ snapshots:
chai: 5.2.1
tinyrainbow: 2.0.0
- '@vitest/mocker@3.2.4(msw@2.4.8(typescript@5.6.3))(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0))':
+ '@vitest/mocker@3.2.4(msw@2.4.8(typescript@5.6.3))(vite@7.1.7(@types/node@20.17.16)(jiti@1.21.7)(yaml@2.7.0))':
dependencies:
'@vitest/spy': 3.2.4
estree-walker: 3.0.3
magic-string: 0.30.17
optionalDependencies:
msw: 2.4.8(typescript@5.6.3)
- vite: 7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)
+ vite: 7.1.7(@types/node@20.17.16)(jiti@1.21.7)(yaml@2.7.0)
'@vitest/pretty-format@3.2.4':
dependencies:
@@ -12316,7 +12306,7 @@ snapshots:
pify@2.3.0: {}
- pirates@4.0.6: {}
+ pirates@4.0.7: {}
pkg-dir@4.2.0:
dependencies:
@@ -12339,18 +12329,18 @@ snapshots:
read-cache: 1.0.0
resolve: 1.22.10
- postcss-js@4.0.1(postcss@8.5.1):
+ postcss-js@4.1.0(postcss@8.5.1):
dependencies:
camelcase-css: 2.0.1
postcss: 8.5.1
- postcss-load-config@4.0.2(postcss@8.5.1)(ts-node@10.9.2(@swc/core@1.3.38)(@types/node@20.17.16)(typescript@5.6.3)):
+ postcss-load-config@6.0.1(jiti@1.21.7)(postcss@8.5.1)(yaml@2.7.0):
dependencies:
lilconfig: 3.1.3
- yaml: 2.7.0
optionalDependencies:
+ jiti: 1.21.7
postcss: 8.5.1
- ts-node: 10.9.2(@swc/core@1.3.38)(@types/node@20.17.16)(typescript@5.6.3)
+ yaml: 2.7.0
postcss-nested@6.2.0(postcss@8.5.1):
dependencies:
@@ -12995,24 +12985,24 @@ snapshots:
dependencies:
internal-slot: 1.0.6
- storybook-addon-remix-react-router@5.0.0(react-dom@19.1.1(react@19.1.1))(react-router@7.8.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react@19.1.1)(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0))):
+ storybook-addon-remix-react-router@5.0.0(react-dom@19.1.1(react@19.1.1))(react-router@7.8.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react@19.1.1)(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@1.21.7)(yaml@2.7.0))):
dependencies:
'@mjackson/form-data-parser': 0.4.0
compare-versions: 6.1.0
react-inspector: 6.0.2(react@19.1.1)
react-router: 7.8.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
- storybook: 9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0))
+ storybook: 9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@1.21.7)(yaml@2.7.0))
optionalDependencies:
react: 19.1.1
react-dom: 19.1.1(react@19.1.1)
- storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)):
+ storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@1.21.7)(yaml@2.7.0)):
dependencies:
'@storybook/global': 5.0.0
'@testing-library/jest-dom': 6.6.3
'@testing-library/user-event': 14.6.1(@testing-library/dom@10.4.0)
'@vitest/expect': 3.2.4
- '@vitest/mocker': 3.2.4(msw@2.4.8(typescript@5.6.3))(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0))
+ '@vitest/mocker': 3.2.4(msw@2.4.8(typescript@5.6.3))(vite@7.1.7(@types/node@20.17.16)(jiti@1.21.7)(yaml@2.7.0))
'@vitest/spy': 3.2.4
better-opn: 3.0.2
esbuild: 0.25.3
@@ -13104,12 +13094,12 @@ snapshots:
sucrase@3.35.0:
dependencies:
- '@jridgewell/gen-mapping': 0.3.8
+ '@jridgewell/gen-mapping': 0.3.13
commander: 4.1.1
glob: 10.4.5
lines-and-columns: 1.2.4
mz: 2.7.0
- pirates: 4.0.6
+ pirates: 4.0.7
ts-interface-checker: 0.1.13
supports-color@7.2.0:
@@ -13126,11 +13116,11 @@ snapshots:
tailwind-merge@2.6.0: {}
- tailwindcss-animate@1.0.7(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.3.38)(@types/node@20.17.16)(typescript@5.6.3))):
+ tailwindcss-animate@1.0.7(tailwindcss@3.4.18(yaml@2.7.0)):
dependencies:
- tailwindcss: 3.4.17(ts-node@10.9.2(@swc/core@1.3.38)(@types/node@20.17.16)(typescript@5.6.3))
+ tailwindcss: 3.4.18(yaml@2.7.0)
- tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.3.38)(@types/node@20.17.16)(typescript@5.6.3)):
+ tailwindcss@3.4.18(yaml@2.7.0):
dependencies:
'@alloc/quick-lru': 5.2.0
arg: 5.0.2
@@ -13148,14 +13138,15 @@ snapshots:
picocolors: 1.1.1
postcss: 8.5.1
postcss-import: 15.1.0(postcss@8.5.1)
- postcss-js: 4.0.1(postcss@8.5.1)
- postcss-load-config: 4.0.2(postcss@8.5.1)(ts-node@10.9.2(@swc/core@1.3.38)(@types/node@20.17.16)(typescript@5.6.3))
+ postcss-js: 4.1.0(postcss@8.5.1)
+ postcss-load-config: 6.0.1(jiti@1.21.7)(postcss@8.5.1)(yaml@2.7.0)
postcss-nested: 6.2.0(postcss@8.5.1)
postcss-selector-parser: 6.1.2
resolve: 1.22.10
sucrase: 3.35.0
transitivePeerDependencies:
- - ts-node
+ - tsx
+ - yaml
test-exclude@6.0.0:
dependencies:
@@ -13474,7 +13465,7 @@ snapshots:
d3-time: 3.1.0
d3-timer: 3.0.1
- vite-plugin-checker@0.11.0(@biomejs/biome@2.2.0)(eslint@8.52.0)(optionator@0.9.3)(typescript@5.6.3)(vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)):
+ vite-plugin-checker@0.11.0(@biomejs/biome@2.2.0)(eslint@8.52.0)(optionator@0.9.3)(typescript@5.6.3)(vite@7.1.7(@types/node@20.17.16)(jiti@1.21.7)(yaml@2.7.0)):
dependencies:
'@babel/code-frame': 7.27.1
chokidar: 4.0.3
@@ -13483,7 +13474,7 @@ snapshots:
picomatch: 4.0.3
tiny-invariant: 1.3.3
tinyglobby: 0.2.15
- vite: 7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0)
+ vite: 7.1.7(@types/node@20.17.16)(jiti@1.21.7)(yaml@2.7.0)
vscode-uri: 3.1.0
optionalDependencies:
'@biomejs/biome': 2.2.0
@@ -13491,7 +13482,7 @@ snapshots:
optionator: 0.9.3
typescript: 5.6.3
- vite@7.1.7(@types/node@20.17.16)(jiti@2.6.1)(yaml@2.7.0):
+ vite@7.1.7(@types/node@20.17.16)(jiti@1.21.7)(yaml@2.7.0):
dependencies:
esbuild: 0.25.10
fdir: 6.5.0(picomatch@4.0.3)
@@ -13502,7 +13493,7 @@ snapshots:
optionalDependencies:
'@types/node': 20.17.16
fsevents: 2.3.3
- jiti: 2.6.1
+ jiti: 1.21.7
yaml: 2.7.0
vscode-uri@3.1.0: {}
@@ -13609,7 +13600,8 @@ snapshots:
yaml@1.10.2: {}
- yaml@2.7.0: {}
+ yaml@2.7.0:
+ optional: true
yargs-parser@21.1.1: {}
From 4cabb9528ecd5ef5493b7f8b53185cb79afc18fe Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 1 Oct 2025 19:46:34 +0000
Subject: [PATCH 021/298] chore: bump @types/lodash from 4.17.15 to 4.17.20 in
/site (#20122)
Bumps
[@types/lodash](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/lodash)
from 4.17.15 to 4.17.20.
Commits
[](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
site/package.json | 2 +-
site/pnpm-lock.yaml | 10 +++++-----
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/site/package.json b/site/package.json
index e90e860dd6a17..bb2257d277c85 100644
--- a/site/package.json
+++ b/site/package.json
@@ -143,7 +143,7 @@
"@types/file-saver": "2.0.7",
"@types/humanize-duration": "3.27.4",
"@types/jest": "29.5.14",
- "@types/lodash": "4.17.15",
+ "@types/lodash": "4.17.20",
"@types/node": "20.17.16",
"@types/react": "19.1.17",
"@types/react-color": "3.0.13",
diff --git a/site/pnpm-lock.yaml b/site/pnpm-lock.yaml
index e2fdf68962550..20a93530895b6 100644
--- a/site/pnpm-lock.yaml
+++ b/site/pnpm-lock.yaml
@@ -339,8 +339,8 @@ importers:
specifier: 29.5.14
version: 29.5.14
'@types/lodash':
- specifier: 4.17.15
- version: 4.17.15
+ specifier: 4.17.20
+ version: 4.17.20
'@types/node':
specifier: 20.17.16
version: 20.17.16
@@ -2916,8 +2916,8 @@ packages:
'@types/jsdom@20.0.1':
resolution: {integrity: sha512-d0r18sZPmMQr1eG35u12FZfhIXNrnsPU/g5wvRKCUf/tOGilKKwYMYGqh33BNR6ba+2gkHw1EUiHoN3mn7E5IQ==, tarball: https://registry.npmjs.org/@types/jsdom/-/jsdom-20.0.1.tgz}
- '@types/lodash@4.17.15':
- resolution: {integrity: sha512-w/P33JFeySuhN6JLkysYUK2gEmy9kHHFN7E8ro0tkfmlDOgxBDzWEZ/J8cWA+fHqFevpswDTFZnDx+R9lbL6xw==, tarball: https://registry.npmjs.org/@types/lodash/-/lodash-4.17.15.tgz}
+ '@types/lodash@4.17.20':
+ resolution: {integrity: sha512-H3MHACvFUEiujabxhaI/ImO6gUrd8oOurg7LQtS7mbwIXA/cUqWrvBsaeJ23aZEPk1TAYkurjfMbSELfoCXlGA==, tarball: https://registry.npmjs.org/@types/lodash/-/lodash-4.17.20.tgz}
'@types/mdast@4.0.3':
resolution: {integrity: sha512-LsjtqsyF+d2/yFOYaN22dHZI1Cpwkrj+g06G8+qtUKlhovPW89YhqSnfKtMbkgmEtYpH2gydRNULd6y8mciAFg==, tarball: https://registry.npmjs.org/@types/mdast/-/mdast-4.0.3.tgz}
@@ -9145,7 +9145,7 @@ snapshots:
'@types/tough-cookie': 4.0.2
parse5: 7.1.2
- '@types/lodash@4.17.15': {}
+ '@types/lodash@4.17.20': {}
'@types/mdast@4.0.3':
dependencies:
From cf8d7665e3feeae41082d7004466be182692ae35 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 1 Oct 2025 19:50:53 +0000
Subject: [PATCH 022/298] chore: bump chroma-js from 2.4.2 to 2.6.0 in /site
(#20123)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Bumps [chroma-js](https://github.com/gka/chroma.js) from 2.4.2 to 2.6.0.
Release notes
Sourced from chroma-js's
releases .
v2.6.0
What's Changed
Full Changelog : https://github.com/gka/chroma.js/compare/v2.5.0...v2.6.0
v2.5.0
What's Changed
New Contributors
Full Changelog : https://github.com/gka/chroma.js/compare/v2.3.0...v2.5.0
Changelog
Sourced from chroma-js's
changelog .
2.6.0
2.5.0
refactored code base to ES6 modules
2.4.0
add support for Oklab and Oklch color spaces
2.3.0
use binom of degree n in chroma.bezier
2.2.0
use Delta e2000 for chroma.deltaE #269
2.0.3
hsl2rgb will, like other x2rgb conversions now set the default alpha
to 1
2.0.2
use a more mangle-safe check for Color class constructor to fix
issues with uglifyjs and terser
2.0.1
added chroma.valid() for checking if a color can be
parsed by chroma.js
2.0.0
chroma.js has been ported from CoffeeScript to ES6! This means you
can now import parts of chroma in your projects!
changed HCG input space from [0..360,0..100,0..100] to
[0..360,0..1,0..1] (to be in line with HSL)
added new object unpacking (e.g. hsl2rgb({h,s,l}))
changed default interpolation to lrgb in
mix/interpolate and average.
if colors can't be parsed correctly, chroma will now throw Errors
instead of silently failing with console.errors
1.4.1
chroma.scale() now interprets null as NaN and returns
the fallback color. Before it had interpreted null as
0
added scale.nodata() to allow customizing the
previously hard-coded fallback (aka "no data") color
#cccccc
1.4.0
color.hex() now automatically sets the mode to 'rgba' if the colors
alpha channel is < 1. so
chroma('rgba(255,0,0,.5)').hex() will now return
"#ff000080" instead of
"#ff0000". if this is not what you want, you must
explicitly set the mode to rgb using
.hex("rgb").
bugfix in chroma.average in LRGB mode (#187 )
chroma.scale now also works with just one color (#180 )
1.3.5
1.3.4
passing null as mode in scale.colors will return chroma
objects
1.3.3
... (truncated)
Commits
[](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
site/package.json | 2 +-
site/pnpm-lock.yaml | 10 +++++-----
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/site/package.json b/site/package.json
index bb2257d277c85..71b790967dcfe 100644
--- a/site/package.json
+++ b/site/package.json
@@ -76,7 +76,7 @@
"@xterm/xterm": "5.5.0",
"ansi-to-html": "0.7.2",
"axios": "1.12.0",
- "chroma-js": "2.4.2",
+ "chroma-js": "2.6.0",
"class-variance-authority": "0.7.1",
"clsx": "2.1.1",
"cmdk": "1.0.4",
diff --git a/site/pnpm-lock.yaml b/site/pnpm-lock.yaml
index 20a93530895b6..1b81ecdeb3be7 100644
--- a/site/pnpm-lock.yaml
+++ b/site/pnpm-lock.yaml
@@ -143,8 +143,8 @@ importers:
specifier: 1.12.0
version: 1.12.0
chroma-js:
- specifier: 2.4.2
- version: 2.4.2
+ specifier: 2.6.0
+ version: 2.6.0
class-variance-authority:
specifier: 0.7.1
version: 0.7.1
@@ -3459,8 +3459,8 @@ packages:
resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==, tarball: https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz}
engines: {node: '>= 14.16.0'}
- chroma-js@2.4.2:
- resolution: {integrity: sha512-U9eDw6+wt7V8z5NncY2jJfZa+hUH8XEj8FQHgFJTrUFnJfXYf4Ml4adI2vXZOjqRDpFWtYVWypDfZwnJ+HIR4A==, tarball: https://registry.npmjs.org/chroma-js/-/chroma-js-2.4.2.tgz}
+ chroma-js@2.6.0:
+ resolution: {integrity: sha512-BLHvCB9s8Z1EV4ethr6xnkl/P2YRFOGqfgvuMG/MyCbZPrTA+NeiByY6XvgF0zP4/2deU2CXnWyMa3zu1LqQ3A==, tarball: https://registry.npmjs.org/chroma-js/-/chroma-js-2.6.0.tgz}
chromatic@11.29.0:
resolution: {integrity: sha512-yisBlntp9hHVj19lIQdpTlcYIXuU9H/DbFuu6tyWHmj6hWT2EtukCCcxYXL78XdQt1vm2GfIrtgtKpj/Rzmo4A==, tarball: https://registry.npmjs.org/chromatic/-/chromatic-11.29.0.tgz}
@@ -9727,7 +9727,7 @@ snapshots:
dependencies:
readdirp: 4.1.2
- chroma-js@2.4.2: {}
+ chroma-js@2.6.0: {}
chromatic@11.29.0: {}
From b92a0f428c7574781e8c90f658b1dcc6d7728f05 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 1 Oct 2025 19:51:24 +0000
Subject: [PATCH 023/298] chore: bump autoprefixer from 10.4.20 to 10.4.21 in
/site (#20124)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Bumps [autoprefixer](https://github.com/postcss/autoprefixer) from
10.4.20 to 10.4.21.
Release notes
Sourced from autoprefixer's
releases .
10.4.21
Changelog
Sourced from autoprefixer's
changelog .
10.4.21
Commits
[](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
site/package.json | 2 +-
site/pnpm-lock.yaml | 75 +++++++++++----------------------------------
2 files changed, 19 insertions(+), 58 deletions(-)
diff --git a/site/package.json b/site/package.json
index 71b790967dcfe..bba60a5ada644 100644
--- a/site/package.json
+++ b/site/package.json
@@ -157,7 +157,7 @@
"@types/ua-parser-js": "0.7.36",
"@types/uuid": "9.0.2",
"@vitejs/plugin-react": "5.0.4",
- "autoprefixer": "10.4.20",
+ "autoprefixer": "10.4.21",
"chromatic": "11.29.0",
"dpdm": "3.14.0",
"express": "4.21.2",
diff --git a/site/pnpm-lock.yaml b/site/pnpm-lock.yaml
index 1b81ecdeb3be7..3a9307d25701b 100644
--- a/site/pnpm-lock.yaml
+++ b/site/pnpm-lock.yaml
@@ -381,8 +381,8 @@ importers:
specifier: 5.0.4
version: 5.0.4(vite@7.1.7(@types/node@20.17.16)(jiti@1.21.7)(yaml@2.7.0))
autoprefixer:
- specifier: 10.4.20
- version: 10.4.20(postcss@8.5.1)
+ specifier: 10.4.21
+ version: 10.4.21(postcss@8.5.1)
chromatic:
specifier: 11.29.0
version: 11.29.0
@@ -3257,8 +3257,8 @@ packages:
asynckit@0.4.0:
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==, tarball: https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz}
- autoprefixer@10.4.20:
- resolution: {integrity: sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==, tarball: https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.20.tgz}
+ autoprefixer@10.4.21:
+ resolution: {integrity: sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==, tarball: https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.21.tgz}
engines: {node: ^10 || ^12 || >=14}
hasBin: true
peerDependencies:
@@ -3309,8 +3309,8 @@ packages:
base64-js@1.5.1:
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==, tarball: https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz}
- baseline-browser-mapping@2.8.9:
- resolution: {integrity: sha512-hY/u2lxLrbecMEWSB0IpGzGyDyeoMFQhCvZd2jGFSE5I17Fh01sYUBPCJtkWERw7zrac9+cIghxm/ytJa2X8iA==, tarball: https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.9.tgz}
+ baseline-browser-mapping@2.8.10:
+ resolution: {integrity: sha512-uLfgBi+7IBNay8ECBO2mVMGZAc1VgZWEChxm4lv+TobGdG82LnXMjuNGo/BSSZZL4UmkWhxEHP2f5ziLNwGWMA==, tarball: https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.10.tgz}
hasBin: true
bcrypt-pbkdf@1.0.2:
@@ -3338,13 +3338,8 @@ packages:
resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==, tarball: https://registry.npmjs.org/braces/-/braces-3.0.3.tgz}
engines: {node: '>=8'}
- browserslist@4.24.2:
- resolution: {integrity: sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==, tarball: https://registry.npmjs.org/browserslist/-/browserslist-4.24.2.tgz}
- engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
- hasBin: true
-
- browserslist@4.26.2:
- resolution: {integrity: sha512-ECFzp6uFOSB+dcZ5BK/IBaGWssbSYBHvuMeMt3MMFyhI0Z8SqGgEkBLARgpRH3hutIgPVsALcMwbDrJqPxQ65A==, tarball: https://registry.npmjs.org/browserslist/-/browserslist-4.26.2.tgz}
+ browserslist@4.26.3:
+ resolution: {integrity: sha512-lAUU+02RFBuCKQPj/P6NgjlbCnLBMp4UtgTx7vNHd3XSIJF87s9a5rA3aH2yw3GS9DqZAUbOtZdCCiZeVRqt0w==, tarball: https://registry.npmjs.org/browserslist/-/browserslist-4.26.3.tgz}
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
hasBin: true
@@ -3397,9 +3392,6 @@ packages:
resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==, tarball: https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz}
engines: {node: '>=10'}
- caniuse-lite@1.0.30001717:
- resolution: {integrity: sha512-auPpttCq6BDEG8ZAuHJIplGw6GODhjw+/11e7IjpnYCxZcW/ONgPs0KVBJ0d1bY3e2+7PRe5RCLyP+PfwVgkYw==, tarball: https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001717.tgz}
-
caniuse-lite@1.0.30001746:
resolution: {integrity: sha512-eA7Ys/DGw+pnkWWSE/id29f2IcPHVoE8wxtvE5JdvD2V28VTDPy1yEeo11Guz0sJ4ZeGRcm3uaTcAqK1LXaphA==, tarball: https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001746.tgz}
@@ -3868,9 +3860,6 @@ packages:
electron-to-chromium@1.5.228:
resolution: {integrity: sha512-nxkiyuqAn4MJ1QbobwqJILiDtu/jk14hEAWaMiJmNPh1Z+jqoFlBFZjdXwLWGeVSeu9hGLg6+2G9yJaW8rBIFA==, tarball: https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.228.tgz}
- electron-to-chromium@1.5.50:
- resolution: {integrity: sha512-eMVObiUQ2LdgeO1F/ySTXsvqvxb6ZH2zPGaMYsWzRDdOddUa77tdmI0ltg+L16UpbWdhPmuF3wIQYyQq65WfZw==, tarball: https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.50.tgz}
-
emittery@0.13.1:
resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==, tarball: https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz}
engines: {node: '>=12'}
@@ -5250,9 +5239,6 @@ packages:
node-int64@0.4.0:
resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==, tarball: https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz}
- node-releases@2.0.18:
- resolution: {integrity: sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==, tarball: https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz}
-
node-releases@2.0.21:
resolution: {integrity: sha512-5b0pgg78U3hwXkCM8Z9b2FJdPZlr9Psr9V2gQPESdGHqbntyFJKFW4r5TeWGFzafGY3hzs1JC62VEQMbl1JFkw==, tarball: https://registry.npmjs.org/node-releases/-/node-releases-2.0.21.tgz}
@@ -6383,12 +6369,6 @@ packages:
unplugin@1.5.0:
resolution: {integrity: sha512-9ZdRwbh/4gcm1JTOkp9lAkIDrtOyOxgHmY7cjuwI8L/2RTikMcVG25GsZwNAgRuap3iDw2jeq7eoqtAsz5rW3A==, tarball: https://registry.npmjs.org/unplugin/-/unplugin-1.5.0.tgz}
- update-browserslist-db@1.1.1:
- resolution: {integrity: sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==, tarball: https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz}
- hasBin: true
- peerDependencies:
- browserslist: '>= 4.21.0'
-
update-browserslist-db@1.1.3:
resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==, tarball: https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz}
hasBin: true
@@ -6771,7 +6751,7 @@ snapshots:
dependencies:
'@babel/compat-data': 7.28.4
'@babel/helper-validator-option': 7.27.1
- browserslist: 4.26.2
+ browserslist: 4.26.3
lru-cache: 5.1.1
semver: 7.7.2
@@ -9470,10 +9450,10 @@ snapshots:
asynckit@0.4.0: {}
- autoprefixer@10.4.20(postcss@8.5.1):
+ autoprefixer@10.4.21(postcss@8.5.1):
dependencies:
- browserslist: 4.24.2
- caniuse-lite: 1.0.30001717
+ browserslist: 4.26.3
+ caniuse-lite: 1.0.30001746
fraction.js: 4.3.7
normalize-range: 0.1.2
picocolors: 1.1.1
@@ -9559,7 +9539,7 @@ snapshots:
base64-js@1.5.1: {}
- baseline-browser-mapping@2.8.9: {}
+ baseline-browser-mapping@2.8.10: {}
bcrypt-pbkdf@1.0.2:
dependencies:
@@ -9603,20 +9583,13 @@ snapshots:
dependencies:
fill-range: 7.1.1
- browserslist@4.24.2:
- dependencies:
- caniuse-lite: 1.0.30001717
- electron-to-chromium: 1.5.50
- node-releases: 2.0.18
- update-browserslist-db: 1.1.1(browserslist@4.24.2)
-
- browserslist@4.26.2:
+ browserslist@4.26.3:
dependencies:
- baseline-browser-mapping: 2.8.9
+ baseline-browser-mapping: 2.8.10
caniuse-lite: 1.0.30001746
electron-to-chromium: 1.5.228
node-releases: 2.0.21
- update-browserslist-db: 1.1.3(browserslist@4.26.2)
+ update-browserslist-db: 1.1.3(browserslist@4.26.3)
bser@2.1.1:
dependencies:
@@ -9667,8 +9640,6 @@ snapshots:
camelcase@6.3.0: {}
- caniuse-lite@1.0.30001717: {}
-
caniuse-lite@1.0.30001746: {}
case-anything@2.1.13: {}
@@ -10079,8 +10050,6 @@ snapshots:
electron-to-chromium@1.5.228: {}
- electron-to-chromium@1.5.50: {}
-
emittery@0.13.1: {}
emoji-mart@5.6.0: {}
@@ -12099,8 +12068,6 @@ snapshots:
node-int64@0.4.0: {}
- node-releases@2.0.18: {}
-
node-releases@2.0.21: {}
normalize-path@3.0.0: {}
@@ -13361,15 +13328,9 @@ snapshots:
webpack-sources: 3.2.3
webpack-virtual-modules: 0.5.0
- update-browserslist-db@1.1.1(browserslist@4.24.2):
- dependencies:
- browserslist: 4.24.2
- escalade: 3.2.0
- picocolors: 1.1.1
-
- update-browserslist-db@1.1.3(browserslist@4.26.2):
+ update-browserslist-db@1.1.3(browserslist@4.26.3):
dependencies:
- browserslist: 4.26.2
+ browserslist: 4.26.3
escalade: 3.2.0
picocolors: 1.1.1
From e89c7cdcef17e1437e96b5c11b67e04177301b21 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 1 Oct 2025 19:51:43 +0000
Subject: [PATCH 024/298] chore: bump @fontsource/ibm-plex-mono from 5.1.1 to
5.2.7 in /site (#20127)
Bumps
[@fontsource/ibm-plex-mono](https://github.com/fontsource/font-files/tree/HEAD/fonts/google/ibm-plex-mono)
from 5.1.1 to 5.2.7.
Commits
[](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
site/package.json | 2 +-
site/pnpm-lock.yaml | 10 +++++-----
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/site/package.json b/site/package.json
index bba60a5ada644..cfa5718b11637 100644
--- a/site/package.json
+++ b/site/package.json
@@ -43,7 +43,7 @@
"@emotion/styled": "11.14.1",
"@fontsource-variable/inter": "5.1.1",
"@fontsource/fira-code": "5.2.7",
- "@fontsource/ibm-plex-mono": "5.1.1",
+ "@fontsource/ibm-plex-mono": "5.2.7",
"@fontsource/jetbrains-mono": "5.2.5",
"@fontsource/source-code-pro": "5.2.5",
"@monaco-editor/react": "4.7.0",
diff --git a/site/pnpm-lock.yaml b/site/pnpm-lock.yaml
index 3a9307d25701b..acc08688be6eb 100644
--- a/site/pnpm-lock.yaml
+++ b/site/pnpm-lock.yaml
@@ -44,8 +44,8 @@ importers:
specifier: 5.2.7
version: 5.2.7
'@fontsource/ibm-plex-mono':
- specifier: 5.1.1
- version: 5.1.1
+ specifier: 5.2.7
+ version: 5.2.7
'@fontsource/jetbrains-mono':
specifier: 5.2.5
version: 5.2.5
@@ -1165,8 +1165,8 @@ packages:
'@fontsource/fira-code@5.2.7':
resolution: {integrity: sha512-tnB9NNund9TwIym8/7DMJe573nlPEQb+fKUV5GL8TBYXjIhDvL0D7mgmNVNQUPhXp+R7RylQeiBdkA4EbOHPGQ==, tarball: https://registry.npmjs.org/@fontsource/fira-code/-/fira-code-5.2.7.tgz}
- '@fontsource/ibm-plex-mono@5.1.1':
- resolution: {integrity: sha512-1aayqPe/ZkD3MlvqpmOHecfA3f2B8g+fAEkgvcCd3lkPP0pS1T0xG5Zmn2EsJQqr1JURtugPUH+5NqvKyfFZMQ==, tarball: https://registry.npmjs.org/@fontsource/ibm-plex-mono/-/ibm-plex-mono-5.1.1.tgz}
+ '@fontsource/ibm-plex-mono@5.2.7':
+ resolution: {integrity: sha512-MKAb8qV+CaiMQn2B0dIi1OV3565NYzp3WN5b4oT6LTkk+F0jR6j0ZN+5BKJiIhffDC3rtBULsYZE65+0018z9w==, tarball: https://registry.npmjs.org/@fontsource/ibm-plex-mono/-/ibm-plex-mono-5.2.7.tgz}
'@fontsource/jetbrains-mono@5.2.5':
resolution: {integrity: sha512-TPZ9b/uq38RMdrlZZkl0RwN8Ju9JxuqMETrw76pUQFbGtE1QbwQaNsLlnUrACNNBNbd0NZRXiJJSkC8ajPgbew==, tarball: https://registry.npmjs.org/@fontsource/jetbrains-mono/-/jetbrains-mono-5.2.5.tgz}
@@ -7330,7 +7330,7 @@ snapshots:
'@fontsource/fira-code@5.2.7': {}
- '@fontsource/ibm-plex-mono@5.1.1': {}
+ '@fontsource/ibm-plex-mono@5.2.7': {}
'@fontsource/jetbrains-mono@5.2.5': {}
From b68c648476f623ef5935865a0bcb1067a782239a Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 1 Oct 2025 19:51:57 +0000
Subject: [PATCH 025/298] chore: bump react-resizable-panels from 3.0.3 to
3.0.6 in /site (#20125)
Bumps
[react-resizable-panels](https://github.com/bvaughn/react-resizable-panels)
from 3.0.3 to 3.0.6.
Release notes
Sourced from react-resizable-panels's
releases .
3.0.6
#517 :
Fixed Firefox bug that caused resizing to be interrupted unexpected
3.0.5
#512 :
Fixed size precision regression from 2.0.17
3.0.4
#503 :
Support custom cursors
Commits
[](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
site/package.json | 2 +-
site/pnpm-lock.yaml | 10 +++++-----
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/site/package.json b/site/package.json
index cfa5718b11637..d3c30a7a4dce7 100644
--- a/site/package.json
+++ b/site/package.json
@@ -101,7 +101,7 @@
"react-dom": "19.1.1",
"react-markdown": "9.1.0",
"react-query": "npm:@tanstack/react-query@5.77.0",
- "react-resizable-panels": "3.0.3",
+ "react-resizable-panels": "3.0.6",
"react-router": "7.8.0",
"react-syntax-highlighter": "15.6.1",
"react-textarea-autosize": "8.5.9",
diff --git a/site/pnpm-lock.yaml b/site/pnpm-lock.yaml
index acc08688be6eb..7d88aef2ab9b7 100644
--- a/site/pnpm-lock.yaml
+++ b/site/pnpm-lock.yaml
@@ -218,8 +218,8 @@ importers:
specifier: npm:@tanstack/react-query@5.77.0
version: '@tanstack/react-query@5.77.0(react@19.1.1)'
react-resizable-panels:
- specifier: 3.0.3
- version: 3.0.3(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ specifier: 3.0.6
+ version: 3.0.6(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
react-router:
specifier: 7.8.0
version: 7.8.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
@@ -5685,8 +5685,8 @@ packages:
'@types/react':
optional: true
- react-resizable-panels@3.0.3:
- resolution: {integrity: sha512-7HA8THVBHTzhDK4ON0tvlGXyMAJN1zBeRpuyyremSikgYh2ku6ltD7tsGQOcXx4NKPrZtYCm/5CBr+dkruTGQw==, tarball: https://registry.npmjs.org/react-resizable-panels/-/react-resizable-panels-3.0.3.tgz}
+ react-resizable-panels@3.0.6:
+ resolution: {integrity: sha512-b3qKHQ3MLqOgSS+FRYKapNkJZf5EQzuf6+RLiq1/IlTHw99YrZ2NJZLk4hQIzTnnIkRg2LUqyVinu6YWWpUYew==, tarball: https://registry.npmjs.org/react-resizable-panels/-/react-resizable-panels-3.0.6.tgz}
peerDependencies:
react: ^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc
react-dom: ^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc
@@ -12544,7 +12544,7 @@ snapshots:
optionalDependencies:
'@types/react': 19.1.17
- react-resizable-panels@3.0.3(react-dom@19.1.1(react@19.1.1))(react@19.1.1):
+ react-resizable-panels@3.0.6(react-dom@19.1.1(react@19.1.1))(react@19.1.1):
dependencies:
react: 19.1.1
react-dom: 19.1.1(react@19.1.1)
From f05ccfe525763e8abbd3baf64375c6cc60cd9b56 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 1 Oct 2025 19:57:46 +0000
Subject: [PATCH 026/298] chore: bump postcss from 8.5.1 to 8.5.6 in /site
(#20113)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Bumps [postcss](https://github.com/postcss/postcss) from 8.5.1 to 8.5.6.
Release notes
Sourced from postcss's
releases .
8.5.6
Fixed ContainerWithChildren type discriminating (by @Goodwine ).
8.5.5
Fixed package.json→exports compatibility
with some tools (by @JounQin ).
8.5.4
8.5.3
8.5.2
Changelog
Sourced from postcss's
changelog .
8.5.6
Fixed ContainerWithChildren type discriminating (by @Goodwine ).
8.5.5
Fixed package.json→exports compatibility
with some tools (by @JounQin ).
8.5.4
8.5.3
8.5.2
Commits
[](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
site/package.json | 2 +-
site/pnpm-lock.yaml | 53 +++++++++++++++------------------------------
2 files changed, 19 insertions(+), 36 deletions(-)
diff --git a/site/package.json b/site/package.json
index d3c30a7a4dce7..500bc7d41d539 100644
--- a/site/package.json
+++ b/site/package.json
@@ -170,7 +170,7 @@
"jest_workaround": "0.1.14",
"knip": "5.64.1",
"msw": "2.4.8",
- "postcss": "8.5.1",
+ "postcss": "8.5.6",
"protobufjs": "7.4.0",
"rollup-plugin-visualizer": "5.14.0",
"rxjs": "7.8.1",
diff --git a/site/pnpm-lock.yaml b/site/pnpm-lock.yaml
index 7d88aef2ab9b7..072598486cbab 100644
--- a/site/pnpm-lock.yaml
+++ b/site/pnpm-lock.yaml
@@ -382,7 +382,7 @@ importers:
version: 5.0.4(vite@7.1.7(@types/node@20.17.16)(jiti@1.21.7)(yaml@2.7.0))
autoprefixer:
specifier: 10.4.21
- version: 10.4.21(postcss@8.5.1)
+ version: 10.4.21(postcss@8.5.6)
chromatic:
specifier: 11.29.0
version: 11.29.0
@@ -420,8 +420,8 @@ importers:
specifier: 2.4.8
version: 2.4.8(typescript@5.6.3)
postcss:
- specifier: 8.5.1
- version: 8.5.1
+ specifier: 8.5.6
+ version: 8.5.6
protobufjs:
specifier: 7.4.0
version: 7.4.0
@@ -5219,11 +5219,6 @@ packages:
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
hasBin: true
- nanoid@3.3.8:
- resolution: {integrity: sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==, tarball: https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz}
- engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
- hasBin: true
-
napi-postinstall@0.3.3:
resolution: {integrity: sha512-uTp172LLXSxuSYHv/kou+f6KW3SMppU9ivthaVTXian9sOt3XM/zHYHpRZiLgQoxeWfYUnslNWQHF1+G71xcow==, tarball: https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.3.3.tgz}
engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0}
@@ -5498,10 +5493,6 @@ packages:
postcss-value-parser@4.2.0:
resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==, tarball: https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz}
- postcss@8.5.1:
- resolution: {integrity: sha512-6oz2beyjc5VMn/KV1pPw8fliQkhBXrVn1Z3TVyqZxU8kZpzEKhBdmCFqI6ZbmGtamQvQGuU1sgPTk8ZrXDD7jQ==, tarball: https://registry.npmjs.org/postcss/-/postcss-8.5.1.tgz}
- engines: {node: ^10 || ^12 || >=14}
-
postcss@8.5.6:
resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==, tarball: https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz}
engines: {node: ^10 || ^12 || >=14}
@@ -9450,14 +9441,14 @@ snapshots:
asynckit@0.4.0: {}
- autoprefixer@10.4.21(postcss@8.5.1):
+ autoprefixer@10.4.21(postcss@8.5.6):
dependencies:
browserslist: 4.26.3
caniuse-lite: 1.0.30001746
fraction.js: 4.3.7
normalize-range: 0.1.2
picocolors: 1.1.1
- postcss: 8.5.1
+ postcss: 8.5.6
postcss-value-parser: 4.2.0
available-typed-arrays@1.0.7:
@@ -12058,8 +12049,6 @@ snapshots:
nanoid@3.3.11: {}
- nanoid@3.3.8: {}
-
napi-postinstall@0.3.3: {}
natural-compare@1.4.0: {}
@@ -12289,29 +12278,29 @@ snapshots:
possible-typed-array-names@1.0.0: {}
- postcss-import@15.1.0(postcss@8.5.1):
+ postcss-import@15.1.0(postcss@8.5.6):
dependencies:
- postcss: 8.5.1
+ postcss: 8.5.6
postcss-value-parser: 4.2.0
read-cache: 1.0.0
resolve: 1.22.10
- postcss-js@4.1.0(postcss@8.5.1):
+ postcss-js@4.1.0(postcss@8.5.6):
dependencies:
camelcase-css: 2.0.1
- postcss: 8.5.1
+ postcss: 8.5.6
- postcss-load-config@6.0.1(jiti@1.21.7)(postcss@8.5.1)(yaml@2.7.0):
+ postcss-load-config@6.0.1(jiti@1.21.7)(postcss@8.5.6)(yaml@2.7.0):
dependencies:
lilconfig: 3.1.3
optionalDependencies:
jiti: 1.21.7
- postcss: 8.5.1
+ postcss: 8.5.6
yaml: 2.7.0
- postcss-nested@6.2.0(postcss@8.5.1):
+ postcss-nested@6.2.0(postcss@8.5.6):
dependencies:
- postcss: 8.5.1
+ postcss: 8.5.6
postcss-selector-parser: 6.1.2
postcss-selector-parser@6.0.10:
@@ -12326,12 +12315,6 @@ snapshots:
postcss-value-parser@4.2.0: {}
- postcss@8.5.1:
- dependencies:
- nanoid: 3.3.8
- picocolors: 1.1.1
- source-map-js: 1.2.1
-
postcss@8.5.6:
dependencies:
nanoid: 3.3.11
@@ -13103,11 +13086,11 @@ snapshots:
normalize-path: 3.0.0
object-hash: 3.0.0
picocolors: 1.1.1
- postcss: 8.5.1
- postcss-import: 15.1.0(postcss@8.5.1)
- postcss-js: 4.1.0(postcss@8.5.1)
- postcss-load-config: 6.0.1(jiti@1.21.7)(postcss@8.5.1)(yaml@2.7.0)
- postcss-nested: 6.2.0(postcss@8.5.1)
+ postcss: 8.5.6
+ postcss-import: 15.1.0(postcss@8.5.6)
+ postcss-js: 4.1.0(postcss@8.5.6)
+ postcss-load-config: 6.0.1(jiti@1.21.7)(postcss@8.5.6)(yaml@2.7.0)
+ postcss-nested: 6.2.0(postcss@8.5.6)
postcss-selector-parser: 6.1.2
resolve: 1.22.10
sucrase: 3.35.0
From 0993dcfef7e80d442aa2f76aaedaf97187e5e594 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 1 Oct 2025 19:57:55 +0000
Subject: [PATCH 027/298] chore: bump monaco-editor from 0.52.2 to 0.53.0 in
/site (#20120)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Bumps [monaco-editor](https://github.com/microsoft/monaco-editor) from
0.52.2 to 0.53.0.
Release notes
Sourced from monaco-editor's
releases .
v0.53.0
Changes:
#4980 :
sets node version
#4979 :
v0.53.0
#4978 :
updates changelog
#4975 :
Fixes worker sandbox problems
#4969 :
Implements language selection
#4967 :
adds amd and firefox/webkit to smoke tests
#4966 :
Fixes AMD web worker loading
#4965 :
Updates monaco-editor-core dependency & fixes basic-languages amd
file
#4964 :
Run npm run playwright-install
#4963 :
Hediet/b/successful mosquito
#4962 :
Fixes node version
#4950 :
ESM Progress
#4913 :
Bump webpack-dev-server from 4.10.0 to 5.2.1 in /samples
#4915 :
Add snowflake sql keywords
#4895 :
Fixes microsoft/monaco-editor#4799
#4742 :
Update webpack plugin to support module workers
#4824 :
Fix CI and website workflows
#4747 :
Engineering - add dependsOn field
#4734 :
Bump express from 4.19.2 to 4.21.1 in /website
#4616 :
Bump requirejs from 2.3.6 to 2.3.7
#4668 :
Bump micromatch from 4.0.5 to 4.0.8 in /website
#4726 :
Bump http-proxy-middleware from 2.0.6 to 2.0.7 in /website
#4595 :
Bump ws from 8.8.1 to 8.18.0 in /samples
#4697 :
Bump body-parser and express in /samples
#4696 :
Bump rollup from 2.79.1 to 2.79.2
This list of changes was auto
generated .
v0.53.0-rc2
No release notes provided.
v0.53.0-dev-20250908
No release notes provided.
v0.53.0-dev-20250907
No release notes provided.
v0.53.0-dev-20250906
Changes:
... (truncated)
Changelog
Sourced from monaco-editor's
changelog .
[0.53.0]
:warning: This release deprecates the AMD build and ships with
significant changes of the AMD build. The AMD build will still be
shipped for a while, but we don't offer support for it anymore. Please
migrate to the ESM build.
New Features
Next Edit Suggestion support.
Scroll On Middle Click
Edit Context Support
Breaking Changes
Internal AMD modules are no longer accessible. Accessing internal
AMD modules was never supported. While this is still possible in the ESM
build, we don't encourage this usage pattern.
The browser-script-editor
scenario for unbundled synchronous script import and editor creation
no longer works. Instead, a the ESM build should be used with a bundler,
such as vite or webpack.
Custom AMD workers don't work anymore out of the box.
[0.52.0]
Comment added inside of IModelContentChangedEvent
[0.51.0]
New fields IEditorOptions.placeholder and
IEditorOptions.compactMode
New fields IGotoLocationOptions.multipleTests and
IGotoLocationOptions.alternativeTestsCommand
New field IInlineEditOptions.backgroundColoring
New experimental field
IEditorOptions.experimental.useTrueInlineView
New options CommentThreadRevealOptions for
comments
Contributions to monaco-editor:
[0.50.0]
New field
IEditorMinimapOptions.sectionHeaderLetterSpacing
New field IOverlayWidgetPosition.stackOridinal
New field EmitOutput.diagnostics
New event IOverlayWidget.onDidLayout
New events ICodeEditor.onBeginUpdate and
ICodeEditor.onEndUpdate
HoverVerbosityRequest.action ->
HoverVerbosityRequest.verbosityDelta
MultiDocumentHighlightProvider.selector changed from
LanguageFilter to LanguageSelector
New optional parameters in getEmitOutput:
emitOnlyDtsFiles and forceDtsEmit
Contributions to monaco-editor:
... (truncated)
Commits
[](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
site/package.json | 2 +-
site/pnpm-lock.yaml | 23 +++++++++++++++--------
2 files changed, 16 insertions(+), 9 deletions(-)
diff --git a/site/package.json b/site/package.json
index 500bc7d41d539..660227b1373a1 100644
--- a/site/package.json
+++ b/site/package.json
@@ -92,7 +92,7 @@
"jszip": "3.10.1",
"lodash": "4.17.21",
"lucide-react": "0.474.0",
- "monaco-editor": "0.52.2",
+ "monaco-editor": "0.53.0",
"pretty-bytes": "6.1.1",
"react": "19.1.1",
"react-color": "2.19.3",
diff --git a/site/pnpm-lock.yaml b/site/pnpm-lock.yaml
index 072598486cbab..068bc1959648e 100644
--- a/site/pnpm-lock.yaml
+++ b/site/pnpm-lock.yaml
@@ -54,7 +54,7 @@ importers:
version: 5.2.5
'@monaco-editor/react':
specifier: 4.7.0
- version: 4.7.0(monaco-editor@0.52.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ version: 4.7.0(monaco-editor@0.53.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
'@mui/icons-material':
specifier: 5.18.0
version: 5.18.0(@mui/material@5.18.0(@emotion/react@11.14.0(@types/react@19.1.17)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.17)(react@19.1.1))(@types/react@19.1.17)(react@19.1.1))(@types/react@19.1.17)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@types/react@19.1.17)(react@19.1.1)
@@ -191,8 +191,8 @@ importers:
specifier: 0.474.0
version: 0.474.0(react@19.1.1)
monaco-editor:
- specifier: 0.52.2
- version: 0.52.2
+ specifier: 0.53.0
+ version: 0.53.0
pretty-bytes:
specifier: 6.1.1
version: 6.1.1
@@ -3031,6 +3031,9 @@ packages:
'@types/tough-cookie@4.0.5':
resolution: {integrity: sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==, tarball: https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz}
+ '@types/trusted-types@1.0.6':
+ resolution: {integrity: sha512-230RC8sFeHoT6sSUlRO6a8cAnclO06eeiq1QDfiv2FGCLWFvvERWgwIQD4FWqD9A69BN7Lzee4OXwoMVnnsWDw==, tarball: https://registry.npmjs.org/@types/trusted-types/-/trusted-types-1.0.6.tgz}
+
'@types/ua-parser-js@0.7.36':
resolution: {integrity: sha512-N1rW+njavs70y2cApeIw1vLMYXRwfBy+7trgavGuuTfOd7j1Yh7QTRc/yqsPl6ncokt72ZXuxEU0PiCp9bSwNQ==, tarball: https://registry.npmjs.org/@types/ua-parser-js/-/ua-parser-js-0.7.36.tgz}
@@ -5182,8 +5185,8 @@ packages:
resolution: {integrity: sha512-qxBgB7Qa2sEQgHFjj0dSigq7fX4k6Saisd5Nelwp2q8mlbAFh5dHV9JTTlF8viYJLSSWgMCZFUom8PJcMNBoJw==, tarball: https://registry.npmjs.org/mock-socket/-/mock-socket-9.3.1.tgz}
engines: {node: '>= 8'}
- monaco-editor@0.52.2:
- resolution: {integrity: sha512-GEQWEZmfkOGLdd3XK8ryrfWz3AIP8YymVXiPHEdewrUq7mh0qrKrfHLNCXcbB6sTnMLnOZ3ztSiKcciFUkIJwQ==, tarball: https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.52.2.tgz}
+ monaco-editor@0.53.0:
+ resolution: {integrity: sha512-0WNThgC6CMWNXXBxTbaYYcunj08iB5rnx4/G56UOPeL9UVIUGGHA1GR0EWIh9Ebabj7NpCRawQ5b0hfN1jQmYQ==, tarball: https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.53.0.tgz}
moo-color@1.0.3:
resolution: {integrity: sha512-i/+ZKXMDf6aqYtBhuOcej71YSlbjT3wCO/4H1j8rPvxDJEifdwgg5MaFyu6iYAT8GBZJg2z0dkgK4YMzvURALQ==, tarball: https://registry.npmjs.org/moo-color/-/moo-color-1.0.3.tgz}
@@ -7651,10 +7654,10 @@ snapshots:
dependencies:
state-local: 1.0.7
- '@monaco-editor/react@4.7.0(monaco-editor@0.52.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
+ '@monaco-editor/react@4.7.0(monaco-editor@0.53.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
dependencies:
'@monaco-editor/loader': 1.5.0
- monaco-editor: 0.52.2
+ monaco-editor: 0.53.0
react: 19.1.1
react-dom: 19.1.1(react@19.1.1)
@@ -9229,6 +9232,8 @@ snapshots:
'@types/tough-cookie@4.0.5': {}
+ '@types/trusted-types@1.0.6': {}
+
'@types/ua-parser-js@0.7.36': {}
'@types/unist@2.0.11': {}
@@ -12004,7 +12009,9 @@ snapshots:
mock-socket@9.3.1: {}
- monaco-editor@0.52.2: {}
+ monaco-editor@0.53.0:
+ dependencies:
+ '@types/trusted-types': 1.0.6
moo-color@1.0.3:
dependencies:
From ebcfae27a2b6cca88a10d37a21f0e1b5b8f90b78 Mon Sep 17 00:00:00 2001
From: Asher
Date: Wed, 1 Oct 2025 13:39:45 -0800
Subject: [PATCH 028/298] feat: add task create, list, status, and delete MCP
tools (#19901)
---
coderd/database/dbfake/dbfake.go | 27 +++
codersdk/toolsdk/toolsdk.go | 253 +++++++++++++++++++++-
codersdk/toolsdk/toolsdk_test.go | 356 +++++++++++++++++++++++++++++++
3 files changed, 633 insertions(+), 3 deletions(-)
diff --git a/coderd/database/dbfake/dbfake.go b/coderd/database/dbfake/dbfake.go
index 6d99005fb3334..a4742a09fff6c 100644
--- a/coderd/database/dbfake/dbfake.go
+++ b/coderd/database/dbfake/dbfake.go
@@ -24,6 +24,7 @@ import (
"github.com/coder/coder/v2/coderd/rbac"
"github.com/coder/coder/v2/coderd/telemetry"
"github.com/coder/coder/v2/coderd/wspubsub"
+ "github.com/coder/coder/v2/codersdk"
"github.com/coder/coder/v2/provisionersdk"
sdkproto "github.com/coder/coder/v2/provisionersdk/proto"
)
@@ -55,6 +56,7 @@ type WorkspaceBuildBuilder struct {
params []database.WorkspaceBuildParameter
agentToken string
dispo workspaceBuildDisposition
+ taskAppID uuid.UUID
}
type workspaceBuildDisposition struct {
@@ -117,6 +119,23 @@ func (b WorkspaceBuildBuilder) WithAgent(mutations ...func([]*sdkproto.Agent) []
return b
}
+func (b WorkspaceBuildBuilder) WithTask() WorkspaceBuildBuilder {
+ //nolint: revive // returns modified struct
+ b.taskAppID = uuid.New()
+ return b.Params(database.WorkspaceBuildParameter{
+ Name: codersdk.AITaskPromptParameterName,
+ Value: "list me",
+ }).WithAgent(func(a []*sdkproto.Agent) []*sdkproto.Agent {
+ a[0].Apps = []*sdkproto.App{
+ {
+ Id: b.taskAppID.String(),
+ Slug: "vcode",
+ },
+ }
+ return a
+ })
+}
+
func (b WorkspaceBuildBuilder) Starting() WorkspaceBuildBuilder {
//nolint: revive // returns modified struct
b.dispo.starting = true
@@ -134,6 +153,14 @@ func (b WorkspaceBuildBuilder) Do() WorkspaceResponse {
b.seed.ID = uuid.New()
b.seed.JobID = jobID
+ if b.taskAppID != uuid.Nil {
+ b.seed.HasAITask = sql.NullBool{
+ Bool: true,
+ Valid: true,
+ }
+ b.seed.AITaskSidebarAppID = uuid.NullUUID{UUID: b.taskAppID, Valid: true}
+ }
+
resp := WorkspaceResponse{
AgentToken: b.agentToken,
}
diff --git a/codersdk/toolsdk/toolsdk.go b/codersdk/toolsdk/toolsdk.go
index acc7a9b10292a..63e17c2f039cd 100644
--- a/codersdk/toolsdk/toolsdk.go
+++ b/codersdk/toolsdk/toolsdk.go
@@ -50,6 +50,10 @@ const (
ToolNameWorkspaceEditFile = "coder_workspace_edit_file"
ToolNameWorkspaceEditFiles = "coder_workspace_edit_files"
ToolNameWorkspacePortForward = "coder_workspace_port_forward"
+ ToolNameCreateTask = "coder_create_task"
+ ToolNameDeleteTask = "coder_delete_task"
+ ToolNameListTasks = "coder_list_tasks"
+ ToolNameGetTaskStatus = "coder_get_task_status"
)
func NewDeps(client *codersdk.Client, opts ...func(*Deps)) (Deps, error) {
@@ -223,6 +227,10 @@ var All = []GenericTool{
WorkspaceEditFile.Generic(),
WorkspaceEditFiles.Generic(),
WorkspacePortForward.Generic(),
+ CreateTask.Generic(),
+ DeleteTask.Generic(),
+ ListTasks.Generic(),
+ GetTaskStatus.Generic(),
}
type ReportTaskArgs struct {
@@ -344,7 +352,7 @@ is provisioned correctly and the agent can connect to the control plane.
Properties: map[string]any{
"user": map[string]any{
"type": "string",
- "description": "Username or ID of the user to create the workspace for. Use the `me` keyword to create a workspace for the authenticated user.",
+ "description": userDescription("create a workspace"),
},
"template_version_id": map[string]any{
"type": "string",
@@ -1393,8 +1401,6 @@ type WorkspaceLSResponse struct {
Contents []WorkspaceLSFile `json:"contents"`
}
-const workspaceDescription = "The workspace name in the format [owner/]workspace[.agent]. If an owner is not specified, the authenticated user is used."
-
var WorkspaceLS = Tool[WorkspaceLSArgs, WorkspaceLSResponse]{
Tool: aisdk.Tool{
Name: ToolNameWorkspaceLS,
@@ -1750,6 +1756,237 @@ var WorkspacePortForward = Tool[WorkspacePortForwardArgs, WorkspacePortForwardRe
},
}
+type CreateTaskArgs struct {
+ Input string `json:"input"`
+ TemplateVersionID string `json:"template_version_id"`
+ TemplateVersionPresetID string `json:"template_version_preset_id"`
+ User string `json:"user"`
+}
+
+var CreateTask = Tool[CreateTaskArgs, codersdk.Task]{
+ Tool: aisdk.Tool{
+ Name: ToolNameCreateTask,
+ Description: `Create a task.`,
+ Schema: aisdk.Schema{
+ Properties: map[string]any{
+ "input": map[string]any{
+ "type": "string",
+ "description": "Input/prompt for the task.",
+ },
+ "template_version_id": map[string]any{
+ "type": "string",
+ "description": "ID of the template version to create the task from.",
+ },
+ "template_version_preset_id": map[string]any{
+ "type": "string",
+ "description": "Optional ID of the template version preset to create the task from.",
+ },
+ "user": map[string]any{
+ "type": "string",
+ "description": userDescription("create a task"),
+ },
+ },
+ Required: []string{"input", "template_version_id"},
+ },
+ },
+ UserClientOptional: true,
+ Handler: func(ctx context.Context, deps Deps, args CreateTaskArgs) (codersdk.Task, error) {
+ if args.Input == "" {
+ return codersdk.Task{}, xerrors.New("input is required")
+ }
+
+ tvID, err := uuid.Parse(args.TemplateVersionID)
+ if err != nil {
+ return codersdk.Task{}, xerrors.New("template_version_id must be a valid UUID")
+ }
+
+ var tvPresetID uuid.UUID
+ if args.TemplateVersionPresetID != "" {
+ tvPresetID, err = uuid.Parse(args.TemplateVersionPresetID)
+ if err != nil {
+ return codersdk.Task{}, xerrors.New("template_version_preset_id must be a valid UUID")
+ }
+ }
+
+ if args.User == "" {
+ args.User = codersdk.Me
+ }
+
+ expClient := codersdk.NewExperimentalClient(deps.coderClient)
+ task, err := expClient.CreateTask(ctx, args.User, codersdk.CreateTaskRequest{
+ Input: args.Input,
+ TemplateVersionID: tvID,
+ TemplateVersionPresetID: tvPresetID,
+ })
+ if err != nil {
+ return codersdk.Task{}, xerrors.Errorf("create task: %w", err)
+ }
+
+ return task, nil
+ },
+}
+
+type DeleteTaskArgs struct {
+ TaskID string `json:"task_id"`
+}
+
+var DeleteTask = Tool[DeleteTaskArgs, codersdk.Response]{
+ Tool: aisdk.Tool{
+ Name: ToolNameDeleteTask,
+ Description: `Delete a task.`,
+ Schema: aisdk.Schema{
+ Properties: map[string]any{
+ "task_id": map[string]any{
+ "type": "string",
+ "description": taskIDDescription("delete"),
+ },
+ },
+ Required: []string{"task_id"},
+ },
+ },
+ UserClientOptional: true,
+ Handler: func(ctx context.Context, deps Deps, args DeleteTaskArgs) (codersdk.Response, error) {
+ if args.TaskID == "" {
+ return codersdk.Response{}, xerrors.New("task_id is required")
+ }
+
+ expClient := codersdk.NewExperimentalClient(deps.coderClient)
+
+ var owner string
+ id, err := uuid.Parse(args.TaskID)
+ if err == nil {
+ task, err := expClient.TaskByID(ctx, id)
+ if err != nil {
+ return codersdk.Response{}, xerrors.Errorf("get task %q: %w", args.TaskID, err)
+ }
+ owner = task.OwnerName
+ } else {
+ ws, err := normalizedNamedWorkspace(ctx, deps.coderClient, args.TaskID)
+ if err != nil {
+ return codersdk.Response{}, xerrors.Errorf("get task workspace %q: %w", args.TaskID, err)
+ }
+ owner = ws.OwnerName
+ id = ws.ID
+ }
+
+ err = expClient.DeleteTask(ctx, owner, id)
+ if err != nil {
+ return codersdk.Response{}, xerrors.Errorf("delete task: %w", err)
+ }
+
+ return codersdk.Response{
+ Message: "Task deleted successfully",
+ }, nil
+ },
+}
+
+type ListTasksArgs struct {
+ Status string `json:"status"`
+ User string `json:"user"`
+}
+
+type ListTasksResponse struct {
+ Tasks []codersdk.Task `json:"tasks"`
+}
+
+var ListTasks = Tool[ListTasksArgs, ListTasksResponse]{
+ Tool: aisdk.Tool{
+ Name: ToolNameListTasks,
+ Description: `List tasks.`,
+ Schema: aisdk.Schema{
+ Properties: map[string]any{
+ "status": map[string]any{
+ "type": "string",
+ "description": "Optional filter by task status.",
+ },
+ "user": map[string]any{
+ "type": "string",
+ "description": userDescription("list tasks"),
+ },
+ },
+ Required: []string{},
+ },
+ },
+ UserClientOptional: true,
+ Handler: func(ctx context.Context, deps Deps, args ListTasksArgs) (ListTasksResponse, error) {
+ if args.User == "" {
+ args.User = codersdk.Me
+ }
+
+ expClient := codersdk.NewExperimentalClient(deps.coderClient)
+ tasks, err := expClient.Tasks(ctx, &codersdk.TasksFilter{
+ Owner: args.User,
+ Status: args.Status,
+ })
+ if err != nil {
+ return ListTasksResponse{}, xerrors.Errorf("list tasks: %w", err)
+ }
+
+ return ListTasksResponse{
+ Tasks: tasks,
+ }, nil
+ },
+}
+
+type GetTaskStatusArgs struct {
+ TaskID string `json:"task_id"`
+}
+
+type GetTaskStatusResponse struct {
+ Status codersdk.WorkspaceStatus `json:"status"`
+ State *codersdk.TaskStateEntry `json:"state"`
+}
+
+var GetTaskStatus = Tool[GetTaskStatusArgs, GetTaskStatusResponse]{
+ Tool: aisdk.Tool{
+ Name: ToolNameGetTaskStatus,
+ Description: `Get the status of a task.`,
+ Schema: aisdk.Schema{
+ Properties: map[string]any{
+ "task_id": map[string]any{
+ "type": "string",
+ "description": taskIDDescription("get"),
+ },
+ },
+ Required: []string{"task_id"},
+ },
+ },
+ UserClientOptional: true,
+ Handler: func(ctx context.Context, deps Deps, args GetTaskStatusArgs) (GetTaskStatusResponse, error) {
+ if args.TaskID == "" {
+ return GetTaskStatusResponse{}, xerrors.New("task_id is required")
+ }
+
+ expClient := codersdk.NewExperimentalClient(deps.coderClient)
+
+ id, err := uuid.Parse(args.TaskID)
+ if err != nil {
+ ws, err := normalizedNamedWorkspace(ctx, deps.coderClient, args.TaskID)
+ if err != nil {
+ return GetTaskStatusResponse{}, xerrors.Errorf("get task workspace %q: %w", args.TaskID, err)
+ }
+ id = ws.ID
+ }
+
+ task, err := expClient.TaskByID(ctx, id)
+ if err != nil {
+ return GetTaskStatusResponse{}, xerrors.Errorf("get task %q: %w", args.TaskID, err)
+ }
+
+ return GetTaskStatusResponse{
+ Status: task.Status,
+ State: task.CurrentState,
+ }, nil
+ },
+}
+
+// normalizedNamedWorkspace normalizes the workspace name before getting the
+// workspace by name.
+func normalizedNamedWorkspace(ctx context.Context, client *codersdk.Client, name string) (codersdk.Workspace, error) {
+ // Maybe namedWorkspace should itself call NormalizeWorkspaceInput?
+ return namedWorkspace(ctx, client, NormalizeWorkspaceInput(name))
+}
+
// NormalizeWorkspaceInput converts workspace name input to standard format.
// Handles the following input formats:
// - workspace → workspace
@@ -1810,3 +2047,13 @@ func newAgentConn(ctx context.Context, client *codersdk.Client, workspace string
}
return conn, nil
}
+
+const workspaceDescription = "The workspace name in the format [owner/]workspace[.agent]. If an owner is not specified, the authenticated user is used."
+
+func taskIDDescription(action string) string {
+ return fmt.Sprintf("ID or workspace identifier in the format [owner/]workspace[.agent] for the task to %s. If an owner is not specified, the authenticated user is used.", action)
+}
+
+func userDescription(action string) string {
+ return fmt.Sprintf("Username or ID of the user for which to %s. Omit or use the `me` keyword to %s for the authenticated user.", action, action)
+}
diff --git a/codersdk/toolsdk/toolsdk_test.go b/codersdk/toolsdk/toolsdk_test.go
index f89f22e0089d7..8e0cc09fff25d 100644
--- a/codersdk/toolsdk/toolsdk_test.go
+++ b/codersdk/toolsdk/toolsdk_test.go
@@ -2,6 +2,7 @@ package toolsdk_test
import (
"context"
+ "database/sql"
"encoding/json"
"fmt"
"os"
@@ -791,6 +792,361 @@ func TestTools(t *testing.T) {
})
}
})
+
+ t.Run("WorkspaceCreateTask", func(t *testing.T) {
+ t.Parallel()
+
+ presetID := uuid.New()
+ // nolint:gocritic // This is in a test package and does not end up in the build
+ aiTV := dbfake.TemplateVersion(t, store).Seed(database.TemplateVersion{
+ OrganizationID: owner.OrganizationID,
+ CreatedBy: member.ID,
+ HasAITask: sql.NullBool{
+ Bool: true,
+ Valid: true,
+ },
+ }).Preset(database.TemplateVersionPreset{
+ ID: presetID,
+ DesiredInstances: sql.NullInt32{
+ Int32: 1,
+ Valid: true,
+ },
+ }).Do()
+
+ tests := []struct {
+ name string
+ args toolsdk.CreateTaskArgs
+ error string
+ }{
+ {
+ name: "OK",
+ args: toolsdk.CreateTaskArgs{
+ TemplateVersionID: aiTV.TemplateVersion.ID.String(),
+ Input: "do a barrel roll",
+ User: "me",
+ },
+ },
+ {
+ name: "NoUser",
+ args: toolsdk.CreateTaskArgs{
+ TemplateVersionID: aiTV.TemplateVersion.ID.String(),
+ Input: "do another barrel roll",
+ },
+ },
+ {
+ name: "NoInput",
+ args: toolsdk.CreateTaskArgs{
+ TemplateVersionID: aiTV.TemplateVersion.ID.String(),
+ },
+ error: "input is required",
+ },
+ {
+ name: "NotTaskTemplate",
+ args: toolsdk.CreateTaskArgs{
+ TemplateVersionID: r.TemplateVersion.ID.String(),
+ Input: "do yet another barrel roll",
+ },
+ error: "Template does not have required parameter \"AI Prompt\"",
+ },
+ {
+ name: "WithPreset",
+ args: toolsdk.CreateTaskArgs{
+ TemplateVersionID: r.TemplateVersion.ID.String(),
+ TemplateVersionPresetID: presetID.String(),
+ Input: "not enough barrel rolls",
+ },
+ error: "Template does not have required parameter \"AI Prompt\"",
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ t.Parallel()
+
+ tb, err := toolsdk.NewDeps(memberClient)
+ require.NoError(t, err)
+
+ _, err = testTool(t, toolsdk.CreateTask, tb, tt.args)
+ if tt.error != "" {
+ require.Error(t, err)
+ require.ErrorContains(t, err, tt.error)
+ } else {
+ require.NoError(t, err)
+ }
+ })
+ }
+ })
+
+ t.Run("WorkspaceDeleteTask", func(t *testing.T) {
+ t.Parallel()
+
+ // nolint:gocritic // This is in a test package and does not end up in the build
+ aiTV := dbfake.TemplateVersion(t, store).Seed(database.TemplateVersion{
+ OrganizationID: owner.OrganizationID,
+ CreatedBy: member.ID,
+ HasAITask: sql.NullBool{
+ Bool: true,
+ Valid: true,
+ },
+ }).Do()
+
+ // nolint:gocritic // This is in a test package and does not end up in the build
+ ws1 := dbfake.WorkspaceBuild(t, store, database.WorkspaceTable{
+ Name: "delete-task-workspace-1",
+ OrganizationID: owner.OrganizationID,
+ OwnerID: member.ID,
+ TemplateID: aiTV.Template.ID,
+ }).WithTask().Do()
+
+ // nolint:gocritic // This is in a test package and does not end up in the build
+ _ = dbfake.WorkspaceBuild(t, store, database.WorkspaceTable{
+ Name: "delete-task-workspace-2",
+ OrganizationID: owner.OrganizationID,
+ OwnerID: member.ID,
+ TemplateID: aiTV.Template.ID,
+ }).WithTask().Do()
+
+ tests := []struct {
+ name string
+ args toolsdk.DeleteTaskArgs
+ error string
+ }{
+ {
+ name: "ByUUID",
+ args: toolsdk.DeleteTaskArgs{
+ TaskID: ws1.Workspace.ID.String(),
+ },
+ },
+ {
+ name: "ByWorkspaceIdentifier",
+ args: toolsdk.DeleteTaskArgs{
+ TaskID: "delete-task-workspace-2",
+ },
+ },
+ {
+ name: "NoID",
+ args: toolsdk.DeleteTaskArgs{},
+ error: "task_id is required",
+ },
+ {
+ name: "NoTaskByID",
+ args: toolsdk.DeleteTaskArgs{
+ TaskID: uuid.New().String(),
+ },
+ error: "Resource not found",
+ },
+ {
+ name: "NoTaskByWorkspaceIdentifier",
+ args: toolsdk.DeleteTaskArgs{
+ TaskID: "non-existent",
+ },
+ error: "Resource not found",
+ },
+ {
+ name: "ExistsButNotATask",
+ args: toolsdk.DeleteTaskArgs{
+ TaskID: r.Workspace.ID.String(),
+ },
+ error: "Resource not found",
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ t.Parallel()
+
+ tb, err := toolsdk.NewDeps(memberClient)
+ require.NoError(t, err)
+
+ _, err = testTool(t, toolsdk.DeleteTask, tb, tt.args)
+ if tt.error != "" {
+ require.Error(t, err)
+ require.ErrorContains(t, err, tt.error)
+ } else {
+ require.NoError(t, err)
+ }
+ })
+ }
+ })
+
+ t.Run("WorkspaceListTasks", func(t *testing.T) {
+ t.Parallel()
+
+ taskClient, taskUser := coderdtest.CreateAnotherUserMutators(t, client, owner.OrganizationID, nil)
+
+ // nolint:gocritic // This is in a test package and does not end up in the build
+ aiTV := dbfake.TemplateVersion(t, store).Seed(database.TemplateVersion{
+ OrganizationID: owner.OrganizationID,
+ CreatedBy: owner.UserID,
+ HasAITask: sql.NullBool{
+ Bool: true,
+ Valid: true,
+ },
+ }).Do()
+
+ // This task should not show up since listing is user-scoped.
+ // nolint:gocritic // This is in a test package and does not end up in the build
+ _ = dbfake.WorkspaceBuild(t, store, database.WorkspaceTable{
+ Name: "list-task-workspace-member",
+ OrganizationID: owner.OrganizationID,
+ OwnerID: member.ID,
+ TemplateID: aiTV.Template.ID,
+ }).WithTask().Do()
+
+ // These tasks should show up.
+ for i := range 5 {
+ // nolint:gocritic // This is in a test package and does not end up in the build
+ var transition database.WorkspaceTransition
+ if i == 0 {
+ // nolint:gocritic // This is in a test package and does not end up in the build
+ transition = database.WorkspaceTransitionStop
+ }
+ // nolint:gocritic // This is in a test package and does not end up in the build
+ _ = dbfake.WorkspaceBuild(t, store, database.WorkspaceTable{
+ Name: fmt.Sprintf("list-task-workspace-%d", i),
+ OrganizationID: owner.OrganizationID,
+ OwnerID: taskUser.ID,
+ TemplateID: aiTV.Template.ID,
+ }).Seed(database.WorkspaceBuild{Transition: transition}).WithTask().Do()
+ }
+
+ tests := []struct {
+ name string
+ args toolsdk.ListTasksArgs
+ expected []string
+ error string
+ }{
+ {
+ name: "ListAllOwned",
+ args: toolsdk.ListTasksArgs{},
+ expected: []string{
+ "list-task-workspace-0",
+ "list-task-workspace-1",
+ "list-task-workspace-2",
+ "list-task-workspace-3",
+ "list-task-workspace-4",
+ },
+ },
+ {
+ name: "ListFiltered",
+ args: toolsdk.ListTasksArgs{
+ Status: "stopped",
+ },
+ expected: []string{
+ "list-task-workspace-0",
+ },
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ t.Parallel()
+
+ tb, err := toolsdk.NewDeps(taskClient)
+ require.NoError(t, err)
+
+ res, err := testTool(t, toolsdk.ListTasks, tb, tt.args)
+ if tt.error != "" {
+ require.Error(t, err)
+ require.ErrorContains(t, err, tt.error)
+ } else {
+ require.NoError(t, err)
+ require.Len(t, res.Tasks, len(tt.expected))
+ for _, task := range res.Tasks {
+ require.Contains(t, tt.expected, task.Name)
+ }
+ }
+ })
+ }
+ })
+
+ t.Run("WorkspaceGetTask", func(t *testing.T) {
+ t.Parallel()
+
+ // nolint:gocritic // This is in a test package and does not end up in the build
+ aiTV := dbfake.TemplateVersion(t, store).Seed(database.TemplateVersion{
+ OrganizationID: owner.OrganizationID,
+ CreatedBy: member.ID,
+ HasAITask: sql.NullBool{
+ Bool: true,
+ Valid: true,
+ },
+ }).Do()
+
+ // nolint:gocritic // This is in a test package and does not end up in the build
+ ws1 := dbfake.WorkspaceBuild(t, store, database.WorkspaceTable{
+ Name: "get-task-workspace-1",
+ OrganizationID: owner.OrganizationID,
+ OwnerID: member.ID,
+ TemplateID: aiTV.Template.ID,
+ }).WithTask().Do()
+
+ tests := []struct {
+ name string
+ args toolsdk.GetTaskStatusArgs
+ expected codersdk.WorkspaceStatus
+ error string
+ }{
+ {
+ name: "ByUUID",
+ args: toolsdk.GetTaskStatusArgs{
+ TaskID: ws1.Workspace.ID.String(),
+ },
+ expected: codersdk.WorkspaceStatusRunning,
+ },
+ {
+ name: "ByWorkspaceIdentifier",
+ args: toolsdk.GetTaskStatusArgs{
+ TaskID: "get-task-workspace-1",
+ },
+ expected: codersdk.WorkspaceStatusRunning,
+ },
+ {
+ name: "NoID",
+ args: toolsdk.GetTaskStatusArgs{},
+ error: "task_id is required",
+ },
+ {
+ name: "NoTaskByID",
+ args: toolsdk.GetTaskStatusArgs{
+ TaskID: uuid.New().String(),
+ },
+ error: "Resource not found",
+ },
+ {
+ name: "NoTaskByWorkspaceIdentifier",
+ args: toolsdk.GetTaskStatusArgs{
+ TaskID: "non-existent",
+ },
+ error: "Resource not found",
+ },
+ {
+ name: "ExistsButNotATask",
+ args: toolsdk.GetTaskStatusArgs{
+ TaskID: r.Workspace.ID.String(),
+ },
+ error: "Resource not found",
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ t.Parallel()
+
+ tb, err := toolsdk.NewDeps(memberClient)
+ require.NoError(t, err)
+
+ res, err := testTool(t, toolsdk.GetTaskStatus, tb, tt.args)
+ if tt.error != "" {
+ require.Error(t, err)
+ require.ErrorContains(t, err, tt.error)
+ } else {
+ require.NoError(t, err)
+ require.Equal(t, tt.expected, res.Status)
+ }
+ })
+ }
+ })
}
// TestedTools keeps track of which tools have been tested.
From 94c76b97bd7f1dab0b5ea485e23cc5c5beaa9b99 Mon Sep 17 00:00:00 2001
From: Asher
Date: Wed, 1 Oct 2025 13:57:11 -0800
Subject: [PATCH 029/298] feat: add list_apps MCP tool (#19952)
---
codersdk/toolsdk/toolsdk.go | 53 ++++++++++++
codersdk/toolsdk/toolsdk_test.go | 140 +++++++++++++++++++++++++++++++
2 files changed, 193 insertions(+)
diff --git a/codersdk/toolsdk/toolsdk.go b/codersdk/toolsdk/toolsdk.go
index 63e17c2f039cd..c8228e51049d9 100644
--- a/codersdk/toolsdk/toolsdk.go
+++ b/codersdk/toolsdk/toolsdk.go
@@ -50,6 +50,7 @@ const (
ToolNameWorkspaceEditFile = "coder_workspace_edit_file"
ToolNameWorkspaceEditFiles = "coder_workspace_edit_files"
ToolNameWorkspacePortForward = "coder_workspace_port_forward"
+ ToolNameWorkspaceListApps = "coder_workspace_list_apps"
ToolNameCreateTask = "coder_create_task"
ToolNameDeleteTask = "coder_delete_task"
ToolNameListTasks = "coder_list_tasks"
@@ -227,6 +228,7 @@ var All = []GenericTool{
WorkspaceEditFile.Generic(),
WorkspaceEditFiles.Generic(),
WorkspacePortForward.Generic(),
+ WorkspaceListApps.Generic(),
CreateTask.Generic(),
DeleteTask.Generic(),
ListTasks.Generic(),
@@ -1756,6 +1758,57 @@ var WorkspacePortForward = Tool[WorkspacePortForwardArgs, WorkspacePortForwardRe
},
}
+type WorkspaceListAppsArgs struct {
+ Workspace string `json:"workspace"`
+}
+
+type WorkspaceListApp struct {
+ Name string `json:"name"`
+ URL string `json:"url"`
+}
+
+type WorkspaceListAppsResponse struct {
+ Apps []WorkspaceListApp `json:"apps"`
+}
+
+var WorkspaceListApps = Tool[WorkspaceListAppsArgs, WorkspaceListAppsResponse]{
+ Tool: aisdk.Tool{
+ Name: ToolNameWorkspaceListApps,
+ Description: `List the URLs of Coder apps running in a workspace for a single agent.`,
+ Schema: aisdk.Schema{
+ Properties: map[string]any{
+ "workspace": map[string]any{
+ "type": "string",
+ "description": workspaceDescription,
+ },
+ },
+ Required: []string{"workspace"},
+ },
+ },
+ UserClientOptional: true,
+ Handler: func(ctx context.Context, deps Deps, args WorkspaceListAppsArgs) (WorkspaceListAppsResponse, error) {
+ workspaceName := NormalizeWorkspaceInput(args.Workspace)
+ _, workspaceAgent, err := findWorkspaceAndAgent(ctx, deps.coderClient, workspaceName)
+ if err != nil {
+ return WorkspaceListAppsResponse{}, xerrors.Errorf("failed to find workspace: %w", err)
+ }
+
+ var res WorkspaceListAppsResponse
+ for _, app := range workspaceAgent.Apps {
+ name := app.DisplayName
+ if name == "" {
+ name = app.Slug
+ }
+ res.Apps = append(res.Apps, WorkspaceListApp{
+ Name: name,
+ URL: app.URL,
+ })
+ }
+
+ return res, nil
+ },
+}
+
type CreateTaskArgs struct {
Input string `json:"input"`
TemplateVersionID string `json:"template_version_id"`
diff --git a/codersdk/toolsdk/toolsdk_test.go b/codersdk/toolsdk/toolsdk_test.go
index 8e0cc09fff25d..1bc17fabb31e2 100644
--- a/codersdk/toolsdk/toolsdk_test.go
+++ b/codersdk/toolsdk/toolsdk_test.go
@@ -1147,6 +1147,146 @@ func TestTools(t *testing.T) {
})
}
})
+
+ t.Run("WorkspaceListApps", func(t *testing.T) {
+ t.Parallel()
+
+ // nolint:gocritic // This is in a test package and does not end up in the build
+ _ = dbfake.WorkspaceBuild(t, store, database.WorkspaceTable{
+ Name: "list-app-workspace-one-agent",
+ OrganizationID: owner.OrganizationID,
+ OwnerID: member.ID,
+ }).WithAgent(func(agents []*proto.Agent) []*proto.Agent {
+ agents[0].Apps = []*proto.App{
+ {
+ Slug: "zero",
+ Url: "http://zero.dev.coder.com",
+ },
+ }
+ return agents
+ }).Do()
+
+ // nolint:gocritic // This is in a test package and does not end up in the build
+ _ = dbfake.WorkspaceBuild(t, store, database.WorkspaceTable{
+ Name: "list-app-workspace-multi-agent",
+ OrganizationID: owner.OrganizationID,
+ OwnerID: member.ID,
+ }).WithAgent(func(agents []*proto.Agent) []*proto.Agent {
+ agents[0].Apps = []*proto.App{
+ {
+ Slug: "one",
+ Url: "http://one.dev.coder.com",
+ },
+ {
+ Slug: "two",
+ Url: "http://two.dev.coder.com",
+ },
+ {
+ Slug: "three",
+ Url: "http://three.dev.coder.com",
+ },
+ }
+ agents = append(agents, &proto.Agent{
+ Id: uuid.NewString(),
+ Name: "dev2",
+ Auth: &proto.Agent_Token{
+ Token: uuid.NewString(),
+ },
+ Env: map[string]string{},
+ Apps: []*proto.App{
+ {
+ Slug: "four",
+ Url: "http://four.dev.coder.com",
+ },
+ },
+ })
+ return agents
+ }).Do()
+
+ tests := []struct {
+ name string
+ args toolsdk.WorkspaceListAppsArgs
+ expected []toolsdk.WorkspaceListApp
+ error string
+ }{
+ {
+ name: "NonExistentWorkspace",
+ args: toolsdk.WorkspaceListAppsArgs{
+ Workspace: "list-appp-workspace-does-not-exist",
+ },
+ error: "failed to find workspace",
+ },
+ {
+ name: "OneAgentOneApp",
+ args: toolsdk.WorkspaceListAppsArgs{
+ Workspace: "list-app-workspace-one-agent",
+ },
+ expected: []toolsdk.WorkspaceListApp{
+ {
+ Name: "zero",
+ URL: "http://zero.dev.coder.com",
+ },
+ },
+ },
+ {
+ name: "MultiAgent",
+ args: toolsdk.WorkspaceListAppsArgs{
+ Workspace: "list-app-workspace-multi-agent",
+ },
+ error: "multiple agents found, please specify the agent name",
+ },
+ {
+ name: "MultiAgentOneApp",
+ args: toolsdk.WorkspaceListAppsArgs{
+ Workspace: "list-app-workspace-multi-agent.dev2",
+ },
+ expected: []toolsdk.WorkspaceListApp{
+ {
+ Name: "four",
+ URL: "http://four.dev.coder.com",
+ },
+ },
+ },
+ {
+ name: "MultiAgentMultiApp",
+ args: toolsdk.WorkspaceListAppsArgs{
+ Workspace: "list-app-workspace-multi-agent.dev",
+ },
+ expected: []toolsdk.WorkspaceListApp{
+ {
+ Name: "one",
+ URL: "http://one.dev.coder.com",
+ },
+ {
+ Name: "three",
+ URL: "http://three.dev.coder.com",
+ },
+ {
+ Name: "two",
+ URL: "http://two.dev.coder.com",
+ },
+ },
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ t.Parallel()
+
+ tb, err := toolsdk.NewDeps(memberClient)
+ require.NoError(t, err)
+
+ res, err := testTool(t, toolsdk.WorkspaceListApps, tb, tt.args)
+ if tt.error != "" {
+ require.Error(t, err)
+ require.ErrorContains(t, err, tt.error)
+ } else {
+ require.NoError(t, err)
+ require.Equal(t, tt.expected, res.Apps)
+ }
+ })
+ }
+ })
}
// TestedTools keeps track of which tools have been tested.
From 230df3eadf344606cc2b99b3689431bd9760cfc2 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 1 Oct 2025 22:11:37 +0000
Subject: [PATCH 030/298] chore: bump react-confetti from 6.2.2 to 6.4.0 in
/site (#20126)
Bumps [react-confetti](https://github.com/alampros/react-confetti) from
6.2.2 to 6.4.0.
Release notes
Sourced from react-confetti's
releases .
v6.4.0
6.4.0
(2025-03-04)
Bug Fixes
clamp tweenProgress between 0 and tweenDuration (f988305 )
Features
adding tweenFrom property to allow smooth transition when parameters
change (dde31e0 )
v6.3.0
6.3.0
(2025-03-01)
Bug Fixes
prevent particle flicker on removal (5cb5bd8 )
Features
using elapsed time in physics updates (d1626dc )
v6.2.3
6.2.3
(2025-02-22)
Bug Fixes
Changelog
Sourced from react-confetti's
changelog .
6.4.0
(2025-03-04)
Bug Fixes
clamp tweenProgress between 0 and tweenDuration (f988305 )
Features
adding tweenFrom property to allow smooth transition when parameters
change (dde31e0 )
6.3.0
(2025-03-01)
Bug Fixes
prevent particle flicker on removal (5cb5bd8 )
Features
using elapsed time in physics updates (d1626dc )
6.2.3
(2025-02-22)
Bug Fixes
Commits
0d53537
chore(release): 6.4.0 [skip ci]
641b351
Merge branch 'develop'
6ac61ed
lint fix
90f5a59
Merge pull request #172
from AlexJDG/bugfix/fix-tweening
f988305
fix: clamp tweenProgress between 0 and tweenDuration
dde31e0
feat: adding tweenFrom property to allow smooth transition when
parameters ch...
5dd9f7b
chore: renaming property for clarity
31eb46d
chore(release): 6.3.0 [skip ci]
e447389
Merge branch 'develop'
b177991
fix lint action name
Additional commits viewable in compare
view
[](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
site/package.json | 2 +-
site/pnpm-lock.yaml | 10 +++++-----
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/site/package.json b/site/package.json
index 660227b1373a1..38617dce23a99 100644
--- a/site/package.json
+++ b/site/package.json
@@ -96,7 +96,7 @@
"pretty-bytes": "6.1.1",
"react": "19.1.1",
"react-color": "2.19.3",
- "react-confetti": "6.2.2",
+ "react-confetti": "6.4.0",
"react-date-range": "1.4.0",
"react-dom": "19.1.1",
"react-markdown": "9.1.0",
diff --git a/site/pnpm-lock.yaml b/site/pnpm-lock.yaml
index 068bc1959648e..eebed5b445afc 100644
--- a/site/pnpm-lock.yaml
+++ b/site/pnpm-lock.yaml
@@ -203,8 +203,8 @@ importers:
specifier: 2.19.3
version: 2.19.3(react@19.1.1)
react-confetti:
- specifier: 6.2.2
- version: 6.2.2(react@19.1.1)
+ specifier: 6.4.0
+ version: 6.4.0(react@19.1.1)
react-date-range:
specifier: 1.4.0
version: 1.4.0(date-fns@2.30.0)(react@19.1.1)
@@ -5588,8 +5588,8 @@ packages:
peerDependencies:
react: '*'
- react-confetti@6.2.2:
- resolution: {integrity: sha512-K+kTyOPgX+ZujMZ+Rmb7pZdHBvg+DzinG/w4Eh52WOB8/pfO38efnnrtEZNJmjTvLxc16RBYO+tPM68Fg8viBA==, tarball: https://registry.npmjs.org/react-confetti/-/react-confetti-6.2.2.tgz}
+ react-confetti@6.4.0:
+ resolution: {integrity: sha512-5MdGUcqxrTU26I2EU7ltkWPwxvucQTuqMm8dUz72z2YMqTD6s9vMcDUysk7n9jnC+lXuCPeJJ7Knf98VEYE9Rg==, tarball: https://registry.npmjs.org/react-confetti/-/react-confetti-6.4.0.tgz}
engines: {node: '>=16'}
peerDependencies:
react: ^16.3.0 || ^17.0.1 || ^18.0.0 || ^19.0.0
@@ -12427,7 +12427,7 @@ snapshots:
reactcss: 1.2.3(react@19.1.1)
tinycolor2: 1.6.0
- react-confetti@6.2.2(react@19.1.1):
+ react-confetti@6.4.0(react@19.1.1):
dependencies:
react: 19.1.1
tween-functions: 1.2.0
From 4e53d8b9c257b96b9360c8e2f73d461cef4ea57d Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 1 Oct 2025 22:12:40 +0000
Subject: [PATCH 031/298] chore: bump @biomejs/biome from 2.2.0 to 2.2.4 in
/site (#20118)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Bumps
[@biomejs/biome](https://github.com/biomejs/biome/tree/HEAD/packages/@biomejs/biome)
from 2.2.0 to 2.2.4.
Release notes
Sourced from @biomejs/biome's
releases .
Biome CLI v2.2.4
2.2.4
Patch Changes
#7453
aa8cea3 Thanks @arendjr ! - Fixed #7242 :
Aliases specified in
package.json's imports section now support
having multiple targets as part of an array.
#7454
ac17183 Thanks @arendjr ! - Greatly
improved performance of
noImportCycles by eliminating allocations.
In one repository, the total runtime of Biome with only
noImportCycles enabled went from ~23s down to ~4s.
#7447
7139aad Thanks @rriski ! - Fixes #7446 .
The GritQL
$... spread metavariable now correctly matches members in
object literals, aligning its behavior with arrays and function
calls.
#6710
98cf9af Thanks @arendjr ! - Fixed #4723 :
Type inference now recognises
index signatures and their accesses when they are being indexed
as a string.
Example
type BagOfPromises = {
// This is an index signature definition. It declares that instances of
type
// `BagOfPromises` can be indexed using arbitrary strings.
[property: string]: Promise<void>;
};
let bag: BagOfPromises = {};
// Because bag.iAmAPromise is equivalent to
bag["iAmAPromise"], this is
// considered an access to the string index, and a Promise is expected.
bag.iAmAPromise;
#7415
d042f18 Thanks @qraqras ! - Fixed #7212 ,
now the
useOptionalChain rule recognizes optional chaining
using
typeof (e.g., typeof foo !== 'undefined' &&
foo.bar).
#7419
576baf4 Thanks @Conaclos ! - Fixed
#7323 .
noUnusedPrivateClassMembers no longer reports as unused
TypeScript
private members if the rule encounters a computed access on
this.
In the following example, member as previously reported
as unused. It is no longer reported.
... (truncated)
Changelog
Sourced from @biomejs/biome's
changelog .
2.2.4
Patch Changes
#7453 aa8cea3
Thanks @arendjr !
- Fixed #7242 :
Aliases specified in
package.json's imports section now support
having multiple targets as part of an array.
#7454 ac17183
Thanks @arendjr !
- Greatly improved performance of
noImportCycles by eliminating allocations.
In one repository, the total runtime of Biome with only
noImportCycles enabled went from ~23s down to ~4s.
#7447 7139aad
Thanks @rriski ! -
Fixes #7446 .
The GritQL
$... spread metavariable now correctly matches members in
object literals, aligning its behavior with arrays and function
calls.
#6710 98cf9af
Thanks @arendjr !
- Fixed #4723 :
Type inference now recognises
index signatures and their accesses when they are being indexed
as a string.
Example
type BagOfPromises = {
// This is an index signature definition. It declares that instances of
type
// `BagOfPromises` can be indexed using arbitrary strings.
[property: string]: Promise<void>;
};
let bag: BagOfPromises = {};
// Because bag.iAmAPromise is equivalent to
bag["iAmAPromise"], this is
// considered an access to the string index, and a Promise is expected.
bag.iAmAPromise;
#7415 d042f18
Thanks @qraqras !
- Fixed #7212 ,
now the useOptionalChain
rule recognizes optional chaining using
typeof (e.g., typeof foo !== 'undefined' &&
foo.bar).
#7419 576baf4
Thanks @Conaclos ! - Fixed
#7323 .
noUnusedPrivateClassMembers
no longer reports as unused TypeScript
private members if the rule encounters a computed access on
this.
In the following example, member as previously reported
as unused. It is no longer reported.
class TsBioo {
private member: number;
set_with_name(name: string, value: number) {
this[name] = value;
}
}
... (truncated)
Commits
[](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
site/package.json | 2 +-
site/pnpm-lock.yaml | 80 ++++++++++++++++++++++-----------------------
2 files changed, 41 insertions(+), 41 deletions(-)
diff --git a/site/package.json b/site/package.json
index 38617dce23a99..8a6c06c110dfb 100644
--- a/site/package.json
+++ b/site/package.json
@@ -123,7 +123,7 @@
"yup": "1.6.1"
},
"devDependencies": {
- "@biomejs/biome": "2.2.0",
+ "@biomejs/biome": "2.2.4",
"@chromatic-com/storybook": "4.1.0",
"@octokit/types": "12.3.0",
"@playwright/test": "1.50.1",
diff --git a/site/pnpm-lock.yaml b/site/pnpm-lock.yaml
index eebed5b445afc..35ed3e0545012 100644
--- a/site/pnpm-lock.yaml
+++ b/site/pnpm-lock.yaml
@@ -279,8 +279,8 @@ importers:
version: 1.6.1
devDependencies:
'@biomejs/biome':
- specifier: 2.2.0
- version: 2.2.0
+ specifier: 2.2.4
+ version: 2.2.4
'@chromatic-com/storybook':
specifier: 4.1.0
version: 4.1.0(storybook@9.1.2(@testing-library/dom@10.4.0)(msw@2.4.8(typescript@5.6.3))(prettier@3.4.1)(vite@7.1.7(@types/node@20.17.16)(jiti@1.21.7)(yaml@2.7.0)))
@@ -454,7 +454,7 @@ importers:
version: 7.1.7(@types/node@20.17.16)(jiti@1.21.7)(yaml@2.7.0)
vite-plugin-checker:
specifier: 0.11.0
- version: 0.11.0(@biomejs/biome@2.2.0)(eslint@8.52.0)(optionator@0.9.3)(typescript@5.6.3)(vite@7.1.7(@types/node@20.17.16)(jiti@1.21.7)(yaml@2.7.0))
+ version: 0.11.0(@biomejs/biome@2.2.4)(eslint@8.52.0)(optionator@0.9.3)(typescript@5.6.3)(vite@7.1.7(@types/node@20.17.16)(jiti@1.21.7)(yaml@2.7.0))
packages:
@@ -658,55 +658,55 @@ packages:
'@bcoe/v8-coverage@0.2.3':
resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==, tarball: https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz}
- '@biomejs/biome@2.2.0':
- resolution: {integrity: sha512-3On3RSYLsX+n9KnoSgfoYlckYBoU6VRM22cw1gB4Y0OuUVSYd/O/2saOJMrA4HFfA1Ff0eacOvMN1yAAvHtzIw==, tarball: https://registry.npmjs.org/@biomejs/biome/-/biome-2.2.0.tgz}
+ '@biomejs/biome@2.2.4':
+ resolution: {integrity: sha512-TBHU5bUy/Ok6m8c0y3pZiuO/BZoY/OcGxoLlrfQof5s8ISVwbVBdFINPQZyFfKwil8XibYWb7JMwnT8wT4WVPg==, tarball: https://registry.npmjs.org/@biomejs/biome/-/biome-2.2.4.tgz}
engines: {node: '>=14.21.3'}
hasBin: true
- '@biomejs/cli-darwin-arm64@2.2.0':
- resolution: {integrity: sha512-zKbwUUh+9uFmWfS8IFxmVD6XwqFcENjZvEyfOxHs1epjdH3wyyMQG80FGDsmauPwS2r5kXdEM0v/+dTIA9FXAg==, tarball: https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.2.0.tgz}
+ '@biomejs/cli-darwin-arm64@2.2.4':
+ resolution: {integrity: sha512-RJe2uiyaloN4hne4d2+qVj3d3gFJFbmrr5PYtkkjei1O9c+BjGXgpUPVbi8Pl8syumhzJjFsSIYkcLt2VlVLMA==, tarball: https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.2.4.tgz}
engines: {node: '>=14.21.3'}
cpu: [arm64]
os: [darwin]
- '@biomejs/cli-darwin-x64@2.2.0':
- resolution: {integrity: sha512-+OmT4dsX2eTfhD5crUOPw3RPhaR+SKVspvGVmSdZ9y9O/AgL8pla6T4hOn1q+VAFBHuHhsdxDRJgFCSC7RaMOw==, tarball: https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.2.0.tgz}
+ '@biomejs/cli-darwin-x64@2.2.4':
+ resolution: {integrity: sha512-cFsdB4ePanVWfTnPVaUX+yr8qV8ifxjBKMkZwN7gKb20qXPxd/PmwqUH8mY5wnM9+U0QwM76CxFyBRJhC9tQwg==, tarball: https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.2.4.tgz}
engines: {node: '>=14.21.3'}
cpu: [x64]
os: [darwin]
- '@biomejs/cli-linux-arm64-musl@2.2.0':
- resolution: {integrity: sha512-egKpOa+4FL9YO+SMUMLUvf543cprjevNc3CAgDNFLcjknuNMcZ0GLJYa3EGTCR2xIkIUJDVneBV3O9OcIlCEZQ==, tarball: https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.2.0.tgz}
+ '@biomejs/cli-linux-arm64-musl@2.2.4':
+ resolution: {integrity: sha512-7TNPkMQEWfjvJDaZRSkDCPT/2r5ESFPKx+TEev+I2BXDGIjfCZk2+b88FOhnJNHtksbOZv8ZWnxrA5gyTYhSsQ==, tarball: https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.2.4.tgz}
engines: {node: '>=14.21.3'}
cpu: [arm64]
os: [linux]
- '@biomejs/cli-linux-arm64@2.2.0':
- resolution: {integrity: sha512-6eoRdF2yW5FnW9Lpeivh7Mayhq0KDdaDMYOJnH9aT02KuSIX5V1HmWJCQQPwIQbhDh68Zrcpl8inRlTEan0SXw==, tarball: https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.2.0.tgz}
+ '@biomejs/cli-linux-arm64@2.2.4':
+ resolution: {integrity: sha512-M/Iz48p4NAzMXOuH+tsn5BvG/Jb07KOMTdSVwJpicmhN309BeEyRyQX+n1XDF0JVSlu28+hiTQ2L4rZPvu7nMw==, tarball: https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.2.4.tgz}
engines: {node: '>=14.21.3'}
cpu: [arm64]
os: [linux]
- '@biomejs/cli-linux-x64-musl@2.2.0':
- resolution: {integrity: sha512-I5J85yWwUWpgJyC1CcytNSGusu2p9HjDnOPAFG4Y515hwRD0jpR9sT9/T1cKHtuCvEQ/sBvx+6zhz9l9wEJGAg==, tarball: https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.2.0.tgz}
+ '@biomejs/cli-linux-x64-musl@2.2.4':
+ resolution: {integrity: sha512-m41nFDS0ksXK2gwXL6W6yZTYPMH0LughqbsxInSKetoH6morVj43szqKx79Iudkp8WRT5SxSh7qVb8KCUiewGg==, tarball: https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.2.4.tgz}
engines: {node: '>=14.21.3'}
cpu: [x64]
os: [linux]
- '@biomejs/cli-linux-x64@2.2.0':
- resolution: {integrity: sha512-5UmQx/OZAfJfi25zAnAGHUMuOd+LOsliIt119x2soA2gLggQYrVPA+2kMUxR6Mw5M1deUF/AWWP2qpxgH7Nyfw==, tarball: https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-2.2.0.tgz}
+ '@biomejs/cli-linux-x64@2.2.4':
+ resolution: {integrity: sha512-orr3nnf2Dpb2ssl6aihQtvcKtLySLta4E2UcXdp7+RTa7mfJjBgIsbS0B9GC8gVu0hjOu021aU8b3/I1tn+pVQ==, tarball: https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-2.2.4.tgz}
engines: {node: '>=14.21.3'}
cpu: [x64]
os: [linux]
- '@biomejs/cli-win32-arm64@2.2.0':
- resolution: {integrity: sha512-n9a1/f2CwIDmNMNkFs+JI0ZjFnMO0jdOyGNtihgUNFnlmd84yIYY2KMTBmMV58ZlVHjgmY5Y6E1hVTnSRieggA==, tarball: https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.2.0.tgz}
+ '@biomejs/cli-win32-arm64@2.2.4':
+ resolution: {integrity: sha512-NXnfTeKHDFUWfxAefa57DiGmu9VyKi0cDqFpdI+1hJWQjGJhJutHPX0b5m+eXvTKOaf+brU+P0JrQAZMb5yYaQ==, tarball: https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.2.4.tgz}
engines: {node: '>=14.21.3'}
cpu: [arm64]
os: [win32]
- '@biomejs/cli-win32-x64@2.2.0':
- resolution: {integrity: sha512-Nawu5nHjP/zPKTIryh2AavzTc/KEg4um/MxWdXW0A6P/RZOyIpa7+QSjeXwAwX/utJGaCoXRPWtF3m5U/bB3Ww==, tarball: https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-2.2.0.tgz}
+ '@biomejs/cli-win32-x64@2.2.4':
+ resolution: {integrity: sha512-3Y4V4zVRarVh/B/eSHczR4LYoSVyv3Dfuvm3cWs5w/HScccS0+Wt/lHOcDTRYeHjQmMYVC3rIRWqyN2EI52+zg==, tarball: https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-2.2.4.tgz}
engines: {node: '>=14.21.3'}
cpu: [x64]
os: [win32]
@@ -6925,39 +6925,39 @@ snapshots:
'@bcoe/v8-coverage@0.2.3': {}
- '@biomejs/biome@2.2.0':
+ '@biomejs/biome@2.2.4':
optionalDependencies:
- '@biomejs/cli-darwin-arm64': 2.2.0
- '@biomejs/cli-darwin-x64': 2.2.0
- '@biomejs/cli-linux-arm64': 2.2.0
- '@biomejs/cli-linux-arm64-musl': 2.2.0
- '@biomejs/cli-linux-x64': 2.2.0
- '@biomejs/cli-linux-x64-musl': 2.2.0
- '@biomejs/cli-win32-arm64': 2.2.0
- '@biomejs/cli-win32-x64': 2.2.0
+ '@biomejs/cli-darwin-arm64': 2.2.4
+ '@biomejs/cli-darwin-x64': 2.2.4
+ '@biomejs/cli-linux-arm64': 2.2.4
+ '@biomejs/cli-linux-arm64-musl': 2.2.4
+ '@biomejs/cli-linux-x64': 2.2.4
+ '@biomejs/cli-linux-x64-musl': 2.2.4
+ '@biomejs/cli-win32-arm64': 2.2.4
+ '@biomejs/cli-win32-x64': 2.2.4
- '@biomejs/cli-darwin-arm64@2.2.0':
+ '@biomejs/cli-darwin-arm64@2.2.4':
optional: true
- '@biomejs/cli-darwin-x64@2.2.0':
+ '@biomejs/cli-darwin-x64@2.2.4':
optional: true
- '@biomejs/cli-linux-arm64-musl@2.2.0':
+ '@biomejs/cli-linux-arm64-musl@2.2.4':
optional: true
- '@biomejs/cli-linux-arm64@2.2.0':
+ '@biomejs/cli-linux-arm64@2.2.4':
optional: true
- '@biomejs/cli-linux-x64-musl@2.2.0':
+ '@biomejs/cli-linux-x64-musl@2.2.4':
optional: true
- '@biomejs/cli-linux-x64@2.2.0':
+ '@biomejs/cli-linux-x64@2.2.4':
optional: true
- '@biomejs/cli-win32-arm64@2.2.0':
+ '@biomejs/cli-win32-arm64@2.2.4':
optional: true
- '@biomejs/cli-win32-x64@2.2.0':
+ '@biomejs/cli-win32-x64@2.2.4':
optional: true
'@bundled-es-modules/cookie@2.0.1':
@@ -13416,7 +13416,7 @@ snapshots:
d3-time: 3.1.0
d3-timer: 3.0.1
- vite-plugin-checker@0.11.0(@biomejs/biome@2.2.0)(eslint@8.52.0)(optionator@0.9.3)(typescript@5.6.3)(vite@7.1.7(@types/node@20.17.16)(jiti@1.21.7)(yaml@2.7.0)):
+ vite-plugin-checker@0.11.0(@biomejs/biome@2.2.4)(eslint@8.52.0)(optionator@0.9.3)(typescript@5.6.3)(vite@7.1.7(@types/node@20.17.16)(jiti@1.21.7)(yaml@2.7.0)):
dependencies:
'@babel/code-frame': 7.27.1
chokidar: 4.0.3
@@ -13428,7 +13428,7 @@ snapshots:
vite: 7.1.7(@types/node@20.17.16)(jiti@1.21.7)(yaml@2.7.0)
vscode-uri: 3.1.0
optionalDependencies:
- '@biomejs/biome': 2.2.0
+ '@biomejs/biome': 2.2.4
eslint: 8.52.0
optionator: 0.9.3
typescript: 5.6.3
From 79f5cb8b9ae314f0d8be6b3b78108ee17ac6041b Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 1 Oct 2025 22:46:31 +0000
Subject: [PATCH 032/298] chore: bump react-virtualized-auto-sizer and
@types/react-virtualized-auto-sizer (#20078)
Bumps
[react-virtualized-auto-sizer](https://github.com/bvaughn/react-virtualized-auto-sizer)
and
[@types/react-virtualized-auto-sizer](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react-virtualized-auto-sizer).
These dependencies needed to be updated together.
Updates `react-virtualized-auto-sizer` from 1.0.24 to 1.0.26
Release notes
Sourced from react-virtualized-auto-sizer's
releases .
1.0.26
Changed width and height values to be
based om getBoundingClientRect rather than
offsetWidth and offsetHeight (which
are integers and can cause rounding/flickering problems in some
cases).
1.0.25
Dependencies updated to include React 19
Changelog
Sourced from react-virtualized-auto-sizer's
changelog .
1.0.26
Changed width and height values to be
based om getBoundingClientRect rather than
offsetWidth and offsetHeight (which
are integers and can cause rounding/flickering problems in some
cases).
1.0.25
Dependencies updated to include React 19
Commits
45b1270
Add deprecation warning for scaledWidth/scaledHeight accessors
e9c8ef0
Merge pull request #97
from bvaughn/issues/96
fdf25d4
Change width and height to come from getBoundingClientRect rather than
offset...
1898b07
Tweaked README format
2dc8808
1.0.24 -> 1.0.25
801cc52
Merge pull request #93
from olafbuitelaar/patch-1
0b8b181
updated deps to react 19
9f970c9
Update README
See full diff in compare
view
Updates `@types/react-virtualized-auto-sizer` from 1.0.4 to 1.0.8
Commits
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
site/package.json | 4 ++--
site/pnpm-lock.yaml | 30 +++++++++++++++++-------------
2 files changed, 19 insertions(+), 15 deletions(-)
diff --git a/site/package.json b/site/package.json
index 8a6c06c110dfb..9183fed149d2e 100644
--- a/site/package.json
+++ b/site/package.json
@@ -105,7 +105,7 @@
"react-router": "7.8.0",
"react-syntax-highlighter": "15.6.1",
"react-textarea-autosize": "8.5.9",
- "react-virtualized-auto-sizer": "1.0.24",
+ "react-virtualized-auto-sizer": "1.0.26",
"react-window": "1.8.11",
"recharts": "2.15.0",
"remark-gfm": "4.0.0",
@@ -150,7 +150,7 @@
"@types/react-date-range": "1.4.4",
"@types/react-dom": "19.1.11",
"@types/react-syntax-highlighter": "15.5.13",
- "@types/react-virtualized-auto-sizer": "1.0.4",
+ "@types/react-virtualized-auto-sizer": "1.0.8",
"@types/react-window": "1.8.8",
"@types/semver": "7.7.1",
"@types/ssh2": "1.15.5",
diff --git a/site/pnpm-lock.yaml b/site/pnpm-lock.yaml
index 35ed3e0545012..4570da4575185 100644
--- a/site/pnpm-lock.yaml
+++ b/site/pnpm-lock.yaml
@@ -230,8 +230,8 @@ importers:
specifier: 8.5.9
version: 8.5.9(@types/react@19.1.17)(react@19.1.1)
react-virtualized-auto-sizer:
- specifier: 1.0.24
- version: 1.0.24(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ specifier: 1.0.26
+ version: 1.0.26(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
react-window:
specifier: 1.8.11
version: 1.8.11(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
@@ -360,8 +360,8 @@ importers:
specifier: 15.5.13
version: 15.5.13
'@types/react-virtualized-auto-sizer':
- specifier: 1.0.4
- version: 1.0.4
+ specifier: 1.0.8
+ version: 1.0.8(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
'@types/react-window':
specifier: 1.8.8
version: 1.8.8
@@ -2987,8 +2987,9 @@ packages:
peerDependencies:
'@types/react': '*'
- '@types/react-virtualized-auto-sizer@1.0.4':
- resolution: {integrity: sha512-nhYwlFiYa8M3S+O2T9QO/e1FQUYMr/wJENUdf/O0dhRi1RS/93rjrYQFYdbUqtdFySuhrtnEDX29P6eKOttY+A==, tarball: https://registry.npmjs.org/@types/react-virtualized-auto-sizer/-/react-virtualized-auto-sizer-1.0.4.tgz}
+ '@types/react-virtualized-auto-sizer@1.0.8':
+ resolution: {integrity: sha512-keJpNyhiwfl2+N12G1ocCVA5ZDBArbPLe/S90X3kt7fam9naeHdaYYWbpe2sHczp70JWJ+2QLhBE8kLvLuVNjA==, tarball: https://registry.npmjs.org/@types/react-virtualized-auto-sizer/-/react-virtualized-auto-sizer-1.0.8.tgz}
+ deprecated: This is a stub types definition. react-virtualized-auto-sizer provides its own type definitions, so you do not need this installed.
'@types/react-window@1.8.8':
resolution: {integrity: sha512-8Ls660bHR1AUA2kuRvVG9D/4XpRC6wjAaPT9dil7Ckc76eP9TKWZwwmgfq8Q1LANX3QNDnoU4Zp48A3w+zK69Q==, tarball: https://registry.npmjs.org/@types/react-window/-/react-window-1.8.8.tgz}
@@ -5728,11 +5729,11 @@ packages:
react: '>=16.6.0'
react-dom: '>=16.6.0'
- react-virtualized-auto-sizer@1.0.24:
- resolution: {integrity: sha512-3kCn7N9NEb3FlvJrSHWGQ4iVl+ydQObq2fHMn12i5wbtm74zHOPhz/i64OL3c1S1vi9i2GXtZqNqUJTQ+BnNfg==, tarball: https://registry.npmjs.org/react-virtualized-auto-sizer/-/react-virtualized-auto-sizer-1.0.24.tgz}
+ react-virtualized-auto-sizer@1.0.26:
+ resolution: {integrity: sha512-CblNyiNVw2o+hsa5/49NH2ogGxZ+t+3aweRvNSq7TVjDIlwk7ir4lencEg5HxHeSzwNarSkNkiu0qJSOXtxm5A==, tarball: https://registry.npmjs.org/react-virtualized-auto-sizer/-/react-virtualized-auto-sizer-1.0.26.tgz}
peerDependencies:
- react: ^15.3.0 || ^16.0.0-alpha || ^17.0.0 || ^18.0.0
- react-dom: ^15.3.0 || ^16.0.0-alpha || ^17.0.0 || ^18.0.0
+ react: ^15.3.0 || ^16.0.0-alpha || ^17.0.0 || ^18.0.0 || ^19.0.0
+ react-dom: ^15.3.0 || ^16.0.0-alpha || ^17.0.0 || ^18.0.0 || ^19.0.0
react-window@1.8.11:
resolution: {integrity: sha512-+SRbUVT2scadgFSWx+R1P754xHPEqvcfSfVX10QYg6POOz+WNgkN48pS+BtZNIMGiL1HYrSEiCkwsMS15QogEQ==, tarball: https://registry.npmjs.org/react-window/-/react-window-1.8.11.tgz}
@@ -9187,9 +9188,12 @@ snapshots:
dependencies:
'@types/react': 19.1.17
- '@types/react-virtualized-auto-sizer@1.0.4':
+ '@types/react-virtualized-auto-sizer@1.0.8(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
dependencies:
- '@types/react': 19.1.17
+ react-virtualized-auto-sizer: 1.0.26(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ transitivePeerDependencies:
+ - react
+ - react-dom
'@types/react-window@1.8.8':
dependencies:
@@ -12591,7 +12595,7 @@ snapshots:
react: 19.1.1
react-dom: 19.1.1(react@19.1.1)
- react-virtualized-auto-sizer@1.0.24(react-dom@19.1.1(react@19.1.1))(react@19.1.1):
+ react-virtualized-auto-sizer@1.0.26(react-dom@19.1.1(react@19.1.1))(react@19.1.1):
dependencies:
react: 19.1.1
react-dom: 19.1.1(react@19.1.1)
From 29b4cfc55b9d7a712866b013da11bac006bd746d Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 1 Oct 2025 17:08:26 -0600
Subject: [PATCH 033/298] chore: bump remark-gfm from 4.0.0 to 4.0.1 in /site
(#20081)
---
site/package.json | 2 +-
site/pnpm-lock.yaml | 409 ++++++++------------------------------------
2 files changed, 75 insertions(+), 336 deletions(-)
diff --git a/site/package.json b/site/package.json
index 9183fed149d2e..7ba86b7881665 100644
--- a/site/package.json
+++ b/site/package.json
@@ -108,7 +108,7 @@
"react-virtualized-auto-sizer": "1.0.26",
"react-window": "1.8.11",
"recharts": "2.15.0",
- "remark-gfm": "4.0.0",
+ "remark-gfm": "4.0.1",
"resize-observer-polyfill": "1.5.1",
"semver": "7.7.2",
"tailwind-merge": "2.6.0",
diff --git a/site/pnpm-lock.yaml b/site/pnpm-lock.yaml
index 4570da4575185..49f5c686087b8 100644
--- a/site/pnpm-lock.yaml
+++ b/site/pnpm-lock.yaml
@@ -239,8 +239,8 @@ importers:
specifier: 2.15.0
version: 2.15.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
remark-gfm:
- specifier: 4.0.0
- version: 4.0.0
+ specifier: 4.0.1
+ version: 4.0.1
resize-observer-polyfill:
specifier: 1.5.1
version: 1.5.1
@@ -2919,9 +2919,6 @@ packages:
'@types/lodash@4.17.20':
resolution: {integrity: sha512-H3MHACvFUEiujabxhaI/ImO6gUrd8oOurg7LQtS7mbwIXA/cUqWrvBsaeJ23aZEPk1TAYkurjfMbSELfoCXlGA==, tarball: https://registry.npmjs.org/@types/lodash/-/lodash-4.17.20.tgz}
- '@types/mdast@4.0.3':
- resolution: {integrity: sha512-LsjtqsyF+d2/yFOYaN22dHZI1Cpwkrj+g06G8+qtUKlhovPW89YhqSnfKtMbkgmEtYpH2gydRNULd6y8mciAFg==, tarball: https://registry.npmjs.org/@types/mdast/-/mdast-4.0.3.tgz}
-
'@types/mdast@4.0.4':
resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==, tarball: https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz}
@@ -3041,9 +3038,6 @@ packages:
'@types/unist@2.0.11':
resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==, tarball: https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz}
- '@types/unist@3.0.2':
- resolution: {integrity: sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==, tarball: https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz}
-
'@types/unist@3.0.3':
resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==, tarball: https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz}
@@ -3730,9 +3724,6 @@ packages:
decimal.js@10.4.3:
resolution: {integrity: sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==, tarball: https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz}
- decode-named-character-reference@1.0.2:
- resolution: {integrity: sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==, tarball: https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.0.2.tgz}
-
decode-named-character-reference@1.2.0:
resolution: {integrity: sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q==, tarball: https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.2.0.tgz}
@@ -4917,8 +4908,8 @@ packages:
makeerror@1.0.12:
resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==, tarball: https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz}
- markdown-table@3.0.3:
- resolution: {integrity: sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw==, tarball: https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.3.tgz}
+ markdown-table@3.0.4:
+ resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==, tarball: https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.4.tgz}
material-colors@1.2.6:
resolution: {integrity: sha512-6qE4B9deFBIa9YSpOc9O0Sgc43zTeVYbgDT5veRKSlB2+ZuHNoVVxA1L/ckMUayV9Ay9y7Z/SZCLcGteW9i7bg==, tarball: https://registry.npmjs.org/material-colors/-/material-colors-1.2.6.tgz}
@@ -4927,20 +4918,17 @@ packages:
resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==, tarball: https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz}
engines: {node: '>= 0.4'}
- mdast-util-find-and-replace@3.0.1:
- resolution: {integrity: sha512-SG21kZHGC3XRTSUhtofZkBzZTJNM5ecCi0SK2IMKmSXR8vO3peL+kb1O0z7Zl83jKtutG4k5Wv/W7V3/YHvzPA==, tarball: https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.1.tgz}
-
- mdast-util-from-markdown@2.0.0:
- resolution: {integrity: sha512-n7MTOr/z+8NAX/wmhhDji8O3bRvPTV/U0oTCaZJkjhPSKTPhS3xufVhKGF8s1pJ7Ox4QgoIU7KHseh09S+9rTA==, tarball: https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.0.tgz}
+ mdast-util-find-and-replace@3.0.2:
+ resolution: {integrity: sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==, tarball: https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.2.tgz}
mdast-util-from-markdown@2.0.2:
resolution: {integrity: sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==, tarball: https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.2.tgz}
- mdast-util-gfm-autolink-literal@2.0.0:
- resolution: {integrity: sha512-FyzMsduZZHSc3i0Px3PQcBT4WJY/X/RCtEJKuybiC6sjPqLv7h1yqAkmILZtuxMSsUyaLUWNp71+vQH2zqp5cg==, tarball: https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.0.tgz}
+ mdast-util-gfm-autolink-literal@2.0.1:
+ resolution: {integrity: sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==, tarball: https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.1.tgz}
- mdast-util-gfm-footnote@2.0.0:
- resolution: {integrity: sha512-5jOT2boTSVkMnQ7LTrd6n/18kqwjmuYqo7JUPe+tRCY6O7dAuTFMtTPauYYrMPpox9hlN0uOx/FL8XvEfG9/mQ==, tarball: https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.0.0.tgz}
+ mdast-util-gfm-footnote@2.1.0:
+ resolution: {integrity: sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==, tarball: https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.1.0.tgz}
mdast-util-gfm-strikethrough@2.0.0:
resolution: {integrity: sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==, tarball: https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz}
@@ -4951,8 +4939,8 @@ packages:
mdast-util-gfm-task-list-item@2.0.0:
resolution: {integrity: sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==, tarball: https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz}
- mdast-util-gfm@3.0.0:
- resolution: {integrity: sha512-dgQEX5Amaq+DuUqf26jJqSK9qgixgd6rYDHAv4aTBuA92cTknZlKpPfa86Z/s8Dj8xsAQpFfBmPUHWJBWqS4Bw==, tarball: https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.0.0.tgz}
+ mdast-util-gfm@3.1.0:
+ resolution: {integrity: sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==, tarball: https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.1.0.tgz}
mdast-util-mdx-expression@2.0.1:
resolution: {integrity: sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==, tarball: https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.1.tgz}
@@ -4963,18 +4951,12 @@ packages:
mdast-util-mdxjs-esm@2.0.1:
resolution: {integrity: sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==, tarball: https://registry.npmjs.org/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz}
- mdast-util-phrasing@4.0.0:
- resolution: {integrity: sha512-xadSsJayQIucJ9n053dfQwVu1kuXg7jCTdYsMK8rqzKZh52nLfSH/k0sAxE0u+pj/zKZX+o5wB+ML5mRayOxFA==, tarball: https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.0.0.tgz}
-
mdast-util-phrasing@4.1.0:
resolution: {integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==, tarball: https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz}
mdast-util-to-hast@13.2.0:
resolution: {integrity: sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==, tarball: https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.0.tgz}
- mdast-util-to-markdown@2.1.0:
- resolution: {integrity: sha512-SR2VnIEdVNCJbP6y7kVTJgPLifdr8WEU440fQec7qHoHOUz/oJ2jmNRqdDQ3rbiStOXb2mCDGTuwsK5OPUgYlQ==, tarball: https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.0.tgz}
-
mdast-util-to-markdown@2.1.2:
resolution: {integrity: sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==, tarball: https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.2.tgz}
@@ -5002,144 +4984,87 @@ packages:
resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==, tarball: https://registry.npmjs.org/methods/-/methods-1.1.2.tgz}
engines: {node: '>= 0.6'}
- micromark-core-commonmark@2.0.0:
- resolution: {integrity: sha512-jThOz/pVmAYUtkroV3D5c1osFXAMv9e0ypGDOIZuCeAe91/sD6BoE2Sjzt30yuXtwOYUmySOhMas/PVyh02itA==, tarball: https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.0.tgz}
-
micromark-core-commonmark@2.0.3:
resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==, tarball: https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz}
- micromark-extension-gfm-autolink-literal@2.0.0:
- resolution: {integrity: sha512-rTHfnpt/Q7dEAK1Y5ii0W8bhfJlVJFnJMHIPisfPK3gpVNuOP0VnRl96+YJ3RYWV/P4gFeQoGKNlT3RhuvpqAg==, tarball: https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.0.0.tgz}
+ micromark-extension-gfm-autolink-literal@2.1.0:
+ resolution: {integrity: sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==, tarball: https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz}
- micromark-extension-gfm-footnote@2.0.0:
- resolution: {integrity: sha512-6Rzu0CYRKDv3BfLAUnZsSlzx3ak6HAoI85KTiijuKIz5UxZxbUI+pD6oHgw+6UtQuiRwnGRhzMmPRv4smcz0fg==, tarball: https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.0.0.tgz}
+ micromark-extension-gfm-footnote@2.1.0:
+ resolution: {integrity: sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==, tarball: https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz}
- micromark-extension-gfm-strikethrough@2.0.0:
- resolution: {integrity: sha512-c3BR1ClMp5fxxmwP6AoOY2fXO9U8uFMKs4ADD66ahLTNcwzSCyRVU4k7LPV5Nxo/VJiR4TdzxRQY2v3qIUceCw==, tarball: https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.0.0.tgz}
+ micromark-extension-gfm-strikethrough@2.1.0:
+ resolution: {integrity: sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==, tarball: https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.1.0.tgz}
- micromark-extension-gfm-table@2.0.0:
- resolution: {integrity: sha512-PoHlhypg1ItIucOaHmKE8fbin3vTLpDOUg8KAr8gRCF1MOZI9Nquq2i/44wFvviM4WuxJzc3demT8Y3dkfvYrw==, tarball: https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.0.0.tgz}
+ micromark-extension-gfm-table@2.1.1:
+ resolution: {integrity: sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==, tarball: https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.1.tgz}
micromark-extension-gfm-tagfilter@2.0.0:
resolution: {integrity: sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==, tarball: https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz}
- micromark-extension-gfm-task-list-item@2.0.1:
- resolution: {integrity: sha512-cY5PzGcnULaN5O7T+cOzfMoHjBW7j+T9D2sucA5d/KbsBTPcYdebm9zUd9zzdgJGCwahV+/W78Z3nbulBYVbTw==, tarball: https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.0.1.tgz}
+ micromark-extension-gfm-task-list-item@2.1.0:
+ resolution: {integrity: sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==, tarball: https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.1.0.tgz}
micromark-extension-gfm@3.0.0:
resolution: {integrity: sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==, tarball: https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz}
- micromark-factory-destination@2.0.0:
- resolution: {integrity: sha512-j9DGrQLm/Uhl2tCzcbLhy5kXsgkHUrjJHg4fFAeoMRwJmJerT9aw4FEhIbZStWN8A3qMwOp1uzHr4UL8AInxtA==, tarball: https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.0.tgz}
-
micromark-factory-destination@2.0.1:
resolution: {integrity: sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==, tarball: https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz}
- micromark-factory-label@2.0.0:
- resolution: {integrity: sha512-RR3i96ohZGde//4WSe/dJsxOX6vxIg9TimLAS3i4EhBAFx8Sm5SmqVfR8E87DPSR31nEAjZfbt91OMZWcNgdZw==, tarball: https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.0.tgz}
-
micromark-factory-label@2.0.1:
resolution: {integrity: sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==, tarball: https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz}
- micromark-factory-space@2.0.0:
- resolution: {integrity: sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==, tarball: https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz}
-
micromark-factory-space@2.0.1:
resolution: {integrity: sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==, tarball: https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz}
- micromark-factory-title@2.0.0:
- resolution: {integrity: sha512-jY8CSxmpWLOxS+t8W+FG3Xigc0RDQA9bKMY/EwILvsesiRniiVMejYTE4wumNc2f4UbAa4WsHqe3J1QS1sli+A==, tarball: https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.0.tgz}
-
micromark-factory-title@2.0.1:
resolution: {integrity: sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==, tarball: https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz}
- micromark-factory-whitespace@2.0.0:
- resolution: {integrity: sha512-28kbwaBjc5yAI1XadbdPYHX/eDnqaUFVikLwrO7FDnKG7lpgxnvk/XGRhX/PN0mOZ+dBSZ+LgunHS+6tYQAzhA==, tarball: https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.0.tgz}
-
micromark-factory-whitespace@2.0.1:
resolution: {integrity: sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==, tarball: https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz}
- micromark-util-character@2.0.1:
- resolution: {integrity: sha512-3wgnrmEAJ4T+mGXAUfMvMAbxU9RDG43XmGce4j6CwPtVxB3vfwXSZ6KhFwDzZ3mZHhmPimMAXg71veiBGzeAZw==, tarball: https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.0.1.tgz}
-
micromark-util-character@2.1.1:
resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==, tarball: https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz}
- micromark-util-chunked@2.0.0:
- resolution: {integrity: sha512-anK8SWmNphkXdaKgz5hJvGa7l00qmcaUQoMYsBwDlSKFKjc6gjGXPDw3FNL3Nbwq5L8gE+RCbGqTw49FK5Qyvg==, tarball: https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.0.tgz}
-
micromark-util-chunked@2.0.1:
resolution: {integrity: sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==, tarball: https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz}
- micromark-util-classify-character@2.0.0:
- resolution: {integrity: sha512-S0ze2R9GH+fu41FA7pbSqNWObo/kzwf8rN/+IGlW/4tC6oACOs8B++bh+i9bVyNnwCcuksbFwsBme5OCKXCwIw==, tarball: https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.0.tgz}
-
micromark-util-classify-character@2.0.1:
resolution: {integrity: sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==, tarball: https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz}
- micromark-util-combine-extensions@2.0.0:
- resolution: {integrity: sha512-vZZio48k7ON0fVS3CUgFatWHoKbbLTK/rT7pzpJ4Bjp5JjkZeasRfrS9wsBdDJK2cJLHMckXZdzPSSr1B8a4oQ==, tarball: https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.0.tgz}
-
micromark-util-combine-extensions@2.0.1:
resolution: {integrity: sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==, tarball: https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz}
- micromark-util-decode-numeric-character-reference@2.0.1:
- resolution: {integrity: sha512-bmkNc7z8Wn6kgjZmVHOX3SowGmVdhYS7yBpMnuMnPzDq/6xwVA604DuOXMZTO1lvq01g+Adfa0pE2UKGlxL1XQ==, tarball: https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.1.tgz}
-
micromark-util-decode-numeric-character-reference@2.0.2:
resolution: {integrity: sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==, tarball: https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz}
- micromark-util-decode-string@2.0.0:
- resolution: {integrity: sha512-r4Sc6leeUTn3P6gk20aFMj2ntPwn6qpDZqWvYmAG6NgvFTIlj4WtrAudLi65qYoaGdXYViXYw2pkmn7QnIFasA==, tarball: https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.0.tgz}
-
micromark-util-decode-string@2.0.1:
resolution: {integrity: sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==, tarball: https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.1.tgz}
micromark-util-encode@2.0.1:
resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==, tarball: https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz}
- micromark-util-html-tag-name@2.0.0:
- resolution: {integrity: sha512-xNn4Pqkj2puRhKdKTm8t1YHC/BAjx6CEwRFXntTaRf/x16aqka6ouVoutm+QdkISTlT7e2zU7U4ZdlDLJd2Mcw==, tarball: https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.0.tgz}
-
micromark-util-html-tag-name@2.0.1:
resolution: {integrity: sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==, tarball: https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz}
- micromark-util-normalize-identifier@2.0.0:
- resolution: {integrity: sha512-2xhYT0sfo85FMrUPtHcPo2rrp1lwbDEEzpx7jiH2xXJLqBuy4H0GgXk5ToU8IEwoROtXuL8ND0ttVa4rNqYK3w==, tarball: https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.0.tgz}
-
micromark-util-normalize-identifier@2.0.1:
resolution: {integrity: sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==, tarball: https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz}
- micromark-util-resolve-all@2.0.0:
- resolution: {integrity: sha512-6KU6qO7DZ7GJkaCgwBNtplXCvGkJToU86ybBAUdavvgsCiG8lSSvYxr9MhwmQ+udpzywHsl4RpGJsYWG1pDOcA==, tarball: https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.0.tgz}
-
micromark-util-resolve-all@2.0.1:
resolution: {integrity: sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==, tarball: https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz}
micromark-util-sanitize-uri@2.0.1:
resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==, tarball: https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz}
- micromark-util-subtokenize@2.0.0:
- resolution: {integrity: sha512-vc93L1t+gpR3p8jxeVdaYlbV2jTYteDje19rNSS/H5dlhxUYll5Fy6vJ2cDwP8RnsXi818yGty1ayP55y3W6fg==, tarball: https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.0.0.tgz}
-
micromark-util-subtokenize@2.1.0:
resolution: {integrity: sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==, tarball: https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz}
- micromark-util-symbol@2.0.0:
- resolution: {integrity: sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==, tarball: https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz}
-
micromark-util-symbol@2.0.1:
resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==, tarball: https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz}
- micromark-util-types@2.0.0:
- resolution: {integrity: sha512-oNh6S2WMHWRZrmutsRmDDfkzKtxF+bc2VxLC9dvtrDIRFln627VsFP6fLMgTryGDljgLPjkrzQSDcPrjPyDJ5w==, tarball: https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.0.tgz}
-
micromark-util-types@2.0.2:
resolution: {integrity: sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==, tarball: https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz}
- micromark@4.0.0:
- resolution: {integrity: sha512-o/sd0nMof8kYff+TqcDx3VSrgBTcZpSvYcAHIfHhv5VAuNmisCxjhx6YmxS8PFEpb9z5WKWKPdzf0jM23ro3RQ==, tarball: https://registry.npmjs.org/micromark/-/micromark-4.0.0.tgz}
-
micromark@4.0.2:
resolution: {integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==, tarball: https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz}
@@ -5797,8 +5722,8 @@ packages:
resolution: {integrity: sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==, tarball: https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz}
engines: {node: '>= 0.4'}
- remark-gfm@4.0.0:
- resolution: {integrity: sha512-U92vJgBPkbw4Zfu/IiW2oTZLSL3Zpv+uI7My2eq8JxKgqraFdU8YUGicEJCEgSbeaG+QDFqIcwwfMTOEelPxuA==, tarball: https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.0.tgz}
+ remark-gfm@4.0.1:
+ resolution: {integrity: sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==, tarball: https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.1.tgz}
remark-parse@11.0.0:
resolution: {integrity: sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==, tarball: https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz}
@@ -6210,9 +6135,6 @@ packages:
trim-lines@3.0.1:
resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==, tarball: https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz}
- trough@2.1.0:
- resolution: {integrity: sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==, tarball: https://registry.npmjs.org/trough/-/trough-2.1.0.tgz}
-
trough@2.2.0:
resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==, tarball: https://registry.npmjs.org/trough/-/trough-2.2.0.tgz}
@@ -6324,9 +6246,6 @@ packages:
resolution: {integrity: sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==, tarball: https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz}
engines: {node: '>=18'}
- unified@11.0.4:
- resolution: {integrity: sha512-apMPnyLjAX+ty4OrNap7yumyVAMlKx5IWU2wlzzUdYJO9A8f1p9m/gywF/GM2ZDFcjQPrx59Mc90KwmxsoklxQ==, tarball: https://registry.npmjs.org/unified/-/unified-11.0.4.tgz}
-
unified@11.0.5:
resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==, tarball: https://registry.npmjs.org/unified/-/unified-11.0.5.tgz}
@@ -9122,10 +9041,6 @@ snapshots:
'@types/lodash@4.17.20': {}
- '@types/mdast@4.0.3':
- dependencies:
- '@types/unist': 3.0.2
-
'@types/mdast@4.0.4':
dependencies:
'@types/unist': 3.0.3
@@ -9242,8 +9157,6 @@ snapshots:
'@types/unist@2.0.11': {}
- '@types/unist@3.0.2': {}
-
'@types/unist@3.0.3': {}
'@types/uuid@9.0.2': {}
@@ -9914,10 +9827,6 @@ snapshots:
decimal.js@10.4.3: {}
- decode-named-character-reference@1.0.2:
- dependencies:
- character-entities: 2.0.2
-
decode-named-character-reference@1.2.0:
dependencies:
character-entities: 2.0.2
@@ -11462,36 +11371,19 @@ snapshots:
dependencies:
tmpl: 1.0.5
- markdown-table@3.0.3: {}
+ markdown-table@3.0.4: {}
material-colors@1.2.6: {}
math-intrinsics@1.1.0: {}
- mdast-util-find-and-replace@3.0.1:
+ mdast-util-find-and-replace@3.0.2:
dependencies:
'@types/mdast': 4.0.4
escape-string-regexp: 5.0.0
unist-util-is: 6.0.0
unist-util-visit-parents: 6.0.1
- mdast-util-from-markdown@2.0.0:
- dependencies:
- '@types/mdast': 4.0.4
- '@types/unist': 3.0.3
- decode-named-character-reference: 1.0.2
- devlop: 1.1.0
- mdast-util-to-string: 4.0.0
- micromark: 4.0.0
- micromark-util-decode-numeric-character-reference: 2.0.1
- micromark-util-decode-string: 2.0.0
- micromark-util-normalize-identifier: 2.0.0
- micromark-util-symbol: 2.0.0
- micromark-util-types: 2.0.2
- unist-util-stringify-position: 4.0.0
- transitivePeerDependencies:
- - supports-color
-
mdast-util-from-markdown@2.0.2:
dependencies:
'@types/mdast': 4.0.4
@@ -11509,21 +11401,21 @@ snapshots:
transitivePeerDependencies:
- supports-color
- mdast-util-gfm-autolink-literal@2.0.0:
+ mdast-util-gfm-autolink-literal@2.0.1:
dependencies:
'@types/mdast': 4.0.4
ccount: 2.0.1
devlop: 1.1.0
- mdast-util-find-and-replace: 3.0.1
- micromark-util-character: 2.0.1
+ mdast-util-find-and-replace: 3.0.2
+ micromark-util-character: 2.1.1
- mdast-util-gfm-footnote@2.0.0:
+ mdast-util-gfm-footnote@2.1.0:
dependencies:
'@types/mdast': 4.0.4
devlop: 1.1.0
mdast-util-from-markdown: 2.0.2
- mdast-util-to-markdown: 2.1.0
- micromark-util-normalize-identifier: 2.0.0
+ mdast-util-to-markdown: 2.1.2
+ micromark-util-normalize-identifier: 2.0.1
transitivePeerDependencies:
- supports-color
@@ -11531,7 +11423,7 @@ snapshots:
dependencies:
'@types/mdast': 4.0.4
mdast-util-from-markdown: 2.0.2
- mdast-util-to-markdown: 2.1.0
+ mdast-util-to-markdown: 2.1.2
transitivePeerDependencies:
- supports-color
@@ -11539,9 +11431,9 @@ snapshots:
dependencies:
'@types/mdast': 4.0.4
devlop: 1.1.0
- markdown-table: 3.0.3
+ markdown-table: 3.0.4
mdast-util-from-markdown: 2.0.2
- mdast-util-to-markdown: 2.1.0
+ mdast-util-to-markdown: 2.1.2
transitivePeerDependencies:
- supports-color
@@ -11550,19 +11442,19 @@ snapshots:
'@types/mdast': 4.0.4
devlop: 1.1.0
mdast-util-from-markdown: 2.0.2
- mdast-util-to-markdown: 2.1.0
+ mdast-util-to-markdown: 2.1.2
transitivePeerDependencies:
- supports-color
- mdast-util-gfm@3.0.0:
+ mdast-util-gfm@3.1.0:
dependencies:
- mdast-util-from-markdown: 2.0.0
- mdast-util-gfm-autolink-literal: 2.0.0
- mdast-util-gfm-footnote: 2.0.0
+ mdast-util-from-markdown: 2.0.2
+ mdast-util-gfm-autolink-literal: 2.0.1
+ mdast-util-gfm-footnote: 2.1.0
mdast-util-gfm-strikethrough: 2.0.0
mdast-util-gfm-table: 2.0.0
mdast-util-gfm-task-list-item: 2.0.0
- mdast-util-to-markdown: 2.1.0
+ mdast-util-to-markdown: 2.1.2
transitivePeerDependencies:
- supports-color
@@ -11605,11 +11497,6 @@ snapshots:
transitivePeerDependencies:
- supports-color
- mdast-util-phrasing@4.0.0:
- dependencies:
- '@types/mdast': 4.0.4
- unist-util-is: 6.0.0
-
mdast-util-phrasing@4.1.0:
dependencies:
'@types/mdast': 4.0.4
@@ -11627,17 +11514,6 @@ snapshots:
unist-util-visit: 5.0.0
vfile: 6.0.3
- mdast-util-to-markdown@2.1.0:
- dependencies:
- '@types/mdast': 4.0.4
- '@types/unist': 3.0.3
- longest-streak: 3.1.0
- mdast-util-phrasing: 4.0.0
- mdast-util-to-string: 4.0.0
- micromark-util-decode-string: 2.0.0
- unist-util-visit: 5.0.0
- zwitch: 2.0.4
-
mdast-util-to-markdown@2.1.2:
dependencies:
'@types/mdast': 4.0.4
@@ -11666,25 +11542,6 @@ snapshots:
methods@1.1.2: {}
- micromark-core-commonmark@2.0.0:
- dependencies:
- decode-named-character-reference: 1.2.0
- devlop: 1.1.0
- micromark-factory-destination: 2.0.0
- micromark-factory-label: 2.0.0
- micromark-factory-space: 2.0.0
- micromark-factory-title: 2.0.0
- micromark-factory-whitespace: 2.0.0
- micromark-util-character: 2.1.1
- micromark-util-chunked: 2.0.0
- micromark-util-classify-character: 2.0.0
- micromark-util-html-tag-name: 2.0.0
- micromark-util-normalize-identifier: 2.0.1
- micromark-util-resolve-all: 2.0.0
- micromark-util-subtokenize: 2.0.0
- micromark-util-symbol: 2.0.1
- micromark-util-types: 2.0.2
-
micromark-core-commonmark@2.0.3:
dependencies:
decode-named-character-reference: 1.2.0
@@ -11704,68 +11561,62 @@ snapshots:
micromark-util-symbol: 2.0.1
micromark-util-types: 2.0.2
- micromark-extension-gfm-autolink-literal@2.0.0:
+ micromark-extension-gfm-autolink-literal@2.1.0:
dependencies:
- micromark-util-character: 2.0.1
+ micromark-util-character: 2.1.1
micromark-util-sanitize-uri: 2.0.1
- micromark-util-symbol: 2.0.0
+ micromark-util-symbol: 2.0.1
micromark-util-types: 2.0.2
- micromark-extension-gfm-footnote@2.0.0:
+ micromark-extension-gfm-footnote@2.1.0:
dependencies:
devlop: 1.1.0
- micromark-core-commonmark: 2.0.0
- micromark-factory-space: 2.0.0
- micromark-util-character: 2.0.1
- micromark-util-normalize-identifier: 2.0.0
+ micromark-core-commonmark: 2.0.3
+ micromark-factory-space: 2.0.1
+ micromark-util-character: 2.1.1
+ micromark-util-normalize-identifier: 2.0.1
micromark-util-sanitize-uri: 2.0.1
- micromark-util-symbol: 2.0.0
+ micromark-util-symbol: 2.0.1
micromark-util-types: 2.0.2
- micromark-extension-gfm-strikethrough@2.0.0:
+ micromark-extension-gfm-strikethrough@2.1.0:
dependencies:
devlop: 1.1.0
- micromark-util-chunked: 2.0.0
- micromark-util-classify-character: 2.0.0
- micromark-util-resolve-all: 2.0.0
- micromark-util-symbol: 2.0.0
+ micromark-util-chunked: 2.0.1
+ micromark-util-classify-character: 2.0.1
+ micromark-util-resolve-all: 2.0.1
+ micromark-util-symbol: 2.0.1
micromark-util-types: 2.0.2
- micromark-extension-gfm-table@2.0.0:
+ micromark-extension-gfm-table@2.1.1:
dependencies:
devlop: 1.1.0
- micromark-factory-space: 2.0.0
- micromark-util-character: 2.0.1
- micromark-util-symbol: 2.0.0
+ micromark-factory-space: 2.0.1
+ micromark-util-character: 2.1.1
+ micromark-util-symbol: 2.0.1
micromark-util-types: 2.0.2
micromark-extension-gfm-tagfilter@2.0.0:
dependencies:
micromark-util-types: 2.0.2
- micromark-extension-gfm-task-list-item@2.0.1:
+ micromark-extension-gfm-task-list-item@2.1.0:
dependencies:
devlop: 1.1.0
- micromark-factory-space: 2.0.0
- micromark-util-character: 2.0.1
- micromark-util-symbol: 2.0.0
+ micromark-factory-space: 2.0.1
+ micromark-util-character: 2.1.1
+ micromark-util-symbol: 2.0.1
micromark-util-types: 2.0.2
micromark-extension-gfm@3.0.0:
dependencies:
- micromark-extension-gfm-autolink-literal: 2.0.0
- micromark-extension-gfm-footnote: 2.0.0
- micromark-extension-gfm-strikethrough: 2.0.0
- micromark-extension-gfm-table: 2.0.0
+ micromark-extension-gfm-autolink-literal: 2.1.0
+ micromark-extension-gfm-footnote: 2.1.0
+ micromark-extension-gfm-strikethrough: 2.1.0
+ micromark-extension-gfm-table: 2.1.1
micromark-extension-gfm-tagfilter: 2.0.0
- micromark-extension-gfm-task-list-item: 2.0.1
- micromark-util-combine-extensions: 2.0.0
- micromark-util-types: 2.0.0
-
- micromark-factory-destination@2.0.0:
- dependencies:
- micromark-util-character: 2.1.1
- micromark-util-symbol: 2.0.1
+ micromark-extension-gfm-task-list-item: 2.1.0
+ micromark-util-combine-extensions: 2.0.1
micromark-util-types: 2.0.2
micromark-factory-destination@2.0.1:
@@ -11774,13 +11625,6 @@ snapshots:
micromark-util-symbol: 2.0.1
micromark-util-types: 2.0.2
- micromark-factory-label@2.0.0:
- dependencies:
- devlop: 1.1.0
- micromark-util-character: 2.1.1
- micromark-util-symbol: 2.0.1
- micromark-util-types: 2.0.2
-
micromark-factory-label@2.0.1:
dependencies:
devlop: 1.1.0
@@ -11788,23 +11632,11 @@ snapshots:
micromark-util-symbol: 2.0.1
micromark-util-types: 2.0.2
- micromark-factory-space@2.0.0:
- dependencies:
- micromark-util-character: 2.1.1
- micromark-util-types: 2.0.2
-
micromark-factory-space@2.0.1:
dependencies:
micromark-util-character: 2.1.1
micromark-util-types: 2.0.2
- micromark-factory-title@2.0.0:
- dependencies:
- micromark-factory-space: 2.0.1
- micromark-util-character: 2.1.1
- micromark-util-symbol: 2.0.1
- micromark-util-types: 2.0.2
-
micromark-factory-title@2.0.1:
dependencies:
micromark-factory-space: 2.0.1
@@ -11812,13 +11644,6 @@ snapshots:
micromark-util-symbol: 2.0.1
micromark-util-types: 2.0.2
- micromark-factory-whitespace@2.0.0:
- dependencies:
- micromark-factory-space: 2.0.1
- micromark-util-character: 2.1.1
- micromark-util-symbol: 2.0.1
- micromark-util-types: 2.0.2
-
micromark-factory-whitespace@2.0.1:
dependencies:
micromark-factory-space: 2.0.1
@@ -11826,61 +11651,30 @@ snapshots:
micromark-util-symbol: 2.0.1
micromark-util-types: 2.0.2
- micromark-util-character@2.0.1:
- dependencies:
- micromark-util-symbol: 2.0.1
- micromark-util-types: 2.0.2
-
micromark-util-character@2.1.1:
dependencies:
micromark-util-symbol: 2.0.1
micromark-util-types: 2.0.2
- micromark-util-chunked@2.0.0:
- dependencies:
- micromark-util-symbol: 2.0.1
-
micromark-util-chunked@2.0.1:
dependencies:
micromark-util-symbol: 2.0.1
- micromark-util-classify-character@2.0.0:
- dependencies:
- micromark-util-character: 2.1.1
- micromark-util-symbol: 2.0.1
- micromark-util-types: 2.0.2
-
micromark-util-classify-character@2.0.1:
dependencies:
micromark-util-character: 2.1.1
micromark-util-symbol: 2.0.1
micromark-util-types: 2.0.2
- micromark-util-combine-extensions@2.0.0:
- dependencies:
- micromark-util-chunked: 2.0.0
- micromark-util-types: 2.0.2
-
micromark-util-combine-extensions@2.0.1:
dependencies:
micromark-util-chunked: 2.0.1
micromark-util-types: 2.0.2
- micromark-util-decode-numeric-character-reference@2.0.1:
- dependencies:
- micromark-util-symbol: 2.0.1
-
micromark-util-decode-numeric-character-reference@2.0.2:
dependencies:
micromark-util-symbol: 2.0.1
- micromark-util-decode-string@2.0.0:
- dependencies:
- decode-named-character-reference: 1.2.0
- micromark-util-character: 2.1.1
- micromark-util-decode-numeric-character-reference: 2.0.2
- micromark-util-symbol: 2.0.1
-
micromark-util-decode-string@2.0.1:
dependencies:
decode-named-character-reference: 1.2.0
@@ -11890,22 +11684,12 @@ snapshots:
micromark-util-encode@2.0.1: {}
- micromark-util-html-tag-name@2.0.0: {}
-
micromark-util-html-tag-name@2.0.1: {}
- micromark-util-normalize-identifier@2.0.0:
- dependencies:
- micromark-util-symbol: 2.0.1
-
micromark-util-normalize-identifier@2.0.1:
dependencies:
micromark-util-symbol: 2.0.1
- micromark-util-resolve-all@2.0.0:
- dependencies:
- micromark-util-types: 2.0.2
-
micromark-util-resolve-all@2.0.1:
dependencies:
micromark-util-types: 2.0.2
@@ -11916,13 +11700,6 @@ snapshots:
micromark-util-encode: 2.0.1
micromark-util-symbol: 2.0.1
- micromark-util-subtokenize@2.0.0:
- dependencies:
- devlop: 1.1.0
- micromark-util-chunked: 2.0.1
- micromark-util-symbol: 2.0.1
- micromark-util-types: 2.0.2
-
micromark-util-subtokenize@2.1.0:
dependencies:
devlop: 1.1.0
@@ -11930,36 +11707,10 @@ snapshots:
micromark-util-symbol: 2.0.1
micromark-util-types: 2.0.2
- micromark-util-symbol@2.0.0: {}
-
micromark-util-symbol@2.0.1: {}
- micromark-util-types@2.0.0: {}
-
micromark-util-types@2.0.2: {}
- micromark@4.0.0:
- dependencies:
- '@types/debug': 4.1.12
- debug: 4.4.3
- decode-named-character-reference: 1.2.0
- devlop: 1.1.0
- micromark-core-commonmark: 2.0.0
- micromark-factory-space: 2.0.0
- micromark-util-character: 2.1.1
- micromark-util-chunked: 2.0.0
- micromark-util-combine-extensions: 2.0.0
- micromark-util-decode-numeric-character-reference: 2.0.2
- micromark-util-encode: 2.0.1
- micromark-util-normalize-identifier: 2.0.1
- micromark-util-resolve-all: 2.0.0
- micromark-util-sanitize-uri: 2.0.1
- micromark-util-subtokenize: 2.0.0
- micromark-util-symbol: 2.0.1
- micromark-util-types: 2.0.2
- transitivePeerDependencies:
- - supports-color
-
micromark@4.0.2:
dependencies:
'@types/debug': 4.1.12
@@ -12684,14 +12435,14 @@ snapshots:
define-properties: 1.2.1
set-function-name: 2.0.1
- remark-gfm@4.0.0:
+ remark-gfm@4.0.1:
dependencies:
- '@types/mdast': 4.0.3
- mdast-util-gfm: 3.0.0
+ '@types/mdast': 4.0.4
+ mdast-util-gfm: 3.1.0
micromark-extension-gfm: 3.0.0
remark-parse: 11.0.0
remark-stringify: 11.0.0
- unified: 11.0.4
+ unified: 11.0.5
transitivePeerDependencies:
- supports-color
@@ -12715,7 +12466,7 @@ snapshots:
remark-stringify@11.0.0:
dependencies:
'@types/mdast': 4.0.4
- mdast-util-to-markdown: 2.1.0
+ mdast-util-to-markdown: 2.1.2
unified: 11.0.5
require-directory@2.1.1: {}
@@ -13166,8 +12917,6 @@ snapshots:
trim-lines@3.0.1: {}
- trough@2.1.0: {}
-
trough@2.2.0: {}
ts-dedent@2.2.0: {}
@@ -13264,16 +13013,6 @@ snapshots:
unicorn-magic@0.3.0: {}
- unified@11.0.4:
- dependencies:
- '@types/unist': 3.0.2
- bail: 2.0.2
- devlop: 1.1.0
- extend: 3.0.2
- is-plain-obj: 4.1.0
- trough: 2.1.0
- vfile: 6.0.3
-
unified@11.0.5:
dependencies:
'@types/unist': 3.0.3
From 41420aea3c1636e86d92d99b9b41bf68f4fe5b60 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 1 Oct 2025 23:11:11 +0000
Subject: [PATCH 034/298] chore: bump ts-proto from 1.164.0 to 1.181.2 in /site
(#20080)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Bumps [ts-proto](https://github.com/stephenh/ts-proto) from 1.164.0 to
1.181.2.
Release notes
Sourced from ts-proto's
releases .
v1.181.2
Bug Fixes
toJSON Function with removeEnumPrefix=true and
unrecognizedEnumValue=0 Options (#1089 )
(2401490 ),
closes #1086
#1086
v1.181.1
Bug Fixes
Incorrect message names in the generated code for repeated fields
(#1073 )
(8a95d8e ),
closes #1072
v1.181.0
Features
v1.180.0
Features
oneof=unions-value to use the same field name for oneof cases (#1062 )
(7493090 ),
closes #1060
v1.179.0
Features
v1.178.0
Features
no-file-descriptor setting for outputSchema option (#1047 )
(c54f06c )
v1.177.0
... (truncated)
Changelog
Sourced from ts-proto's
changelog .
Bug Fixes
toJSON Function with removeEnumPrefix=true and
unrecognizedEnumValue=0 Options (#1089 )
(2401490 ),
closes #1086
#1086
Bug Fixes
Incorrect message names in the generated code for repeated fields
(#1073 )
(8a95d8e ),
closes #1072
Features
Features
oneof=unions-value to use the same field name for oneof cases (#1062 )
(7493090 ),
closes #1060
Features
Features
no-file-descriptor setting for outputSchema option (#1047 )
(c54f06c )
Features
... (truncated)
Commits
290d0c5
chore(release): 1.181.2 [skip ci]
2401490
fix: toJSON Function with removeEnumPrefix=true and
`unrecognizedEnumValue=...
76243a8
chore(release): 1.181.1 [skip ci]
8a95d8e
fix: Incorrect message names in the generated code for repeated fields
(#1073 )
2078d1a
Remove .DS_Store (#1071 )
c5546fb
chore(release): 1.181.0 [skip ci]
ab515cd
feat: added the "typePrefix" and "typeSuffix"
options. (#1069 )
14e7e0f
docs: Describe oneof=unions-value output as Algebraic Data
Type (#1065 )
84ccaf2
chore(release): 1.180.0 [skip ci]
7493090
feat: oneof=unions-value to use the same field name for oneof cases (#1062 )
Additional commits viewable in compare
view
[](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
---------
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: ケイラ
---
.../e2e/google/protobuf/timestampGenerated.ts | 6 ++
site/e2e/provisionerGenerated.ts | 62 ++++++++++---------
site/package.json | 2 +-
site/pnpm-lock.yaml | 33 +++++-----
4 files changed, 60 insertions(+), 43 deletions(-)
diff --git a/site/e2e/google/protobuf/timestampGenerated.ts b/site/e2e/google/protobuf/timestampGenerated.ts
index 6dd4b08e96087..6cddbb0b0b781 100644
--- a/site/e2e/google/protobuf/timestampGenerated.ts
+++ b/site/e2e/google/protobuf/timestampGenerated.ts
@@ -1,3 +1,9 @@
+// Code generated by protoc-gen-ts_proto. DO NOT EDIT.
+// versions:
+// protoc-gen-ts_proto v1.181.2
+// protoc v4.23.4
+// source: google/protobuf/timestamp.proto
+
/* eslint-disable */
import * as _m0 from "protobufjs/minimal";
diff --git a/site/e2e/provisionerGenerated.ts b/site/e2e/provisionerGenerated.ts
index 82fd25db9258d..65e0557c1b779 100644
--- a/site/e2e/provisionerGenerated.ts
+++ b/site/e2e/provisionerGenerated.ts
@@ -1,3 +1,9 @@
+// Code generated by protoc-gen-ts_proto. DO NOT EDIT.
+// versions:
+// protoc-gen-ts_proto v1.181.2
+// protoc v4.23.4
+// source: provisioner.proto
+
/* eslint-disable */
import * as _m0 from "protobufjs/minimal";
import { Observable } from "rxjs";
@@ -560,10 +566,10 @@ export const TemplateVariable = {
if (message.defaultValue !== "") {
writer.uint32(34).string(message.defaultValue);
}
- if (message.required === true) {
+ if (message.required !== false) {
writer.uint32(40).bool(message.required);
}
- if (message.sensitive === true) {
+ if (message.sensitive !== false) {
writer.uint32(48).bool(message.sensitive);
}
return writer;
@@ -599,7 +605,7 @@ export const RichParameter = {
if (message.type !== "") {
writer.uint32(26).string(message.type);
}
- if (message.mutable === true) {
+ if (message.mutable !== false) {
writer.uint32(32).bool(message.mutable);
}
if (message.defaultValue !== "") {
@@ -626,7 +632,7 @@ export const RichParameter = {
if (message.validationMonotonic !== "") {
writer.uint32(98).string(message.validationMonotonic);
}
- if (message.required === true) {
+ if (message.required !== false) {
writer.uint32(104).bool(message.required);
}
if (message.displayName !== "") {
@@ -635,7 +641,7 @@ export const RichParameter = {
if (message.order !== 0) {
writer.uint32(128).int32(message.order);
}
- if (message.ephemeral === true) {
+ if (message.ephemeral !== false) {
writer.uint32(136).bool(message.ephemeral);
}
if (message.formType !== 0) {
@@ -716,7 +722,7 @@ export const Preset = {
if (message.prebuild !== undefined) {
Prebuild.encode(message.prebuild, writer.uint32(26).fork()).ldelim();
}
- if (message.default === true) {
+ if (message.default !== false) {
writer.uint32(32).bool(message.default);
}
if (message.description !== "") {
@@ -761,7 +767,7 @@ export const VariableValue = {
if (message.value !== "") {
writer.uint32(18).string(message.value);
}
- if (message.sensitive === true) {
+ if (message.sensitive !== false) {
writer.uint32(24).bool(message.sensitive);
}
return writer;
@@ -794,7 +800,7 @@ export const ExternalAuthProviderResource = {
if (message.id !== "") {
writer.uint32(10).string(message.id);
}
- if (message.optional === true) {
+ if (message.optional !== false) {
writer.uint32(16).bool(message.optional);
}
return writer;
@@ -929,7 +935,7 @@ export const ResourcesMonitoring = {
export const MemoryResourceMonitor = {
encode(message: MemoryResourceMonitor, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer {
- if (message.enabled === true) {
+ if (message.enabled !== false) {
writer.uint32(8).bool(message.enabled);
}
if (message.threshold !== 0) {
@@ -944,7 +950,7 @@ export const VolumeResourceMonitor = {
if (message.path !== "") {
writer.uint32(10).string(message.path);
}
- if (message.enabled === true) {
+ if (message.enabled !== false) {
writer.uint32(16).bool(message.enabled);
}
if (message.threshold !== 0) {
@@ -956,19 +962,19 @@ export const VolumeResourceMonitor = {
export const DisplayApps = {
encode(message: DisplayApps, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer {
- if (message.vscode === true) {
+ if (message.vscode !== false) {
writer.uint32(8).bool(message.vscode);
}
- if (message.vscodeInsiders === true) {
+ if (message.vscodeInsiders !== false) {
writer.uint32(16).bool(message.vscodeInsiders);
}
- if (message.webTerminal === true) {
+ if (message.webTerminal !== false) {
writer.uint32(24).bool(message.webTerminal);
}
- if (message.sshHelper === true) {
+ if (message.sshHelper !== false) {
writer.uint32(32).bool(message.sshHelper);
}
- if (message.portForwardingHelper === true) {
+ if (message.portForwardingHelper !== false) {
writer.uint32(40).bool(message.portForwardingHelper);
}
return writer;
@@ -1001,13 +1007,13 @@ export const Script = {
if (message.cron !== "") {
writer.uint32(34).string(message.cron);
}
- if (message.startBlocksLogin === true) {
+ if (message.startBlocksLogin !== false) {
writer.uint32(40).bool(message.startBlocksLogin);
}
- if (message.runOnStart === true) {
+ if (message.runOnStart !== false) {
writer.uint32(48).bool(message.runOnStart);
}
- if (message.runOnStop === true) {
+ if (message.runOnStop !== false) {
writer.uint32(56).bool(message.runOnStop);
}
if (message.timeoutSeconds !== 0) {
@@ -1052,7 +1058,7 @@ export const App = {
if (message.icon !== "") {
writer.uint32(42).string(message.icon);
}
- if (message.subdomain === true) {
+ if (message.subdomain !== false) {
writer.uint32(48).bool(message.subdomain);
}
if (message.healthcheck !== undefined) {
@@ -1061,13 +1067,13 @@ export const App = {
if (message.sharingLevel !== 0) {
writer.uint32(64).int32(message.sharingLevel);
}
- if (message.external === true) {
+ if (message.external !== false) {
writer.uint32(72).bool(message.external);
}
if (message.order !== 0) {
writer.uint32(80).int64(message.order);
}
- if (message.hidden === true) {
+ if (message.hidden !== false) {
writer.uint32(88).bool(message.hidden);
}
if (message.openIn !== 0) {
@@ -1115,7 +1121,7 @@ export const Resource = {
for (const v of message.metadata) {
Resource_Metadata.encode(v!, writer.uint32(34).fork()).ldelim();
}
- if (message.hide === true) {
+ if (message.hide !== false) {
writer.uint32(40).bool(message.hide);
}
if (message.icon !== "") {
@@ -1142,10 +1148,10 @@ export const Resource_Metadata = {
if (message.value !== "") {
writer.uint32(18).string(message.value);
}
- if (message.sensitive === true) {
+ if (message.sensitive !== false) {
writer.uint32(24).bool(message.sensitive);
}
- if (message.isNull === true) {
+ if (message.isNull !== false) {
writer.uint32(32).bool(message.isNull);
}
return writer;
@@ -1352,7 +1358,7 @@ export const PlanRequest = {
for (const v of message.previousParameterValues) {
RichParameterValue.encode(v!, writer.uint32(42).fork()).ldelim();
}
- if (message.omitModuleFiles === true) {
+ if (message.omitModuleFiles !== false) {
writer.uint32(48).bool(message.omitModuleFiles);
}
return writer;
@@ -1394,13 +1400,13 @@ export const PlanComplete = {
if (message.moduleFilesHash.length !== 0) {
writer.uint32(98).bytes(message.moduleFilesHash);
}
- if (message.hasAiTasks === true) {
+ if (message.hasAiTasks !== false) {
writer.uint32(104).bool(message.hasAiTasks);
}
for (const v of message.aiTasks) {
AITask.encode(v!, writer.uint32(114).fork()).ldelim();
}
- if (message.hasExternalAgents === true) {
+ if (message.hasExternalAgents !== false) {
writer.uint32(120).bool(message.hasExternalAgents);
}
return writer;
@@ -1571,7 +1577,7 @@ export interface Provisioner {
}
function toTimestamp(date: Date): Timestamp {
- const seconds = date.getTime() / 1_000;
+ const seconds = Math.trunc(date.getTime() / 1_000);
const nanos = (date.getTime() % 1_000) * 1_000_000;
return { seconds, nanos };
}
diff --git a/site/package.json b/site/package.json
index 7ba86b7881665..ddb04c084ce01 100644
--- a/site/package.json
+++ b/site/package.json
@@ -178,7 +178,7 @@
"storybook": "9.1.2",
"storybook-addon-remix-react-router": "5.0.0",
"tailwindcss": "3.4.18",
- "ts-proto": "1.164.0",
+ "ts-proto": "1.181.2",
"typescript": "5.6.3",
"vite": "7.1.7",
"vite-plugin-checker": "0.11.0"
diff --git a/site/pnpm-lock.yaml b/site/pnpm-lock.yaml
index 49f5c686087b8..396028241502c 100644
--- a/site/pnpm-lock.yaml
+++ b/site/pnpm-lock.yaml
@@ -444,8 +444,8 @@ importers:
specifier: 3.4.18
version: 3.4.18(yaml@2.7.0)
ts-proto:
- specifier: 1.164.0
- version: 1.164.0
+ specifier: 1.181.2
+ version: 1.181.2
typescript:
specifier: 5.6.3
version: 5.6.3
@@ -4863,6 +4863,9 @@ packages:
long@5.2.3:
resolution: {integrity: sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==, tarball: https://registry.npmjs.org/long/-/long-5.2.3.tgz}
+ long@5.3.2:
+ resolution: {integrity: sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==, tarball: https://registry.npmjs.org/long/-/long-5.3.2.tgz}
+
longest-streak@3.1.0:
resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==, tarball: https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz}
@@ -6159,14 +6162,14 @@ packages:
'@swc/wasm':
optional: true
- ts-poet@6.11.0:
- resolution: {integrity: sha512-r5AGF8vvb+GjBsnqiTqbLhN1/U2FJt6BI+k0dfCrkKzWvUhNlwMmq9nDHuucHs45LomgHjZPvYj96dD3JawjJA==, tarball: https://registry.npmjs.org/ts-poet/-/ts-poet-6.11.0.tgz}
+ ts-poet@6.12.0:
+ resolution: {integrity: sha512-xo+iRNMWqyvXpFTaOAvLPA5QAWO6TZrSUs5s4Odaya3epqofBu/fMLHEWl8jPmjhA0s9sgj9sNvF1BmaQlmQkA==, tarball: https://registry.npmjs.org/ts-poet/-/ts-poet-6.12.0.tgz}
- ts-proto-descriptors@1.15.0:
- resolution: {integrity: sha512-TYyJ7+H+7Jsqawdv+mfsEpZPTIj9siDHS6EMCzG/z3b/PZiphsX+mWtqFfFVe5/N0Th6V3elK9lQqjnrgTOfrg==, tarball: https://registry.npmjs.org/ts-proto-descriptors/-/ts-proto-descriptors-1.15.0.tgz}
+ ts-proto-descriptors@1.16.0:
+ resolution: {integrity: sha512-3yKuzMLpltdpcyQji1PJZRfoo4OJjNieKTYkQY8pF7xGKsYz/RHe3aEe4KiRxcinoBmnEhmuI+yJTxLb922ULA==, tarball: https://registry.npmjs.org/ts-proto-descriptors/-/ts-proto-descriptors-1.16.0.tgz}
- ts-proto@1.164.0:
- resolution: {integrity: sha512-yIyMucjcozS7Vxtyy5mH6C8ltbY4gEBVNW4ymZ0kWiKlyMxsvhyUZ63CbxcF7dCKQVjHR+fLJ3SiorfgyhQ+AQ==, tarball: https://registry.npmjs.org/ts-proto/-/ts-proto-1.164.0.tgz}
+ ts-proto@1.181.2:
+ resolution: {integrity: sha512-knJ8dtjn2Pd0c5ZGZG8z9DMiD4PUY8iGI9T9tb8DvGdWRMkLpf0WcPO7G+7cmbZyxvNTAG6ci3fybEaFgMZIvg==, tarball: https://registry.npmjs.org/ts-proto/-/ts-proto-1.181.2.tgz}
hasBin: true
tsconfig-paths@4.2.0:
@@ -11329,6 +11332,8 @@ snapshots:
long@5.2.3: {}
+ long@5.3.2: {}
+
longest-streak@3.1.0: {}
loose-envify@1.4.0:
@@ -12944,21 +12949,21 @@ snapshots:
'@swc/core': 1.3.38
optional: true
- ts-poet@6.11.0:
+ ts-poet@6.12.0:
dependencies:
dprint-node: 1.0.8
- ts-proto-descriptors@1.15.0:
+ ts-proto-descriptors@1.16.0:
dependencies:
- long: 5.2.3
+ long: 5.3.2
protobufjs: 7.4.0
- ts-proto@1.164.0:
+ ts-proto@1.181.2:
dependencies:
case-anything: 2.1.13
protobufjs: 7.4.0
- ts-poet: 6.11.0
- ts-proto-descriptors: 1.15.0
+ ts-poet: 6.12.0
+ ts-proto-descriptors: 1.16.0
tsconfig-paths@4.2.0:
dependencies:
From f84a789b40284e8c7f9192ac0cf2b6764a197b36 Mon Sep 17 00:00:00 2001
From: Ethan <39577870+ethanndickson@users.noreply.github.com>
Date: Thu, 2 Oct 2025 10:45:52 +1000
Subject: [PATCH 035/298] feat(scaletest): add runner for thundering herd
autostart (#19998)
Relates to https://github.com/coder/internal/issues/911
This PR adds a scaletest runner that simulates a user with a workspace configured to autostart at a specific time.
An instance of this autostart runner does the following:
1. Creates a user.
2. Creates a workspace.
3. Listens on `/api/v2/workspaces//watch` to wait for build completions throughout the run.
4. Stops the workspace, waits for the build to finish.
4. Waits for all other concurrently executing runners (per the `SetupBarrier` `WaitGroup`) to also have a stopped workspace.
5. Sets the workspace autostart time to `time.Now().Add(cfg.AutoStartDelay)`
6. Waits for the autostart workspace build to begin, enter the `pending` status, and then `running`.
7. Waits for the autostart workspace build to end.
Exposes four prometheus metrics:
- `autostart_job_creation_latency_seconds` - HistogramVec. Labels = {username, workspace_name}
- `autostart_job_acquired_latency_seconds` - HistogramVec. Labels = {username, workspace_name}
- `autostart_total_latency_seconds` - `HistogramVec`. Labels = `{username, workspace_name}`.
- `autostart_errors_total` - `CounterVec`. Labels = `{username, action}`.
---
scaletest/autostart/config.go | 75 +++++++++
scaletest/autostart/metrics.go | 65 ++++++++
scaletest/autostart/run.go | 245 +++++++++++++++++++++++++++++
scaletest/autostart/run_test.go | 158 +++++++++++++++++++
scaletest/workspacebuild/config.go | 3 +
scaletest/workspacebuild/run.go | 40 ++---
6 files changed, 568 insertions(+), 18 deletions(-)
create mode 100644 scaletest/autostart/config.go
create mode 100644 scaletest/autostart/metrics.go
create mode 100644 scaletest/autostart/run.go
create mode 100644 scaletest/autostart/run_test.go
diff --git a/scaletest/autostart/config.go b/scaletest/autostart/config.go
new file mode 100644
index 0000000000000..ad804a0b89666
--- /dev/null
+++ b/scaletest/autostart/config.go
@@ -0,0 +1,75 @@
+package autostart
+
+import (
+ "sync"
+ "time"
+
+ "golang.org/x/xerrors"
+
+ "github.com/coder/coder/v2/codersdk"
+ "github.com/coder/coder/v2/scaletest/createusers"
+ "github.com/coder/coder/v2/scaletest/workspacebuild"
+)
+
+type Config struct {
+ // User is the configuration for the user to create.
+ User createusers.Config `json:"user"`
+
+ // Workspace is the configuration for the workspace to create. The workspace
+ // will be built using the new user.
+ //
+ // OrganizationID is ignored and set to the new user's organization ID.
+ Workspace workspacebuild.Config `json:"workspace"`
+
+ // WorkspaceJobTimeout is how long to wait for any one workspace job
+ // (start or stop) to complete.
+ WorkspaceJobTimeout time.Duration `json:"workspace_job_timeout"`
+
+ // AutostartDelay is how long after all the workspaces have been stopped
+ // to schedule them to be started again.
+ AutostartDelay time.Duration `json:"autostart_delay"`
+
+ // AutostartTimeout is how long to wait for the autostart build to be
+ // initiated after the scheduled time.
+ AutostartTimeout time.Duration `json:"autostart_timeout"`
+
+ Metrics *Metrics `json:"-"`
+
+ // SetupBarrier is used to ensure all runners own stopped workspaces
+ // before setting the autostart schedule on each.
+ SetupBarrier *sync.WaitGroup `json:"-"`
+}
+
+func (c Config) Validate() error {
+ if err := c.User.Validate(); err != nil {
+ return xerrors.Errorf("user config: %w", err)
+ }
+ c.Workspace.OrganizationID = c.User.OrganizationID
+ // This value will be overwritten during the test.
+ c.Workspace.UserID = codersdk.Me
+ if err := c.Workspace.Validate(); err != nil {
+ return xerrors.Errorf("workspace config: %w", err)
+ }
+
+ if c.SetupBarrier == nil {
+ return xerrors.New("setup barrier must be set")
+ }
+
+ if c.WorkspaceJobTimeout <= 0 {
+ return xerrors.New("workspace_job_timeout must be greater than 0")
+ }
+
+ if c.AutostartDelay < time.Minute*2 {
+ return xerrors.New("autostart_delay must be at least 2 minutes")
+ }
+
+ if c.AutostartTimeout <= 0 {
+ return xerrors.New("autostart_timeout must be greater than 0")
+ }
+
+ if c.Metrics == nil {
+ return xerrors.New("metrics must be set")
+ }
+
+ return nil
+}
diff --git a/scaletest/autostart/metrics.go b/scaletest/autostart/metrics.go
new file mode 100644
index 0000000000000..d1ff94e7898c4
--- /dev/null
+++ b/scaletest/autostart/metrics.go
@@ -0,0 +1,65 @@
+package autostart
+
+import (
+ "time"
+
+ "github.com/prometheus/client_golang/prometheus"
+)
+
+type Metrics struct {
+ AutostartJobCreationLatencySeconds prometheus.HistogramVec
+ AutostartJobAcquiredLatencySeconds prometheus.HistogramVec
+ AutostartTotalLatencySeconds prometheus.HistogramVec
+ AutostartErrorsTotal prometheus.CounterVec
+}
+
+func NewMetrics(reg prometheus.Registerer) *Metrics {
+ m := &Metrics{
+ AutostartJobCreationLatencySeconds: *prometheus.NewHistogramVec(prometheus.HistogramOpts{
+ Namespace: "coderd",
+ Subsystem: "scaletest",
+ Name: "autostart_job_creation_latency_seconds",
+ Help: "Time from when the workspace is scheduled to be autostarted to when the autostart job has been created.",
+ }, []string{"username", "workspace_name"}),
+ AutostartJobAcquiredLatencySeconds: *prometheus.NewHistogramVec(prometheus.HistogramOpts{
+ Namespace: "coderd",
+ Subsystem: "scaletest",
+ Name: "autostart_job_acquired_latency_seconds",
+ Help: "Time from when the workspace is scheduled to be autostarted to when the job has been acquired by a provisioner daemon.",
+ }, []string{"username", "workspace_name"}),
+ AutostartTotalLatencySeconds: *prometheus.NewHistogramVec(prometheus.HistogramOpts{
+ Namespace: "coderd",
+ Subsystem: "scaletest",
+ Name: "autostart_total_latency_seconds",
+ Help: "Time from when the workspace is scheduled to be autostarted to when the autostart build has finished.",
+ }, []string{"username", "workspace_name"}),
+ AutostartErrorsTotal: *prometheus.NewCounterVec(prometheus.CounterOpts{
+ Namespace: "coderd",
+ Subsystem: "scaletest",
+ Name: "autostart_errors_total",
+ Help: "Total number of autostart errors",
+ }, []string{"username", "action"}),
+ }
+
+ reg.MustRegister(m.AutostartTotalLatencySeconds)
+ reg.MustRegister(m.AutostartJobCreationLatencySeconds)
+ reg.MustRegister(m.AutostartJobAcquiredLatencySeconds)
+ reg.MustRegister(m.AutostartErrorsTotal)
+ return m
+}
+
+func (m *Metrics) RecordCompletion(elapsed time.Duration, username string, workspace string) {
+ m.AutostartTotalLatencySeconds.WithLabelValues(username, workspace).Observe(elapsed.Seconds())
+}
+
+func (m *Metrics) RecordJobCreation(elapsed time.Duration, username string, workspace string) {
+ m.AutostartJobCreationLatencySeconds.WithLabelValues(username, workspace).Observe(elapsed.Seconds())
+}
+
+func (m *Metrics) RecordJobAcquired(elapsed time.Duration, username string, workspace string) {
+ m.AutostartJobAcquiredLatencySeconds.WithLabelValues(username, workspace).Observe(elapsed.Seconds())
+}
+
+func (m *Metrics) AddError(username string, action string) {
+ m.AutostartErrorsTotal.WithLabelValues(username, action).Inc()
+}
diff --git a/scaletest/autostart/run.go b/scaletest/autostart/run.go
new file mode 100644
index 0000000000000..59f50a04dd837
--- /dev/null
+++ b/scaletest/autostart/run.go
@@ -0,0 +1,245 @@
+package autostart
+
+import (
+ "context"
+ "fmt"
+ "io"
+ "time"
+
+ "golang.org/x/xerrors"
+
+ "cdr.dev/slog"
+ "cdr.dev/slog/sloggers/sloghuman"
+ "github.com/coder/coder/v2/coderd/tracing"
+ "github.com/coder/coder/v2/codersdk"
+ "github.com/coder/coder/v2/scaletest/createusers"
+ "github.com/coder/coder/v2/scaletest/harness"
+ "github.com/coder/coder/v2/scaletest/loadtestutil"
+ "github.com/coder/coder/v2/scaletest/workspacebuild"
+)
+
+type Runner struct {
+ client *codersdk.Client
+ cfg Config
+
+ createUserRunner *createusers.Runner
+ workspacebuildRunner *workspacebuild.Runner
+
+ autostartTotalLatency time.Duration
+ autostartJobCreationLatency time.Duration
+ autostartJobAcquiredLatency time.Duration
+}
+
+func NewRunner(client *codersdk.Client, cfg Config) *Runner {
+ return &Runner{
+ client: client,
+ cfg: cfg,
+ }
+}
+
+var (
+ _ harness.Runnable = &Runner{}
+ _ harness.Cleanable = &Runner{}
+ _ harness.Collectable = &Runner{}
+)
+
+func (r *Runner) Run(ctx context.Context, id string, logs io.Writer) error {
+ ctx, span := tracing.StartSpan(ctx)
+ defer span.End()
+
+ reachedBarrier := false
+ defer func() {
+ if !reachedBarrier {
+ r.cfg.SetupBarrier.Done()
+ }
+ }()
+
+ logs = loadtestutil.NewSyncWriter(logs)
+ logger := slog.Make(sloghuman.Sink(logs)).Leveled(slog.LevelDebug)
+ r.client.SetLogger(logger)
+ r.client.SetLogBodies(true)
+
+ r.createUserRunner = createusers.NewRunner(r.client, r.cfg.User)
+ newUserAndToken, err := r.createUserRunner.RunReturningUser(ctx, id, logs)
+ if err != nil {
+ r.cfg.Metrics.AddError("", "create_user")
+ return xerrors.Errorf("create user: %w", err)
+ }
+ newUser := newUserAndToken.User
+
+ newUserClient := codersdk.New(r.client.URL,
+ codersdk.WithSessionToken(newUserAndToken.SessionToken),
+ codersdk.WithLogger(logger),
+ codersdk.WithLogBodies())
+
+ //nolint:gocritic // short log is fine
+ logger.Info(ctx, "user created", slog.F("username", newUser.Username), slog.F("user_id", newUser.ID.String()))
+
+ workspaceBuildConfig := r.cfg.Workspace
+ workspaceBuildConfig.OrganizationID = r.cfg.User.OrganizationID
+ workspaceBuildConfig.UserID = newUser.ID.String()
+ // We'll wait for the build ourselves to avoid multiple API requests
+ workspaceBuildConfig.NoWaitForBuild = true
+
+ r.workspacebuildRunner = workspacebuild.NewRunner(newUserClient, workspaceBuildConfig)
+ workspace, err := r.workspacebuildRunner.RunReturningWorkspace(ctx, id, logs)
+ if err != nil {
+ r.cfg.Metrics.AddError(newUser.Username, "create_workspace")
+ return xerrors.Errorf("create workspace: %w", err)
+ }
+
+ watchCtx, cancel := context.WithCancel(ctx)
+ defer cancel()
+ workspaceUpdates, err := newUserClient.WatchWorkspace(watchCtx, workspace.ID)
+ if err != nil {
+ r.cfg.Metrics.AddError(newUser.Username, "watch_workspace")
+ return xerrors.Errorf("watch workspace: %w", err)
+ }
+
+ createWorkspaceCtx, cancel2 := context.WithTimeout(ctx, r.cfg.WorkspaceJobTimeout)
+ defer cancel2()
+
+ err = waitForWorkspaceUpdate(createWorkspaceCtx, logger, workspaceUpdates, func(ws codersdk.Workspace) bool {
+ return ws.LatestBuild.Transition == codersdk.WorkspaceTransitionStart &&
+ ws.LatestBuild.Job.Status == codersdk.ProvisionerJobSucceeded
+ })
+ if err != nil {
+ r.cfg.Metrics.AddError(newUser.Username, "wait_for_initial_build")
+ return xerrors.Errorf("timeout waiting for initial workspace build to complete: %w", err)
+ }
+
+ logger.Info(ctx, "stopping workspace", slog.F("workspace_name", workspace.Name))
+
+ _, err = newUserClient.CreateWorkspaceBuild(ctx, workspace.ID, codersdk.CreateWorkspaceBuildRequest{
+ Transition: codersdk.WorkspaceTransitionStop,
+ })
+ if err != nil {
+ r.cfg.Metrics.AddError(newUser.Username, "create_stop_build")
+ return xerrors.Errorf("create stop build: %w", err)
+ }
+
+ stopBuildCtx, cancel3 := context.WithTimeout(ctx, r.cfg.WorkspaceJobTimeout)
+ defer cancel3()
+
+ err = waitForWorkspaceUpdate(stopBuildCtx, logger, workspaceUpdates, func(ws codersdk.Workspace) bool {
+ return ws.LatestBuild.Transition == codersdk.WorkspaceTransitionStop &&
+ ws.LatestBuild.Job.Status == codersdk.ProvisionerJobSucceeded
+ })
+ if err != nil {
+ r.cfg.Metrics.AddError(newUser.Username, "wait_for_stop_build")
+ return xerrors.Errorf("timeout waiting for stop build to complete: %w", err)
+ }
+
+ logger.Info(ctx, "workspace stopped successfully", slog.F("workspace_name", workspace.Name))
+
+ logger.Info(ctx, "waiting for all runners to reach barrier")
+ reachedBarrier = true
+ r.cfg.SetupBarrier.Done()
+ r.cfg.SetupBarrier.Wait()
+ logger.Info(ctx, "all runners reached barrier, proceeding with autostart schedule")
+
+ testStartTime := time.Now().UTC()
+ autostartTime := testStartTime.Add(r.cfg.AutostartDelay).Round(time.Minute)
+ schedule := fmt.Sprintf("CRON_TZ=UTC %d %d * * *", autostartTime.Minute(), autostartTime.Hour())
+
+ logger.Info(ctx, "setting autostart schedule for workspace", slog.F("workspace_name", workspace.Name), slog.F("schedule", schedule))
+
+ err = newUserClient.UpdateWorkspaceAutostart(ctx, workspace.ID, codersdk.UpdateWorkspaceAutostartRequest{
+ Schedule: &schedule,
+ })
+ if err != nil {
+ r.cfg.Metrics.AddError(newUser.Username, "update_workspace_autostart")
+ return xerrors.Errorf("update workspace autostart: %w", err)
+ }
+
+ logger.Info(ctx, "waiting for workspace to autostart", slog.F("workspace_name", workspace.Name))
+
+ autostartInitiateCtx, cancel4 := context.WithDeadline(ctx, autostartTime.Add(r.cfg.AutostartDelay))
+ defer cancel4()
+
+ logger.Info(ctx, "listening for workspace updates to detect autostart build")
+
+ err = waitForWorkspaceUpdate(autostartInitiateCtx, logger, workspaceUpdates, func(ws codersdk.Workspace) bool {
+ if ws.LatestBuild.Transition != codersdk.WorkspaceTransitionStart {
+ return false
+ }
+
+ // The job has been created, but it might be pending
+ if r.autostartJobCreationLatency == 0 {
+ r.autostartJobCreationLatency = time.Since(autostartTime)
+ r.cfg.Metrics.RecordJobCreation(r.autostartJobCreationLatency, newUser.Username, workspace.Name)
+ }
+
+ if ws.LatestBuild.Job.Status == codersdk.ProvisionerJobRunning ||
+ ws.LatestBuild.Job.Status == codersdk.ProvisionerJobSucceeded {
+ // Job is no longer pending, but it might not have finished
+ if r.autostartJobAcquiredLatency == 0 {
+ r.autostartJobAcquiredLatency = time.Since(autostartTime)
+ r.cfg.Metrics.RecordJobAcquired(r.autostartJobAcquiredLatency, newUser.Username, workspace.Name)
+ }
+ return ws.LatestBuild.Job.Status == codersdk.ProvisionerJobSucceeded
+ }
+
+ return false
+ })
+ if err != nil {
+ r.cfg.Metrics.AddError(newUser.Username, "wait_for_autostart_build")
+ return xerrors.Errorf("timeout waiting for autostart build to be created: %w", err)
+ }
+
+ r.autostartTotalLatency = time.Since(autostartTime)
+
+ logger.Info(ctx, "autostart workspace build complete", slog.F("duration", r.autostartTotalLatency))
+ r.cfg.Metrics.RecordCompletion(r.autostartTotalLatency, newUser.Username, workspace.Name)
+
+ return nil
+}
+
+func waitForWorkspaceUpdate(ctx context.Context, logger slog.Logger, updates <-chan codersdk.Workspace, shouldBreak func(codersdk.Workspace) bool) error {
+ for {
+ select {
+ case <-ctx.Done():
+ return ctx.Err()
+ case updatedWorkspace, ok := <-updates:
+ if !ok {
+ return xerrors.New("workspace updates channel closed")
+ }
+ logger.Debug(ctx, "received workspace update", slog.F("update", updatedWorkspace))
+ if shouldBreak(updatedWorkspace) {
+ return nil
+ }
+ }
+ }
+}
+
+func (r *Runner) Cleanup(ctx context.Context, id string, logs io.Writer) error {
+ if r.workspacebuildRunner != nil {
+ _, _ = fmt.Fprintln(logs, "Cleaning up workspace...")
+ if err := r.workspacebuildRunner.Cleanup(ctx, id, logs); err != nil {
+ return xerrors.Errorf("cleanup workspace: %w", err)
+ }
+ }
+
+ if r.createUserRunner != nil {
+ _, _ = fmt.Fprintln(logs, "Cleaning up user...")
+ if err := r.createUserRunner.Cleanup(ctx, id, logs); err != nil {
+ return xerrors.Errorf("cleanup user: %w", err)
+ }
+ }
+
+ return nil
+}
+
+const (
+ AutostartTotalLatencyMetric = "autostart_total_latency_seconds"
+ AutostartJobCreationLatencyMetric = "autostart_job_creation_latency_seconds"
+ AutostartJobAcquiredLatencyMetric = "autostart_job_acquired_latency_seconds"
+)
+
+func (r *Runner) GetMetrics() map[string]any {
+ return map[string]any{
+ AutostartTotalLatencyMetric: r.autostartTotalLatency.Seconds(),
+ AutostartJobCreationLatencyMetric: r.autostartJobCreationLatency.Seconds(),
+ AutostartJobAcquiredLatencyMetric: r.autostartJobAcquiredLatency.Seconds(),
+ }
+}
diff --git a/scaletest/autostart/run_test.go b/scaletest/autostart/run_test.go
new file mode 100644
index 0000000000000..dc0fb9fea018e
--- /dev/null
+++ b/scaletest/autostart/run_test.go
@@ -0,0 +1,158 @@
+package autostart_test
+
+import (
+ "io"
+ "strconv"
+ "sync"
+ "testing"
+ "time"
+
+ "github.com/google/uuid"
+ "github.com/prometheus/client_golang/prometheus"
+ "github.com/stretchr/testify/require"
+ "golang.org/x/sync/errgroup"
+
+ "github.com/coder/coder/v2/coderd/coderdtest"
+ "github.com/coder/coder/v2/codersdk"
+ "github.com/coder/coder/v2/provisioner/echo"
+ "github.com/coder/coder/v2/provisionersdk/proto"
+ "github.com/coder/coder/v2/scaletest/autostart"
+ "github.com/coder/coder/v2/scaletest/createusers"
+ "github.com/coder/coder/v2/scaletest/workspacebuild"
+ "github.com/coder/coder/v2/testutil"
+)
+
+func TestRun(t *testing.T) {
+ t.Parallel()
+ numUsers := 2
+ autoStartDelay := 2 * time.Minute
+
+ // Faking a workspace autostart schedule start time at the coderd level
+ // is difficult and error-prone.
+ t.Skip("This test takes several minutes to run, and is intended as a manual regression test")
+
+ ctx := testutil.Context(t, time.Minute*3)
+
+ client := coderdtest.New(t, &coderdtest.Options{
+ IncludeProvisionerDaemon: true,
+ AutobuildTicker: time.NewTicker(time.Second * 1).C,
+ })
+ user := coderdtest.CreateFirstUser(t, client)
+
+ authToken := uuid.NewString()
+ version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{
+ Parse: echo.ParseComplete,
+ ProvisionPlan: echo.PlanComplete,
+ ProvisionApply: []*proto.Response{
+ {
+ Type: &proto.Response_Apply{
+ Apply: &proto.ApplyComplete{
+ Resources: []*proto.Resource{
+ {
+ Name: "example",
+ Type: "aws_instance",
+ Agents: []*proto.Agent{
+ {
+ Id: uuid.NewString(),
+ Name: "agent",
+ Auth: &proto.Agent_Token{
+ Token: authToken,
+ },
+ Apps: []*proto.App{},
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ })
+
+ template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
+ coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)
+
+ barrier := new(sync.WaitGroup)
+ barrier.Add(numUsers)
+ metrics := autostart.NewMetrics(prometheus.NewRegistry())
+
+ eg, runCtx := errgroup.WithContext(ctx)
+
+ runners := make([]*autostart.Runner, 0, numUsers)
+ for i := range numUsers {
+ cfg := autostart.Config{
+ User: createusers.Config{
+ OrganizationID: user.OrganizationID,
+ },
+ Workspace: workspacebuild.Config{
+ OrganizationID: user.OrganizationID,
+ Request: codersdk.CreateWorkspaceRequest{
+ TemplateID: template.ID,
+ },
+ NoWaitForAgents: true,
+ },
+ WorkspaceJobTimeout: testutil.WaitMedium,
+ AutostartDelay: autoStartDelay,
+ AutostartTimeout: testutil.WaitShort,
+ Metrics: metrics,
+ SetupBarrier: barrier,
+ }
+ err := cfg.Validate()
+ require.NoError(t, err)
+
+ runner := autostart.NewRunner(client, cfg)
+ runners = append(runners, runner)
+ eg.Go(func() error {
+ return runner.Run(runCtx, strconv.Itoa(i), io.Discard)
+ })
+ }
+
+ err := eg.Wait()
+ require.NoError(t, err)
+
+ users, err := client.Users(ctx, codersdk.UsersRequest{})
+ require.NoError(t, err)
+ require.Len(t, users.Users, 1+numUsers) // owner + created users
+
+ workspaces, err := client.Workspaces(ctx, codersdk.WorkspaceFilter{})
+ require.NoError(t, err)
+ require.Len(t, workspaces.Workspaces, numUsers) // one workspace per user
+
+ // Verify that workspaces have autostart schedules set and are running
+ for _, workspace := range workspaces.Workspaces {
+ require.NotNil(t, workspace.AutostartSchedule)
+ require.Equal(t, codersdk.WorkspaceTransitionStart, workspace.LatestBuild.Transition)
+ require.Equal(t, codersdk.ProvisionerJobSucceeded, workspace.LatestBuild.Job.Status)
+ }
+
+ cleanupEg, cleanupCtx := errgroup.WithContext(ctx)
+ for i, runner := range runners {
+ cleanupEg.Go(func() error {
+ return runner.Cleanup(cleanupCtx, strconv.Itoa(i), io.Discard)
+ })
+ }
+ err = cleanupEg.Wait()
+ require.NoError(t, err)
+
+ workspaces, err = client.Workspaces(ctx, codersdk.WorkspaceFilter{})
+ require.NoError(t, err)
+ require.Len(t, workspaces.Workspaces, 0)
+
+ users, err = client.Users(ctx, codersdk.UsersRequest{})
+ require.NoError(t, err)
+ require.Len(t, users.Users, 1) // owner
+
+ for _, runner := range runners {
+ metrics := runner.GetMetrics()
+ require.Contains(t, metrics, autostart.AutostartTotalLatencyMetric)
+ latency, ok := metrics[autostart.AutostartTotalLatencyMetric].(float64)
+ require.True(t, ok)
+ jobCreationLatency, ok := metrics[autostart.AutostartJobCreationLatencyMetric].(float64)
+ require.True(t, ok)
+ jobAcquiredLatency, ok := metrics[autostart.AutostartJobAcquiredLatencyMetric].(float64)
+ require.True(t, ok)
+ require.Greater(t, latency, float64(0))
+ require.Greater(t, jobCreationLatency, float64(0))
+ require.Greater(t, jobAcquiredLatency, float64(0))
+ }
+}
diff --git a/scaletest/workspacebuild/config.go b/scaletest/workspacebuild/config.go
index 90184dacf84e8..105883ba3b7a8 100644
--- a/scaletest/workspacebuild/config.go
+++ b/scaletest/workspacebuild/config.go
@@ -19,6 +19,9 @@ type Config struct {
// NoWaitForAgents determines whether the test should wait for the workspace
// agents to connect before returning.
NoWaitForAgents bool `json:"no_wait_for_agents"`
+ // NoWaitForBuild determines whether the test should wait for the workspace
+ // build to complete before returning.
+ NoWaitForBuild bool `json:"no_wait_for_build"`
// Retry determines how many times to retry starting a workspace build if it
// fails.
Retry int `json:"retry"`
diff --git a/scaletest/workspacebuild/run.go b/scaletest/workspacebuild/run.go
index c9a59a18d69cb..308c18f0b6a03 100644
--- a/scaletest/workspacebuild/run.go
+++ b/scaletest/workspacebuild/run.go
@@ -58,27 +58,31 @@ func (r *Runner) RunReturningWorkspace(ctx context.Context, id string, logs io.W
}
r.workspaceID = workspace.ID
- err = waitForBuild(ctx, logs, r.client, workspace.LatestBuild.ID)
- if err != nil {
- for i := 0; i < r.cfg.Retry; i++ {
- _, _ = fmt.Fprintf(logs, "Retrying build %d/%d...\n", i+1, r.cfg.Retry)
-
- workspace.LatestBuild, err = r.client.CreateWorkspaceBuild(ctx, workspace.ID, codersdk.CreateWorkspaceBuildRequest{
- Transition: codersdk.WorkspaceTransitionStart,
- RichParameterValues: req.RichParameterValues,
- TemplateVersionID: req.TemplateVersionID,
- })
- if err != nil {
- return codersdk.Workspace{}, xerrors.Errorf("create workspace build: %w", err)
+ if r.cfg.NoWaitForBuild {
+ _, _ = fmt.Fprintln(logs, "Skipping waiting for build")
+ } else {
+ err = waitForBuild(ctx, logs, r.client, workspace.LatestBuild.ID)
+ if err != nil {
+ for i := 0; i < r.cfg.Retry; i++ {
+ _, _ = fmt.Fprintf(logs, "Retrying build %d/%d...\n", i+1, r.cfg.Retry)
+
+ workspace.LatestBuild, err = r.client.CreateWorkspaceBuild(ctx, workspace.ID, codersdk.CreateWorkspaceBuildRequest{
+ Transition: codersdk.WorkspaceTransitionStart,
+ RichParameterValues: req.RichParameterValues,
+ TemplateVersionID: req.TemplateVersionID,
+ })
+ if err != nil {
+ return codersdk.Workspace{}, xerrors.Errorf("create workspace build: %w", err)
+ }
+ err = waitForBuild(ctx, logs, r.client, workspace.LatestBuild.ID)
+ if err == nil {
+ break
+ }
}
- err = waitForBuild(ctx, logs, r.client, workspace.LatestBuild.ID)
- if err == nil {
- break
+ if err != nil {
+ return codersdk.Workspace{}, xerrors.Errorf("wait for build: %w", err)
}
}
- if err != nil {
- return codersdk.Workspace{}, xerrors.Errorf("wait for build: %w", err)
- }
}
if r.cfg.NoWaitForAgents {
From 76d6e13185b2acd8d0fd23e43e0d9c3eb8bcccc0 Mon Sep 17 00:00:00 2001
From: Ethan <39577870+ethanndickson@users.noreply.github.com>
Date: Thu, 2 Oct 2025 11:22:05 +1000
Subject: [PATCH 036/298] ci: make `changes` required (#20131)
Earlier today, a dependabot PR was merged despite CI not having been run. https://github.com/coder/coder/pull/20068
This was because the `changes` job failed due to a github ratelimit, which caused all the tests to be skipped, which caused `required` to pass as it passes if tests are skipped.
This PR makes `changes` required so this can't happen again (assuming we keep around the dependabot automerge around, it might).
---
.github/workflows/ci.yaml | 2 ++
1 file changed, 2 insertions(+)
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index 2d41883287e54..6fbba7883afbd 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -919,6 +919,7 @@ jobs:
required:
runs-on: ubuntu-latest
needs:
+ - changes
- fmt
- lint
- gen
@@ -942,6 +943,7 @@ jobs:
- name: Ensure required checks
run: | # zizmor: ignore[template-injection] We're just reading needs.x.result here, no risk of injection
echo "Checking required checks"
+ echo "- changes: ${{ needs.changes.result }}"
echo "- fmt: ${{ needs.fmt.result }}"
echo "- lint: ${{ needs.lint.result }}"
echo "- gen: ${{ needs.gen.result }}"
From e5c8c9bdaf770828ded482262add1c8ef68bfee5 Mon Sep 17 00:00:00 2001
From: Dean Sheather
Date: Thu, 2 Oct 2025 12:12:29 +1000
Subject: [PATCH 037/298] chore: pin dogfood to release branch during release
freeze (#20028)
Relates to https://github.com/coder/dogfood/pull/189
Closes https://github.com/coder/internal/issues/1021
- Adds new script `scripts/should_deploy.sh` which implements the
algorithm in the linked issue
- Changes the `ci.yaml` workflow to run on release branches
- Moves the deployment steps out of `ci.yaml` into a new workflow
`deploy.yaml` for concurrency limiting purposes
- Changes the behavior of image tag pushing slightly:
- Versioned tags will no longer have a `main-` prefix
- `main` branch will still push the `main` and `latest` tags
- `release/x.y` branches will now push `release-x.y` tags
- The deploy job will exit early if `should_deploy.sh` returns false
- The deploy job will now retag whatever image it's about to deploy as
`dogfood`
---
.github/workflows/ci.yaml | 152 ++++++++----------------------
.github/workflows/deploy.yaml | 170 ++++++++++++++++++++++++++++++++++
.github/zizmor.yml | 4 +
scripts/image_tag.sh | 5 +-
scripts/should_deploy.sh | 68 ++++++++++++++
5 files changed, 280 insertions(+), 119 deletions(-)
create mode 100644 .github/workflows/deploy.yaml
create mode 100644 .github/zizmor.yml
create mode 100755 scripts/should_deploy.sh
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index 6fbba7883afbd..eb2ba62e6b764 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -4,6 +4,7 @@ on:
push:
branches:
- main
+ - release/*
pull_request:
workflow_dispatch:
@@ -969,7 +970,7 @@ jobs:
needs: changes
# We always build the dylibs on Go changes to verify we're not merging unbuildable code,
# but they need only be signed and uploaded on coder/coder main.
- if: needs.changes.outputs.go == 'true' || needs.changes.outputs.ci == 'true' || github.ref == 'refs/heads/main'
+ if: needs.changes.outputs.go == 'true' || needs.changes.outputs.ci == 'true' || github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release/')
runs-on: ${{ github.repository_owner == 'coder' && 'depot-macos-latest' || 'macos-latest' }}
steps:
# Harden Runner doesn't work on macOS
@@ -997,7 +998,7 @@ jobs:
uses: ./.github/actions/setup-go
- name: Install rcodesign
- if: ${{ github.repository_owner == 'coder' && github.ref == 'refs/heads/main' }}
+ if: ${{ github.repository_owner == 'coder' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release/')) }}
run: |
set -euo pipefail
wget -O /tmp/rcodesign.tar.gz https://github.com/indygreg/apple-platform-rs/releases/download/apple-codesign%2F0.22.0/apple-codesign-0.22.0-macos-universal.tar.gz
@@ -1008,7 +1009,7 @@ jobs:
rm /tmp/rcodesign.tar.gz
- name: Setup Apple Developer certificate and API key
- if: ${{ github.repository_owner == 'coder' && github.ref == 'refs/heads/main' }}
+ if: ${{ github.repository_owner == 'coder' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release/')) }}
run: |
set -euo pipefail
touch /tmp/{apple_cert.p12,apple_cert_password.txt,apple_apikey.p8}
@@ -1029,12 +1030,12 @@ jobs:
make gen/mark-fresh
make build/coder-dylib
env:
- CODER_SIGN_DARWIN: ${{ github.ref == 'refs/heads/main' && '1' || '0' }}
+ CODER_SIGN_DARWIN: ${{ (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release/')) && '1' || '0' }}
AC_CERTIFICATE_FILE: /tmp/apple_cert.p12
AC_CERTIFICATE_PASSWORD_FILE: /tmp/apple_cert_password.txt
- name: Upload build artifacts
- if: ${{ github.repository_owner == 'coder' && github.ref == 'refs/heads/main' }}
+ if: ${{ github.repository_owner == 'coder' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release/')) }}
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: dylibs
@@ -1044,7 +1045,7 @@ jobs:
retention-days: 7
- name: Delete Apple Developer certificate and API key
- if: ${{ github.repository_owner == 'coder' && github.ref == 'refs/heads/main' }}
+ if: ${{ github.repository_owner == 'coder' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release/')) }}
run: rm -f /tmp/{apple_cert.p12,apple_cert_password.txt,apple_apikey.p8}
check-build:
@@ -1094,7 +1095,7 @@ jobs:
needs:
- changes
- build-dylib
- if: github.ref == 'refs/heads/main' && needs.changes.outputs.docs-only == 'false' && !github.event.pull_request.head.repo.fork
+ if: (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release/')) && needs.changes.outputs.docs-only == 'false' && !github.event.pull_request.head.repo.fork
runs-on: ${{ github.repository_owner == 'coder' && 'depot-ubuntu-22.04-8' || 'ubuntu-22.04' }}
permissions:
# Necessary to push docker images to ghcr.io.
@@ -1247,40 +1248,45 @@ jobs:
id: build-docker
env:
CODER_IMAGE_BASE: ghcr.io/coder/coder-preview
- CODER_IMAGE_TAG_PREFIX: main
DOCKER_CLI_EXPERIMENTAL: "enabled"
run: |
set -euxo pipefail
# build Docker images for each architecture
version="$(./scripts/version.sh)"
- tag="main-${version//+/-}"
+ tag="${version//+/-}"
echo "tag=$tag" >> "$GITHUB_OUTPUT"
# build images for each architecture
# note: omitting the -j argument to avoid race conditions when pushing
make build/coder_"$version"_linux_{amd64,arm64,armv7}.tag
- # only push if we are on main branch
- if [ "${GITHUB_REF}" == "refs/heads/main" ]; then
+ # only push if we are on main branch or release branch
+ if [[ "${GITHUB_REF}" == "refs/heads/main" || "${GITHUB_REF}" == refs/heads/release/* ]]; then
# build and push multi-arch manifest, this depends on the other images
# being pushed so will automatically push them
# note: omitting the -j argument to avoid race conditions when pushing
make push/build/coder_"$version"_linux_{amd64,arm64,armv7}.tag
# Define specific tags
- tags=("$tag" "main" "latest")
+ tags=("$tag")
+ if [ "${GITHUB_REF}" == "refs/heads/main" ]; then
+ tags+=("main" "latest")
+ elif [[ "${GITHUB_REF}" == refs/heads/release/* ]]; then
+ tags+=("release-${GITHUB_REF#refs/heads/release/}")
+ fi
# Create and push a multi-arch manifest for each tag
# we are adding `latest` tag and keeping `main` for backward
# compatibality
for t in "${tags[@]}"; do
- # shellcheck disable=SC2046
- ./scripts/build_docker_multiarch.sh \
- --push \
- --target "ghcr.io/coder/coder-preview:$t" \
- --version "$version" \
- $(cat build/coder_"$version"_linux_{amd64,arm64,armv7}.tag)
+ echo "Pushing multi-arch manifest for tag: $t"
+ # shellcheck disable=SC2046
+ ./scripts/build_docker_multiarch.sh \
+ --push \
+ --target "ghcr.io/coder/coder-preview:$t" \
+ --version "$version" \
+ $(cat build/coder_"$version"_linux_{amd64,arm64,armv7}.tag)
done
fi
@@ -1471,112 +1477,28 @@ jobs:
./build/*.deb
retention-days: 7
+ # Deploy is handled in deploy.yaml so we can apply concurrency limits.
deploy:
- name: "deploy"
- runs-on: ubuntu-latest
- timeout-minutes: 30
needs:
- changes
- build
if: |
- github.ref == 'refs/heads/main' && !github.event.pull_request.head.repo.fork
+ (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release/'))
&& needs.changes.outputs.docs-only == 'false'
+ && !github.event.pull_request.head.repo.fork
+ uses: ./.github/workflows/deploy.yaml
+ with:
+ image: ${{ needs.build.outputs.IMAGE }}
permissions:
contents: read
id-token: write
- steps:
- - name: Harden Runner
- uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
- with:
- egress-policy: audit
-
- - name: Checkout
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- with:
- fetch-depth: 0
- persist-credentials: false
-
- - name: Authenticate to Google Cloud
- uses: google-github-actions/auth@7c6bc770dae815cd3e89ee6cdf493a5fab2cc093 # v3.0.0
- with:
- workload_identity_provider: ${{ vars.GCP_WORKLOAD_ID_PROVIDER }}
- service_account: ${{ vars.GCP_SERVICE_ACCOUNT }}
-
- - name: Set up Google Cloud SDK
- uses: google-github-actions/setup-gcloud@aa5489c8933f4cc7a4f7d45035b3b1440c9c10db # v3.0.1
-
- - name: Set up Flux CLI
- uses: fluxcd/flux2/action@6bf37f6a560fd84982d67f853162e4b3c2235edb # v2.6.4
- with:
- # Keep this and the github action up to date with the version of flux installed in dogfood cluster
- version: "2.5.1"
-
- - name: Get Cluster Credentials
- uses: google-github-actions/get-gke-credentials@3da1e46a907576cefaa90c484278bb5b259dd395 # v3.0.0
- with:
- cluster_name: dogfood-v2
- location: us-central1-a
- project_id: coder-dogfood-v2
-
- - name: Reconcile Flux
- run: |
- set -euxo pipefail
- flux --namespace flux-system reconcile source git flux-system
- flux --namespace flux-system reconcile source git coder-main
- flux --namespace flux-system reconcile kustomization flux-system
- flux --namespace flux-system reconcile kustomization coder
- flux --namespace flux-system reconcile source chart coder-coder
- flux --namespace flux-system reconcile source chart coder-coder-provisioner
- flux --namespace coder reconcile helmrelease coder
- flux --namespace coder reconcile helmrelease coder-provisioner
-
- # Just updating Flux is usually not enough. The Helm release may get
- # redeployed, but unless something causes the Deployment to update the
- # pods won't be recreated. It's important that the pods get recreated,
- # since we use `imagePullPolicy: Always` to ensure we're running the
- # latest image.
- - name: Rollout Deployment
- run: |
- set -euxo pipefail
- kubectl --namespace coder rollout restart deployment/coder
- kubectl --namespace coder rollout status deployment/coder
- kubectl --namespace coder rollout restart deployment/coder-provisioner
- kubectl --namespace coder rollout status deployment/coder-provisioner
- kubectl --namespace coder rollout restart deployment/coder-provisioner-tagged
- kubectl --namespace coder rollout status deployment/coder-provisioner-tagged
-
- deploy-wsproxies:
- runs-on: ubuntu-latest
- needs: build
- if: github.ref == 'refs/heads/main' && !github.event.pull_request.head.repo.fork
- steps:
- - name: Harden Runner
- uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
- with:
- egress-policy: audit
-
- - name: Checkout
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- with:
- fetch-depth: 0
- persist-credentials: false
-
- - name: Setup flyctl
- uses: superfly/flyctl-actions/setup-flyctl@fc53c09e1bc3be6f54706524e3b82c4f462f77be # v1.5
-
- - name: Deploy workspace proxies
- run: |
- flyctl deploy --image "$IMAGE" --app paris-coder --config ./.github/fly-wsproxies/paris-coder.toml --env "CODER_PROXY_SESSION_TOKEN=$TOKEN_PARIS" --yes
- flyctl deploy --image "$IMAGE" --app sydney-coder --config ./.github/fly-wsproxies/sydney-coder.toml --env "CODER_PROXY_SESSION_TOKEN=$TOKEN_SYDNEY" --yes
- flyctl deploy --image "$IMAGE" --app sao-paulo-coder --config ./.github/fly-wsproxies/sao-paulo-coder.toml --env "CODER_PROXY_SESSION_TOKEN=$TOKEN_SAO_PAULO" --yes
- flyctl deploy --image "$IMAGE" --app jnb-coder --config ./.github/fly-wsproxies/jnb-coder.toml --env "CODER_PROXY_SESSION_TOKEN=$TOKEN_JNB" --yes
- env:
- FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}
- IMAGE: ${{ needs.build.outputs.IMAGE }}
- TOKEN_PARIS: ${{ secrets.FLY_PARIS_CODER_PROXY_SESSION_TOKEN }}
- TOKEN_SYDNEY: ${{ secrets.FLY_SYDNEY_CODER_PROXY_SESSION_TOKEN }}
- TOKEN_SAO_PAULO: ${{ secrets.FLY_SAO_PAULO_CODER_PROXY_SESSION_TOKEN }}
- TOKEN_JNB: ${{ secrets.FLY_JNB_CODER_PROXY_SESSION_TOKEN }}
+ packages: write # to retag image as dogfood
+ secrets:
+ FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}
+ FLY_PARIS_CODER_PROXY_SESSION_TOKEN: ${{ secrets.FLY_PARIS_CODER_PROXY_SESSION_TOKEN }}
+ FLY_SYDNEY_CODER_PROXY_SESSION_TOKEN: ${{ secrets.FLY_SYDNEY_CODER_PROXY_SESSION_TOKEN }}
+ FLY_SAO_PAULO_CODER_PROXY_SESSION_TOKEN: ${{ secrets.FLY_SAO_PAULO_CODER_PROXY_SESSION_TOKEN }}
+ FLY_JNB_CODER_PROXY_SESSION_TOKEN: ${{ secrets.FLY_JNB_CODER_PROXY_SESSION_TOKEN }}
# sqlc-vet runs a postgres docker container, runs Coder migrations, and then
# runs sqlc-vet to ensure all queries are valid. This catches any mistakes
diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml
new file mode 100644
index 0000000000000..7983591246363
--- /dev/null
+++ b/.github/workflows/deploy.yaml
@@ -0,0 +1,170 @@
+name: deploy
+
+on:
+ # Via workflow_call, called from ci.yaml
+ workflow_call:
+ inputs:
+ image:
+ description: "Image and tag to potentially deploy. Current branch will be validated against should-deploy check."
+ required: true
+ type: string
+ secrets:
+ FLY_API_TOKEN:
+ required: true
+ FLY_PARIS_CODER_PROXY_SESSION_TOKEN:
+ required: true
+ FLY_SYDNEY_CODER_PROXY_SESSION_TOKEN:
+ required: true
+ FLY_SAO_PAULO_CODER_PROXY_SESSION_TOKEN:
+ required: true
+ FLY_JNB_CODER_PROXY_SESSION_TOKEN:
+ required: true
+
+permissions:
+ contents: read
+
+concurrency:
+ group: ${{ github.workflow }} # no per-branch concurrency
+ cancel-in-progress: false
+
+jobs:
+ # Determines if the given branch should be deployed to dogfood.
+ should-deploy:
+ name: should-deploy
+ runs-on: ubuntu-latest
+ outputs:
+ verdict: ${{ steps.check.outputs.verdict }} # DEPLOY or NOOP
+ steps:
+ - name: Harden Runner
+ uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
+ with:
+ egress-policy: audit
+
+ - name: Checkout
+ uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
+ with:
+ fetch-depth: 0
+ persist-credentials: false
+
+ - name: Check if deploy is enabled
+ id: check
+ run: |
+ set -euo pipefail
+ verdict="$(./scripts/should_deploy.sh)"
+ echo "verdict=$verdict" >> "$GITHUB_OUTPUT"
+
+ deploy:
+ name: "deploy"
+ runs-on: ubuntu-latest
+ timeout-minutes: 30
+ needs: should-deploy
+ if: needs.should-deploy.outputs.verdict == 'DEPLOY'
+ permissions:
+ contents: read
+ id-token: write
+ packages: write # to retag image as dogfood
+ steps:
+ - name: Harden Runner
+ uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
+ with:
+ egress-policy: audit
+
+ - name: Checkout
+ uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
+ with:
+ fetch-depth: 0
+ persist-credentials: false
+
+ - name: GHCR Login
+ uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 # v3.5.0
+ with:
+ registry: ghcr.io
+ username: ${{ github.actor }}
+ password: ${{ secrets.GITHUB_TOKEN }}
+
+ - name: Authenticate to Google Cloud
+ uses: google-github-actions/auth@7c6bc770dae815cd3e89ee6cdf493a5fab2cc093 # v3.0.0
+ with:
+ workload_identity_provider: ${{ vars.GCP_WORKLOAD_ID_PROVIDER }}
+ service_account: ${{ vars.GCP_SERVICE_ACCOUNT }}
+
+ - name: Set up Google Cloud SDK
+ uses: google-github-actions/setup-gcloud@aa5489c8933f4cc7a4f7d45035b3b1440c9c10db # v3.0.1
+
+ - name: Set up Flux CLI
+ uses: fluxcd/flux2/action@6bf37f6a560fd84982d67f853162e4b3c2235edb # v2.6.4
+ with:
+ # Keep this and the github action up to date with the version of flux installed in dogfood cluster
+ version: "2.7.0"
+
+ - name: Get Cluster Credentials
+ uses: google-github-actions/get-gke-credentials@3da1e46a907576cefaa90c484278bb5b259dd395 # v3.0.0
+ with:
+ cluster_name: dogfood-v2
+ location: us-central1-a
+ project_id: coder-dogfood-v2
+
+ - name: Tag image as dogfood
+ run: |
+ set -euxo pipefail
+ # Retag image as dogfood while maintaining the multi-arch manifest
+ docker buildx imagetools create --tag "ghcr.io/coder/coder-preview:dogfood" "$IMAGE"
+
+ - name: Reconcile Flux
+ run: |
+ set -euxo pipefail
+ flux --namespace flux-system reconcile source git flux-system
+ flux --namespace flux-system reconcile source git coder-main
+ flux --namespace flux-system reconcile kustomization flux-system
+ flux --namespace flux-system reconcile kustomization coder
+ flux --namespace flux-system reconcile source chart coder-coder
+ flux --namespace flux-system reconcile source chart coder-coder-provisioner
+ flux --namespace coder reconcile helmrelease coder
+ flux --namespace coder reconcile helmrelease coder-provisioner
+
+ # Just updating Flux is usually not enough. The Helm release may get
+ # redeployed, but unless something causes the Deployment to update the
+ # pods won't be recreated. It's important that the pods get recreated,
+ # since we use `imagePullPolicy: Always` to ensure we're running the
+ # latest image.
+ - name: Rollout Deployment
+ run: |
+ set -euxo pipefail
+ kubectl --namespace coder rollout restart deployment/coder
+ kubectl --namespace coder rollout status deployment/coder
+ kubectl --namespace coder rollout restart deployment/coder-provisioner
+ kubectl --namespace coder rollout status deployment/coder-provisioner
+ kubectl --namespace coder rollout restart deployment/coder-provisioner-tagged
+ kubectl --namespace coder rollout status deployment/coder-provisioner-tagged
+
+ deploy-wsproxies:
+ runs-on: ubuntu-latest
+ needs: deploy
+ steps:
+ - name: Harden Runner
+ uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
+ with:
+ egress-policy: audit
+
+ - name: Checkout
+ uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
+ with:
+ fetch-depth: 0
+ persist-credentials: false
+
+ - name: Setup flyctl
+ uses: superfly/flyctl-actions/setup-flyctl@fc53c09e1bc3be6f54706524e3b82c4f462f77be # v1.5
+
+ - name: Deploy workspace proxies
+ run: |
+ flyctl deploy --image "$IMAGE" --app paris-coder --config ./.github/fly-wsproxies/paris-coder.toml --env "CODER_PROXY_SESSION_TOKEN=$TOKEN_PARIS" --yes
+ flyctl deploy --image "$IMAGE" --app sydney-coder --config ./.github/fly-wsproxies/sydney-coder.toml --env "CODER_PROXY_SESSION_TOKEN=$TOKEN_SYDNEY" --yes
+ flyctl deploy --image "$IMAGE" --app sao-paulo-coder --config ./.github/fly-wsproxies/sao-paulo-coder.toml --env "CODER_PROXY_SESSION_TOKEN=$TOKEN_SAO_PAULO" --yes
+ flyctl deploy --image "$IMAGE" --app jnb-coder --config ./.github/fly-wsproxies/jnb-coder.toml --env "CODER_PROXY_SESSION_TOKEN=$TOKEN_JNB" --yes
+ env:
+ FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}
+ IMAGE: ${{ inputs.image }}
+ TOKEN_PARIS: ${{ secrets.FLY_PARIS_CODER_PROXY_SESSION_TOKEN }}
+ TOKEN_SYDNEY: ${{ secrets.FLY_SYDNEY_CODER_PROXY_SESSION_TOKEN }}
+ TOKEN_SAO_PAULO: ${{ secrets.FLY_SAO_PAULO_CODER_PROXY_SESSION_TOKEN }}
+ TOKEN_JNB: ${{ secrets.FLY_JNB_CODER_PROXY_SESSION_TOKEN }}
diff --git a/.github/zizmor.yml b/.github/zizmor.yml
new file mode 100644
index 0000000000000..e125592cfdc6a
--- /dev/null
+++ b/.github/zizmor.yml
@@ -0,0 +1,4 @@
+rules:
+ cache-poisoning:
+ ignore:
+ - "ci.yaml:184"
diff --git a/scripts/image_tag.sh b/scripts/image_tag.sh
index 68dfbcebf99cb..8767a22cb199c 100755
--- a/scripts/image_tag.sh
+++ b/scripts/image_tag.sh
@@ -51,10 +51,7 @@ fi
image="${CODER_IMAGE_BASE:-ghcr.io/coder/coder}"
-# use CODER_IMAGE_TAG_PREFIX if set as a prefix for the tag
-tag_prefix="${CODER_IMAGE_TAG_PREFIX:-}"
-
-tag="${tag_prefix:+$tag_prefix-}v$version"
+tag="v$version"
if [[ "$version" == "latest" ]]; then
tag="latest"
diff --git a/scripts/should_deploy.sh b/scripts/should_deploy.sh
new file mode 100755
index 0000000000000..3122192956b8d
--- /dev/null
+++ b/scripts/should_deploy.sh
@@ -0,0 +1,68 @@
+#!/usr/bin/env bash
+
+# This script determines if a commit in either the main branch or a
+# `release/x.y` branch should be deployed to dogfood.
+#
+# To avoid masking unrelated failures, this script will return 0 in either case,
+# and will print `DEPLOY` or `NOOP` to stdout.
+
+set -euo pipefail
+# shellcheck source=scripts/lib.sh
+source "$(dirname "${BASH_SOURCE[0]}")/lib.sh"
+cdroot
+
+deploy_branch=main
+
+# Determine the current branch name and check that it is one of the supported
+# branch names.
+branch_name=$(git branch --show-current)
+if [[ "$branch_name" != "main" && ! "$branch_name" =~ ^release/[0-9]+\.[0-9]+$ ]]; then
+ error "Current branch '$branch_name' is not a supported branch name for dogfood, must be 'main' or 'release/x.y'"
+fi
+log "Current branch '$branch_name'"
+
+# Determine the remote name
+remote=$(git remote -v | grep coder/coder | awk '{print $1}' | head -n1)
+if [[ -z "${remote}" ]]; then
+ error "Could not find remote for coder/coder"
+fi
+log "Using remote '$remote'"
+
+# Step 1: List all release branches and sort them by major/minor so we can find
+# the latest release branch.
+release_branches=$(
+ git branch -r --format='%(refname:short)' |
+ grep -E "${remote}/release/[0-9]+\.[0-9]+$" |
+ sed "s|${remote}/||" |
+ sort -V
+)
+
+# As a sanity check, release/2.26 should exist.
+if ! echo "$release_branches" | grep "release/2.26" >/dev/null; then
+ error "Could not find existing release branches. Did you run 'git fetch -ap ${remote}'?"
+fi
+
+latest_release_branch=$(echo "$release_branches" | tail -n 1)
+latest_release_branch_version=${latest_release_branch#release/}
+log "Latest release branch: $latest_release_branch"
+log "Latest release branch version: $latest_release_branch_version"
+
+# Step 2: check if a matching tag `v.0` exists. If it does not, we will
+# use the release branch as the deploy branch.
+if ! git rev-parse "refs/tags/v${latest_release_branch_version}.0" >/dev/null 2>&1; then
+ log "Tag 'v${latest_release_branch_version}.0' does not exist, using release branch as deploy branch"
+ deploy_branch=$latest_release_branch
+else
+ log "Matching tag 'v${latest_release_branch_version}.0' exists, using main as deploy branch"
+fi
+log "Deploy branch: $deploy_branch"
+
+# Finally, check if the current branch is the deploy branch.
+log
+if [[ "$branch_name" != "$deploy_branch" ]]; then
+ log "VERDICT: DO NOT DEPLOY"
+ echo "NOOP" # stdout
+else
+ log "VERDICT: DEPLOY"
+ echo "DEPLOY" # stdout
+fi
From d2c286d9b0eac6d5f04b33d10323c677d5e940d4 Mon Sep 17 00:00:00 2001
From: Dean Sheather
Date: Thu, 2 Oct 2025 16:08:29 +1000
Subject: [PATCH 038/298] chore: fix missing variable in deploy workflow
(#20136)
already in release branch and tested working
---
.github/workflows/deploy.yaml | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml
index 7983591246363..895fd32ec9851 100644
--- a/.github/workflows/deploy.yaml
+++ b/.github/workflows/deploy.yaml
@@ -104,11 +104,11 @@ jobs:
location: us-central1-a
project_id: coder-dogfood-v2
+ # Retag image as dogfood while maintaining the multi-arch manifest
- name: Tag image as dogfood
- run: |
- set -euxo pipefail
- # Retag image as dogfood while maintaining the multi-arch manifest
- docker buildx imagetools create --tag "ghcr.io/coder/coder-preview:dogfood" "$IMAGE"
+ run: docker buildx imagetools create --tag "ghcr.io/coder/coder-preview:dogfood" "$IMAGE"
+ env:
+ IMAGE: ${{ inputs.image }}
- name: Reconcile Flux
run: |
From d63bb2ce2fd33acf0d4b158437dad6219ba60749 Mon Sep 17 00:00:00 2001
From: Danny Kopping
Date: Thu, 2 Oct 2025 11:10:51 +0200
Subject: [PATCH 039/298] chore: add Audit Log purge advice (#20052)
Audit Log entries can be deleted safely (with appropriate caveats), but
we don't specifically call this out in the docs.
---------
Signed-off-by: Danny Kopping
---
docs/admin/security/audit-logs.md | 52 ++++++++++++++++++++++++++++++-
1 file changed, 51 insertions(+), 1 deletion(-)
diff --git a/docs/admin/security/audit-logs.md b/docs/admin/security/audit-logs.md
index 37ed2a1c00694..2c72528f38ea3 100644
--- a/docs/admin/security/audit-logs.md
+++ b/docs/admin/security/audit-logs.md
@@ -125,6 +125,56 @@ log entry:
2023-06-13 03:43:29.233 [info] coderd: audit_log ID=95f7c392-da3e-480c-a579-8909f145fbe2 Time="2023-06-13T03:43:29.230422Z" UserID=6c405053-27e3-484a-9ad7-bcb64e7bfde6 OrganizationID=00000000-0000-0000-0000-000000000000 Ip= UserAgent= ResourceType=workspace_build ResourceID=988ae133-5b73-41e3-a55e-e1e9d3ef0b66 ResourceTarget="" Action=start Diff="{}" StatusCode=200 AdditionalFields="{\"workspace_name\":\"linux-container\",\"build_number\":\"7\",\"build_reason\":\"initiator\",\"workspace_owner\":\"\"}" RequestID=9682b1b5-7b9f-4bf2-9a39-9463f8e41cd6 ResourceIcon=""
```
+## Purging Old Audit Logs
+
+> [!WARNING]
+> Audit Logs provide critical security and compliance information. Purging Audit Logs may impact your organization's ability
+> to investigate security incidents or meet compliance requirements. Consult your security and compliance teams before purging any audit data.
+
+Audit Logs are not automatically purged from the database, though they can account for a large amount of disk usage.
+Use the following query to determine the amount of disk space used by the `audit_logs` table.
+
+```sql
+SELECT
+ relname AS table_name,
+ pg_size_pretty(pg_total_relation_size(relid)) AS total_size,
+ pg_size_pretty(pg_relation_size(relid)) AS table_size,
+ pg_size_pretty(pg_indexes_size(relid)) AS indexes_size,
+ (SELECT COUNT(*) FROM audit_logs) AS total_records
+FROM pg_catalog.pg_statio_user_tables
+WHERE relname = 'audit_logs'
+ORDER BY pg_total_relation_size(relid) DESC;
+```
+
+Should you wish to purge these records, it is safe to do so. This can only be done by running SQL queries
+directly against the `audit_logs` table in the database. We advise users to only purge old records (>1yr)
+and in accordance with your compliance requirements.
+
+### Backup/Archive
+
+Consider exporting or archiving these records before deletion:
+
+```sql
+-- Export to CSV
+COPY (SELECT * FROM audit_logs WHERE time < CURRENT_TIMESTAMP - INTERVAL '1 year')
+TO '/path/to/audit_logs_archive.csv' DELIMITER ',' CSV HEADER;
+
+-- Copy to archive table
+CREATE TABLE audit_logs_archive AS
+SELECT * FROM audit_logs WHERE time < CURRENT_TIMESTAMP - INTERVAL '1 year';
+```
+
+### Permanent Deletion
+
+> [!NOTE]
+> For large `audit_logs` tables, consider running the `DELETE` operation during maintenance windows as it may impact
+> database performance. You can also batch the deletions to reduce lock time.
+
+```sql
+DELETE FROM audit_logs WHERE time < CURRENT_TIMESTAMP - INTERVAL '1 year';
+-- Consider running `VACUUM VERBOSE audit_logs` afterwards for large datasets to reclaim disk space.
+```
+
## How to Enable Audit Logs
-This feature is only available with a [Premium license](../licensing/index.md).
+This feature is only available with a [Premium license](../licensing/index.md), and is automatically enabled.
From d93629bcdef67be9547b1f061c887c05dbd532e6 Mon Sep 17 00:00:00 2001
From: Marcin Tojek
Date: Thu, 2 Oct 2025 15:07:49 +0200
Subject: [PATCH 040/298] fix: check permission to update username (#20139)
---
coderd/users.go | 8 ++++++
coderd/users_test.go | 63 ++++++++++++++++++++++++++++++++++++++++----
2 files changed, 66 insertions(+), 5 deletions(-)
diff --git a/coderd/users.go b/coderd/users.go
index 1e592d010c077..e24790e7455e7 100644
--- a/coderd/users.go
+++ b/coderd/users.go
@@ -753,6 +753,14 @@ func (api *API) putUserProfile(rw http.ResponseWriter, r *http.Request) {
if !httpapi.Read(ctx, rw, r, ¶ms) {
return
}
+
+ // If caller wants to update user's username, they need "update_users" permission.
+ // This is restricted to user admins only.
+ if params.Username != user.Username && !api.Authorize(r, policy.ActionUpdate, user) {
+ httpapi.ResourceNotFound(rw)
+ return
+ }
+
existentUser, err := api.Database.GetUserByEmailOrUsername(ctx, database.GetUserByEmailOrUsernameParams{
Username: params.Username,
})
diff --git a/coderd/users_test.go b/coderd/users_test.go
index 22c9fad5eebea..283b607e89df9 100644
--- a/coderd/users_test.go
+++ b/coderd/users_test.go
@@ -1051,7 +1051,7 @@ func TestUpdateUserProfile(t *testing.T) {
require.Equal(t, database.AuditActionWrite, auditor.AuditLogs()[numLogs-1].Action)
})
- t.Run("UpdateSelfAsMember", func(t *testing.T) {
+ t.Run("UpdateSelfAsMember_Name", func(t *testing.T) {
t.Parallel()
auditor := audit.NewMock()
client := coderdtest.New(t, &coderdtest.Options{Auditor: auditor})
@@ -1060,29 +1060,82 @@ func TestUpdateUserProfile(t *testing.T) {
firstUser := coderdtest.CreateFirstUser(t, client)
numLogs++ // add an audit log for login
- memberClient, _ := coderdtest.CreateAnotherUser(t, client, firstUser.OrganizationID)
+ memberClient, memberUser := coderdtest.CreateAnotherUser(t, client, firstUser.OrganizationID)
numLogs++ // add an audit log for user creation
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
defer cancel()
- newUsername := coderdtest.RandomUsername(t)
newName := coderdtest.RandomName(t)
userProfile, err := memberClient.UpdateUserProfile(ctx, codersdk.Me, codersdk.UpdateUserProfileRequest{
- Username: newUsername,
Name: newName,
+ Username: memberUser.Username,
})
numLogs++ // add an audit log for user update
numLogs++ // add an audit log for API key creation
require.NoError(t, err)
- require.Equal(t, newUsername, userProfile.Username)
+ require.Equal(t, memberUser.Username, userProfile.Username)
require.Equal(t, newName, userProfile.Name)
require.Len(t, auditor.AuditLogs(), numLogs)
require.Equal(t, database.AuditActionWrite, auditor.AuditLogs()[numLogs-1].Action)
})
+ t.Run("UpdateSelfAsMember_Username", func(t *testing.T) {
+ t.Parallel()
+ auditor := audit.NewMock()
+ client := coderdtest.New(t, &coderdtest.Options{Auditor: auditor})
+
+ firstUser := coderdtest.CreateFirstUser(t, client)
+ memberClient, memberUser := coderdtest.CreateAnotherUser(t, client, firstUser.OrganizationID)
+
+ ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
+ defer cancel()
+
+ newUsername := coderdtest.RandomUsername(t)
+ _, err := memberClient.UpdateUserProfile(ctx, codersdk.Me, codersdk.UpdateUserProfileRequest{
+ Name: memberUser.Name,
+ Username: newUsername,
+ })
+
+ var apiErr *codersdk.Error
+ require.ErrorAs(t, err, &apiErr)
+ require.Equal(t, http.StatusNotFound, apiErr.StatusCode())
+ })
+
+ t.Run("UpdateMemberAsAdmin_Username", func(t *testing.T) {
+ t.Parallel()
+ auditor := audit.NewMock()
+ adminClient := coderdtest.New(t, &coderdtest.Options{Auditor: auditor})
+ numLogs := len(auditor.AuditLogs())
+
+ adminUser := coderdtest.CreateFirstUser(t, adminClient)
+ numLogs++ // add an audit log for login
+
+ _, memberUser := coderdtest.CreateAnotherUser(t, adminClient, adminUser.OrganizationID)
+ numLogs++ // add an audit log for user creation
+
+ ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
+ defer cancel()
+
+ newUsername := coderdtest.RandomUsername(t)
+ userProfile, err := adminClient.UpdateUserProfile(ctx, codersdk.Me, codersdk.UpdateUserProfileRequest{
+ Name: memberUser.Name,
+ Username: newUsername,
+ })
+
+ numLogs++ // add an audit log for user update
+ numLogs++ // add an audit log for API key creation
+
+ require.NoError(t, err)
+ require.Equal(t, newUsername, userProfile.Username)
+ require.Equal(t, memberUser.Name, userProfile.Name)
+
+ require.Len(t, auditor.AuditLogs(), numLogs)
+ require.Equal(t, database.AuditActionWrite, auditor.AuditLogs()[numLogs-1].Action)
+ })
+
t.Run("InvalidRealUserName", func(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, nil)
From 1f71c2c12957218dcde03ed087d3fea50d312308 Mon Sep 17 00:00:00 2001
From: Cian Johnston
Date: Thu, 2 Oct 2025 14:59:22 +0100
Subject: [PATCH 041/298] ci(.github/workflows/traiage.yaml): fix task URL in
github comment (#20142)
---
.github/workflows/traiage.yaml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/traiage.yaml b/.github/workflows/traiage.yaml
index 09881ff2ee46a..30eeb5cb8bb48 100644
--- a/.github/workflows/traiage.yaml
+++ b/.github/workflows/traiage.yaml
@@ -217,7 +217,7 @@ jobs:
echo "Creating task: $TASK_NAME"
./scripts/traiage.sh create
if [[ "${ISSUE_URL}" == "https://github.com/${GITHUB_REPOSITORY}"* ]]; then
- gh issue comment "${ISSUE_URL}" --body "Task created: ${TASK_NAME}" --create-if-none --edit-last
+ gh issue comment "${ISSUE_URL}" --body "Task created: https://dev.coder.com/tasks/${CODER_USERNAME}/${TASK_NAME}" --create-if-none --edit-last
else
echo "Skipping comment on other repo."
fi
From c517aabe43add821ee8c39b760a6740b548600d2 Mon Sep 17 00:00:00 2001
From: Rafael Rodriguez
Date: Thu, 2 Oct 2025 09:32:40 -0500
Subject: [PATCH 042/298] fix: add heartbeat to keep dynamic params websocket
open (#20026)
## Summary
In this pull request we're adding a heartbeat to the
`handleParameterWebsocket` function to ensure that the connection stays
open until the 30 min timeout has been reached.
Closes: https://github.com/coder/coder/issues/19805
### Testing
- Reproduced the problem mentioned in the issue (websocket connection
closes after ~10 minutes of inactivity on the create workspace page)
- Confirmed that adding the heartbeat kept the connection open until the
30 min timeout was reached
---
coderd/parameters.go | 2 ++
1 file changed, 2 insertions(+)
diff --git a/coderd/parameters.go b/coderd/parameters.go
index 4b8b13486934f..cb24dcd4312ec 100644
--- a/coderd/parameters.go
+++ b/coderd/parameters.go
@@ -139,6 +139,8 @@ func (api *API) handleParameterWebsocket(rw http.ResponseWriter, r *http.Request
})
return
}
+ go httpapi.Heartbeat(ctx, conn)
+
stream := wsjson.NewStream[codersdk.DynamicParametersRequest, codersdk.DynamicParametersResponse](
conn,
websocket.MessageText,
From 0d2ccacacdec7f00cb76808af89cc570b18ef3f1 Mon Sep 17 00:00:00 2001
From: Danielle Maywood
Date: Thu, 2 Oct 2025 15:39:11 +0100
Subject: [PATCH 043/298] chore: update to coder/clistat v1.0.1 (#20143)
Update https://github.com/coder/clistat to v1.0.1. This release has two
bug fixes.
---
go.mod | 2 +-
go.sum | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/go.mod b/go.mod
index 34967b03a7060..c375c113f143b 100644
--- a/go.mod
+++ b/go.mod
@@ -462,7 +462,7 @@ require (
sigs.k8s.io/yaml v1.5.0 // indirect
)
-require github.com/coder/clistat v1.0.0
+require github.com/coder/clistat v1.0.1
require github.com/SherClockHolmes/webpush-go v1.4.0
diff --git a/go.sum b/go.sum
index ecc9506cbe700..03c0c1bc96e8b 100644
--- a/go.sum
+++ b/go.sum
@@ -919,8 +919,8 @@ github.com/coder/boundary v1.0.1-0.20250925154134-55a44f2a7945 h1:hDUf02kTX8EGR3
github.com/coder/boundary v1.0.1-0.20250925154134-55a44f2a7945/go.mod h1:d1AMFw81rUgrGHuZzWdPNhkY0G8w7pvLNLYF0e3ceC4=
github.com/coder/bubbletea v1.2.2-0.20241212190825-007a1cdb2c41 h1:SBN/DA63+ZHwuWwPHPYoCZ/KLAjHv5g4h2MS4f2/MTI=
github.com/coder/bubbletea v1.2.2-0.20241212190825-007a1cdb2c41/go.mod h1:I9ULxr64UaOSUv7hcb3nX4kowodJCVS7vt7VVJk/kW4=
-github.com/coder/clistat v1.0.0 h1:MjiS7qQ1IobuSSgDnxcCSyBPESs44hExnh2TEqMcGnA=
-github.com/coder/clistat v1.0.0/go.mod h1:F+gLef+F9chVrleq808RBxdaoq52R4VLopuLdAsh8Y4=
+github.com/coder/clistat v1.0.1 h1:0ZgnKr1C4Z0ukG1z1+RUa8Z4OoIgWIH2hdxWSXQTubE=
+github.com/coder/clistat v1.0.1/go.mod h1:F+gLef+F9chVrleq808RBxdaoq52R4VLopuLdAsh8Y4=
github.com/coder/flog v1.1.0 h1:kbAes1ai8fIS5OeV+QAnKBQE22ty1jRF/mcAwHpLBa4=
github.com/coder/flog v1.1.0/go.mod h1:UQlQvrkJBvnRGo69Le8E24Tcl5SJleAAR7gYEHzAmdQ=
github.com/coder/glog v1.0.1-0.20220322161911-7365fe7f2cd1/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4=
From 4d1003eace5f0604ac61786137db813e9a2ac01f Mon Sep 17 00:00:00 2001
From: Zach <3724288+zedkipp@users.noreply.github.com>
Date: Thu, 2 Oct 2025 11:43:13 -0600
Subject: [PATCH 044/298] fix: remove initial global HTTP client usage (#20128)
This PR makes the initial steps at removing usage of the global Go HTTP
client, which was seen to have impacts on test flakiness in
https://github.com/coder/internal/issues/1020. The first commit removes
uses from tests, with the exception of one test that is tightly coupled
to the default client. The second commit makes easy/low-risk removals
from application code. This should have some impact to reduce test flakiness.
---
agent/agent_test.go | 3 ++-
agent/apphealth.go | 3 ++-
cli/server_test.go | 6 ++++--
cli/ssh_test.go | 3 ++-
coderd/healthcheck/accessurl_test.go | 2 +-
coderd/healthcheck/derphealth/derp_test.go | 3 ++-
coderd/mcp/mcp_e2e_test.go | 18 ++++++++++--------
coderd/oauth2_metadata_test.go | 6 ++++--
coderd/promoauth/oauth2_test.go | 3 ++-
coderd/telemetry/telemetry.go | 4 +++-
codersdk/agentsdk/agentsdk_test.go | 9 ++++++---
enterprise/cli/provisionerdaemonstart_test.go | 3 ++-
enterprise/cli/proxyserver_test.go | 3 ++-
enterprise/cli/server_test.go | 3 ++-
enterprise/coderd/coderd_test.go | 3 ++-
enterprise/wsproxy/wsproxy_test.go | 11 +++++++----
enterprise/x/aibridged/aibridged_test.go | 3 ++-
site/site_test.go | 6 ++++--
18 files changed, 59 insertions(+), 33 deletions(-)
diff --git a/agent/agent_test.go b/agent/agent_test.go
index e8b3b99a95387..d4c857dc39637 100644
--- a/agent/agent_test.go
+++ b/agent/agent_test.go
@@ -2027,7 +2027,8 @@ func runSubAgentMain() int {
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
defer cancel()
req = req.WithContext(ctx)
- resp, err := http.DefaultClient.Do(req)
+ client := &http.Client{}
+ resp, err := client.Do(req)
if err != nil {
_, _ = fmt.Fprintf(os.Stderr, "agent connection failed: %v\n", err)
return 11
diff --git a/agent/apphealth.go b/agent/apphealth.go
index 1c4e1d126902c..4fb551077a30f 100644
--- a/agent/apphealth.go
+++ b/agent/apphealth.go
@@ -63,6 +63,7 @@ func NewAppHealthReporterWithClock(
// run a ticker for each app health check.
var mu sync.RWMutex
failures := make(map[uuid.UUID]int, 0)
+ client := &http.Client{}
for _, nextApp := range apps {
if !shouldStartTicker(nextApp) {
continue
@@ -91,7 +92,7 @@ func NewAppHealthReporterWithClock(
if err != nil {
return err
}
- res, err := http.DefaultClient.Do(req)
+ res, err := client.Do(req)
if err != nil {
return err
}
diff --git a/cli/server_test.go b/cli/server_test.go
index 18d59f7811fc3..0748786765cb8 100644
--- a/cli/server_test.go
+++ b/cli/server_test.go
@@ -1254,8 +1254,9 @@ func TestServer(t *testing.T) {
t.Logf("error creating request: %s", err.Error())
return false
}
+ client := &http.Client{}
// nolint:bodyclose
- res, err := http.DefaultClient.Do(req)
+ res, err := client.Do(req)
if err != nil {
t.Logf("error hitting prometheus endpoint: %s", err.Error())
return false
@@ -1316,8 +1317,9 @@ func TestServer(t *testing.T) {
t.Logf("error creating request: %s", err.Error())
return false
}
+ client := &http.Client{}
// nolint:bodyclose
- res, err := http.DefaultClient.Do(req)
+ res, err := client.Do(req)
if err != nil {
t.Logf("error hitting prometheus endpoint: %s", err.Error())
return false
diff --git a/cli/ssh_test.go b/cli/ssh_test.go
index be3166cc4d32a..652e0e9c01996 100644
--- a/cli/ssh_test.go
+++ b/cli/ssh_test.go
@@ -1242,7 +1242,8 @@ func TestSSH(t *testing.T) {
// true exits the loop.
return true
}
- resp, err := http.DefaultClient.Do(req)
+ client := &http.Client{}
+ resp, err := client.Do(req)
if err != nil {
t.Logf("HTTP GET http://localhost:8222/ %s", err)
return false
diff --git a/coderd/healthcheck/accessurl_test.go b/coderd/healthcheck/accessurl_test.go
index 29bf008346b37..85f362959718e 100644
--- a/coderd/healthcheck/accessurl_test.go
+++ b/coderd/healthcheck/accessurl_test.go
@@ -55,7 +55,7 @@ func TestAccessURL(t *testing.T) {
defer cancel()
report.Run(ctx, &healthcheck.AccessURLReportOptions{
- Client: nil, // defaults to http.DefaultClient
+ Client: &http.Client{},
AccessURL: nil,
})
diff --git a/coderd/healthcheck/derphealth/derp_test.go b/coderd/healthcheck/derphealth/derp_test.go
index c009ea982d620..08dc7db97f982 100644
--- a/coderd/healthcheck/derphealth/derp_test.go
+++ b/coderd/healthcheck/derphealth/derp_test.go
@@ -511,7 +511,8 @@ func tsDERPMap(ctx context.Context, t testing.TB) *tailcfg.DERPMap {
req, err := http.NewRequestWithContext(ctx, "GET", ipn.DefaultControlURL+"/derpmap/default", nil)
require.NoError(t, err)
- res, err := http.DefaultClient.Do(req)
+ client := &http.Client{}
+ res, err := client.Do(req)
require.NoError(t, err)
defer res.Body.Close()
require.Equal(t, http.StatusOK, res.StatusCode)
diff --git a/coderd/mcp/mcp_e2e_test.go b/coderd/mcp/mcp_e2e_test.go
index 2813757a50310..f101cfbdd5b65 100644
--- a/coderd/mcp/mcp_e2e_test.go
+++ b/coderd/mcp/mcp_e2e_test.go
@@ -141,7 +141,8 @@ func TestMCPHTTP_E2E_UnauthenticatedAccess(t *testing.T) {
require.NoError(t, err, "Should be able to create HTTP request")
req.Header.Set("Content-Type", "application/json")
- resp, err := http.DefaultClient.Do(req)
+ client := &http.Client{}
+ resp, err := client.Do(req)
require.NoError(t, err, "Should be able to make HTTP request")
defer resp.Body.Close()
@@ -613,7 +614,7 @@ func TestMCPHTTP_E2E_OAuth2_EndToEnd(t *testing.T) {
require.NoError(t, err)
tokenReq.Header.Set("Content-Type", "application/x-www-form-urlencoded")
- tokenResp, err := http.DefaultClient.Do(tokenReq)
+ tokenResp, err := client.Do(tokenReq)
require.NoError(t, err)
defer tokenResp.Body.Close()
@@ -711,7 +712,7 @@ func TestMCPHTTP_E2E_OAuth2_EndToEnd(t *testing.T) {
require.NoError(t, err)
refreshReq.Header.Set("Content-Type", "application/x-www-form-urlencoded")
- refreshResp, err := http.DefaultClient.Do(refreshReq)
+ refreshResp, err := client.Do(refreshReq)
require.NoError(t, err)
defer refreshResp.Body.Close()
@@ -846,7 +847,7 @@ func TestMCPHTTP_E2E_OAuth2_EndToEnd(t *testing.T) {
regReq.Header.Set("Content-Type", "application/json")
// Dynamic client registration should not require authentication (public endpoint)
- regResp, err := http.DefaultClient.Do(regReq)
+ regResp, err := client.Do(regReq)
require.NoError(t, err)
defer regResp.Body.Close()
@@ -936,7 +937,7 @@ func TestMCPHTTP_E2E_OAuth2_EndToEnd(t *testing.T) {
require.NoError(t, err)
tokenReq.Header.Set("Content-Type", "application/x-www-form-urlencoded")
- tokenResp, err := http.DefaultClient.Do(tokenReq)
+ tokenResp, err := client.Do(tokenReq)
require.NoError(t, err)
defer tokenResp.Body.Close()
@@ -1037,7 +1038,7 @@ func TestMCPHTTP_E2E_OAuth2_EndToEnd(t *testing.T) {
require.NoError(t, err)
refreshReq.Header.Set("Content-Type", "application/x-www-form-urlencoded")
- refreshResp, err := http.DefaultClient.Do(refreshReq)
+ refreshResp, err := client.Do(refreshReq)
require.NoError(t, err)
defer refreshResp.Body.Close()
@@ -1151,7 +1152,8 @@ func TestMCPHTTP_E2E_OAuth2_EndToEnd(t *testing.T) {
require.NoError(t, err)
regReq1.Header.Set("Content-Type", "application/json")
- regResp1, err := http.DefaultClient.Do(regReq1)
+ client := &http.Client{}
+ regResp1, err := client.Do(regReq1)
require.NoError(t, err)
defer regResp1.Body.Close()
@@ -1181,7 +1183,7 @@ func TestMCPHTTP_E2E_OAuth2_EndToEnd(t *testing.T) {
require.NoError(t, err)
regReq2.Header.Set("Content-Type", "application/json")
- regResp2, err := http.DefaultClient.Do(regReq2)
+ regResp2, err := client.Do(regReq2)
require.NoError(t, err)
defer regResp2.Body.Close()
diff --git a/coderd/oauth2_metadata_test.go b/coderd/oauth2_metadata_test.go
index a3e8ec1f50571..0e7ff4b1a8743 100644
--- a/coderd/oauth2_metadata_test.go
+++ b/coderd/oauth2_metadata_test.go
@@ -29,7 +29,8 @@ func TestOAuth2AuthorizationServerMetadata(t *testing.T) {
req, err := http.NewRequestWithContext(ctx, http.MethodGet, endpoint, nil)
require.NoError(t, err)
- resp, err := http.DefaultClient.Do(req)
+ httpClient := &http.Client{}
+ resp, err := httpClient.Do(req)
require.NoError(t, err)
defer resp.Body.Close()
@@ -65,7 +66,8 @@ func TestOAuth2ProtectedResourceMetadata(t *testing.T) {
req, err := http.NewRequestWithContext(ctx, http.MethodGet, endpoint, nil)
require.NoError(t, err)
- resp, err := http.DefaultClient.Do(req)
+ httpClient := &http.Client{}
+ resp, err := httpClient.Do(req)
require.NoError(t, err)
defer resp.Body.Close()
diff --git a/coderd/promoauth/oauth2_test.go b/coderd/promoauth/oauth2_test.go
index 5aeec4f0fb949..ab8e7c33146f7 100644
--- a/coderd/promoauth/oauth2_test.go
+++ b/coderd/promoauth/oauth2_test.go
@@ -94,7 +94,8 @@ func TestInstrument(t *testing.T) {
must[*url.URL](t)(idp.IssuerURL().Parse("/.well-known/openid-configuration")).String(), nil)
require.NoError(t, err)
- resp, err := http.DefaultClient.Do(req)
+ client := &http.Client{}
+ resp, err := client.Do(req)
require.NoError(t, err)
_ = resp.Body.Close()
diff --git a/coderd/telemetry/telemetry.go b/coderd/telemetry/telemetry.go
index 8f203126c99ba..075083adaa96d 100644
--- a/coderd/telemetry/telemetry.go
+++ b/coderd/telemetry/telemetry.go
@@ -87,6 +87,7 @@ func New(options Options) (Reporter, error) {
deploymentURL: deploymentURL,
snapshotURL: snapshotURL,
startedAt: dbtime.Now(),
+ client: &http.Client{},
}
go reporter.runSnapshotter()
return reporter, nil
@@ -119,6 +120,7 @@ type remoteReporter struct {
snapshotURL *url.URL
startedAt time.Time
shutdownAt *time.Time
+ client *http.Client
}
func (r *remoteReporter) Enabled() bool {
@@ -142,7 +144,7 @@ func (r *remoteReporter) reportSync(snapshot *Snapshot) {
return
}
req.Header.Set(VersionHeader, buildinfo.Version())
- resp, err := http.DefaultClient.Do(req)
+ resp, err := r.client.Do(req)
if err != nil {
// If the request fails it's not necessarily an error.
// In an airgapped environment, it's fine if this fails!
diff --git a/codersdk/agentsdk/agentsdk_test.go b/codersdk/agentsdk/agentsdk_test.go
index 4f3d7d838b524..b6646662a4536 100644
--- a/codersdk/agentsdk/agentsdk_test.go
+++ b/codersdk/agentsdk/agentsdk_test.go
@@ -42,7 +42,8 @@ func TestStreamAgentReinitEvents(t *testing.T) {
requestCtx := testutil.Context(t, testutil.WaitShort)
req, err := http.NewRequestWithContext(requestCtx, "GET", srv.URL, nil)
require.NoError(t, err)
- resp, err := http.DefaultClient.Do(req)
+ client := &http.Client{}
+ resp, err := client.Do(req)
require.NoError(t, err)
defer resp.Body.Close()
@@ -77,7 +78,8 @@ func TestStreamAgentReinitEvents(t *testing.T) {
requestCtx := testutil.Context(t, testutil.WaitShort)
req, err := http.NewRequestWithContext(requestCtx, "GET", srv.URL, nil)
require.NoError(t, err)
- resp, err := http.DefaultClient.Do(req)
+ client := &http.Client{}
+ resp, err := client.Do(req)
require.NoError(t, err)
defer resp.Body.Close()
@@ -110,7 +112,8 @@ func TestStreamAgentReinitEvents(t *testing.T) {
requestCtx := testutil.Context(t, testutil.WaitShort)
req, err := http.NewRequestWithContext(requestCtx, "GET", srv.URL, nil)
require.NoError(t, err)
- resp, err := http.DefaultClient.Do(req)
+ client := &http.Client{}
+ resp, err := client.Do(req)
require.NoError(t, err)
defer resp.Body.Close()
diff --git a/enterprise/cli/provisionerdaemonstart_test.go b/enterprise/cli/provisionerdaemonstart_test.go
index 58603715f8184..884c3e6436e9e 100644
--- a/enterprise/cli/provisionerdaemonstart_test.go
+++ b/enterprise/cli/provisionerdaemonstart_test.go
@@ -495,6 +495,7 @@ func TestProvisionerDaemon_PrometheusEnabled(t *testing.T) {
// Fetch metrics from Prometheus endpoint
var req *http.Request
var res *http.Response
+ httpClient := &http.Client{}
require.Eventually(t, func() bool {
req, err = http.NewRequestWithContext(ctx, "GET", fmt.Sprintf("http://127.0.0.1:%d", prometheusPort), nil)
if err != nil {
@@ -503,7 +504,7 @@ func TestProvisionerDaemon_PrometheusEnabled(t *testing.T) {
}
// nolint:bodyclose
- res, err = http.DefaultClient.Do(req)
+ res, err = httpClient.Do(req)
if err != nil {
t.Logf("unable to call Prometheus endpoint: %s", err.Error())
return false
diff --git a/enterprise/cli/proxyserver_test.go b/enterprise/cli/proxyserver_test.go
index ae01f6ac9dda6..b8df3d2c6a072 100644
--- a/enterprise/cli/proxyserver_test.go
+++ b/enterprise/cli/proxyserver_test.go
@@ -114,11 +114,12 @@ func TestWorkspaceProxy_Server_PrometheusEnabled(t *testing.T) {
// Fetch metrics from Prometheus endpoint
var res *http.Response
+ client := &http.Client{}
require.Eventually(t, func() bool {
req, err := http.NewRequestWithContext(ctx, "GET", fmt.Sprintf("http://127.0.0.1:%d", prometheusPort), nil)
assert.NoError(t, err)
// nolint:bodyclose
- res, err = http.DefaultClient.Do(req)
+ res, err = client.Do(req)
return err == nil
}, testutil.WaitShort, testutil.IntervalFast)
defer res.Body.Close()
diff --git a/enterprise/cli/server_test.go b/enterprise/cli/server_test.go
index 7489699a6f3dd..38001b701a9c1 100644
--- a/enterprise/cli/server_test.go
+++ b/enterprise/cli/server_test.go
@@ -43,13 +43,14 @@ func TestServer_Single(t *testing.T) {
)
clitest.Start(t, inv.WithContext(ctx))
accessURL := waitAccessURL(t, cfg)
+ client := &http.Client{}
require.Eventually(t, func() bool {
reqCtx := testutil.Context(t, testutil.IntervalMedium)
req, err := http.NewRequestWithContext(reqCtx, http.MethodGet, accessURL.String()+"/healthz", nil)
if err != nil {
panic(err)
}
- resp, err := http.DefaultClient.Do(req)
+ resp, err := client.Do(req)
if err != nil {
t.Log("/healthz not ready yet")
return false
diff --git a/enterprise/coderd/coderd_test.go b/enterprise/coderd/coderd_test.go
index 302b367c304cd..860c4135e0c1e 100644
--- a/enterprise/coderd/coderd_test.go
+++ b/enterprise/coderd/coderd_test.go
@@ -595,6 +595,7 @@ func TestSCIMDisabled(t *testing.T) {
"/scim/v2/random/path/that/is/long.txt",
}
+ client := &http.Client{}
for _, p := range checkPaths {
t.Run(p, func(t *testing.T) {
t.Parallel()
@@ -605,7 +606,7 @@ func TestSCIMDisabled(t *testing.T) {
req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, u.String(), nil)
require.NoError(t, err)
- resp, err := http.DefaultClient.Do(req)
+ resp, err := client.Do(req)
require.NoError(t, err)
defer resp.Body.Close()
require.Equal(t, http.StatusNotFound, resp.StatusCode)
diff --git a/enterprise/wsproxy/wsproxy_test.go b/enterprise/wsproxy/wsproxy_test.go
index 5d7eaada7f990..03245999350cd 100644
--- a/enterprise/wsproxy/wsproxy_test.go
+++ b/enterprise/wsproxy/wsproxy_test.go
@@ -689,12 +689,13 @@ func TestWorkspaceProxyDERPMeshProbe(t *testing.T) {
t.Log("all replicas have pinged")
// Check they're all healthy according to /healthz-report.
+ httpClient := &http.Client{}
for _, proxy := range proxies {
// GET /healthz-report
u := proxy.ServerURL.ResolveReference(&url.URL{Path: "/healthz-report"})
req, err := http.NewRequestWithContext(ctx, http.MethodGet, u.String(), nil)
require.NoError(t, err)
- resp, err := http.DefaultClient.Do(req)
+ resp, err := httpClient.Do(req)
require.NoError(t, err)
var respJSON codersdk.ProxyHealthReport
@@ -781,7 +782,8 @@ func TestWorkspaceProxyDERPMeshProbe(t *testing.T) {
u := proxy.ServerURL.ResolveReference(&url.URL{Path: "/healthz-report"})
req, err := http.NewRequestWithContext(ctx, http.MethodGet, u.String(), nil)
require.NoError(t, err)
- resp, err := http.DefaultClient.Do(req)
+ httpClient := &http.Client{}
+ resp, err := httpClient.Do(req)
require.NoError(t, err)
var respJSON codersdk.ProxyHealthReport
@@ -869,7 +871,8 @@ func TestWorkspaceProxyDERPMeshProbe(t *testing.T) {
u := proxy.ServerURL.ResolveReference(&url.URL{Path: "/healthz-report"})
req, err := http.NewRequestWithContext(ctx, http.MethodGet, u.String(), nil)
require.NoError(t, err)
- resp, err := http.DefaultClient.Do(req)
+ httpClient := &http.Client{}
+ resp, err := httpClient.Do(req)
require.NoError(t, err)
var respJSON codersdk.ProxyHealthReport
err = json.NewDecoder(resp.Body).Decode(&respJSON)
@@ -903,7 +906,7 @@ func TestWorkspaceProxyDERPMeshProbe(t *testing.T) {
// GET /healthz-report
req, err = http.NewRequestWithContext(ctx, http.MethodGet, u.String(), nil)
require.NoError(t, err)
- resp, err = http.DefaultClient.Do(req)
+ resp, err = httpClient.Do(req)
require.NoError(t, err)
err = json.NewDecoder(resp.Body).Decode(&respJSON)
resp.Body.Close()
diff --git a/enterprise/x/aibridged/aibridged_test.go b/enterprise/x/aibridged/aibridged_test.go
index 22210a00f34f3..32ef4870623ee 100644
--- a/enterprise/x/aibridged/aibridged_test.go
+++ b/enterprise/x/aibridged/aibridged_test.go
@@ -70,6 +70,7 @@ func TestServeHTTP_FailureModes(t *testing.T) {
t.Parallel()
defaultHeaders := map[string]string{"Authorization": "Bearer key"}
+ httpClient := &http.Client{}
cases := []struct {
name string
@@ -155,7 +156,7 @@ func TestServeHTTP_FailureModes(t *testing.T) {
req.Header.Set(k, v)
}
- resp, err := http.DefaultClient.Do(req)
+ resp, err := httpClient.Do(req)
t.Cleanup(func() {
if resp == nil || resp.Body == nil {
return
diff --git a/site/site_test.go b/site/site_test.go
index fa3c0809f22a7..36ec124ef8bc8 100644
--- a/site/site_test.go
+++ b/site/site_test.go
@@ -232,6 +232,7 @@ func TestServingFiles(t *testing.T) {
Database: db,
}))
defer srv.Close()
+ client := &http.Client{}
// Create a context
ctx, cancelFunc := context.WithTimeout(context.Background(), testutil.WaitShort)
@@ -275,7 +276,7 @@ func TestServingFiles(t *testing.T) {
req, err := http.NewRequestWithContext(ctx, "GET", path, nil)
require.NoError(t, err)
- resp, err := http.DefaultClient.Do(req)
+ resp, err := client.Do(req)
require.NoError(t, err, "get file")
data, _ := io.ReadAll(resp.Body)
require.Equal(t, string(data), testCase.expected, "Verify file: "+testCase.path)
@@ -521,6 +522,7 @@ func TestServingBin(t *testing.T) {
compressor := middleware.NewCompressor(1, "text/*", "application/*")
srv := httptest.NewServer(compressor.Handler(site))
defer srv.Close()
+ client := &http.Client{}
// Create a context
ctx, cancelFunc := context.WithTimeout(context.Background(), testutil.WaitShort)
@@ -538,7 +540,7 @@ func TestServingBin(t *testing.T) {
req.Header.Set("Accept-Encoding", "gzip")
}
- resp, err := http.DefaultClient.Do(req)
+ resp, err := client.Do(req)
require.NoError(t, err, "http do failed")
defer resp.Body.Close()
From ffcb7a169379ea9d8b83fa39bd4a7f727b82ad0d Mon Sep 17 00:00:00 2001
From: Cian Johnston
Date: Thu, 2 Oct 2025 19:54:07 +0100
Subject: [PATCH 045/298] fix(coderd): truncate task prompt to 160 characters
in notifications (#20147)
Truncates the task prompt used in notifications to a maximum of 160
characters. The length of 160 characters was chosen arbitrarily.
---
coderd/aitasks_test.go | 29 +++++++++++++--
coderd/util/strings/strings.go | 55 +++++++++++++++++++++++++++--
coderd/util/strings/strings_test.go | 47 +++++++++++++++++++-----
coderd/workspaceagents.go | 5 +++
4 files changed, 123 insertions(+), 13 deletions(-)
diff --git a/coderd/aitasks_test.go b/coderd/aitasks_test.go
index 20b33e9314da4..6425e06c771db 100644
--- a/coderd/aitasks_test.go
+++ b/coderd/aitasks_test.go
@@ -6,8 +6,10 @@ import (
"io"
"net/http"
"net/http/httptest"
+ "strings"
"testing"
"time"
+ "unicode/utf8"
"github.com/google/uuid"
"github.com/stretchr/testify/assert"
@@ -977,6 +979,7 @@ func TestTasksNotification(t *testing.T) {
isAITask bool
isNotificationSent bool
notificationTemplate uuid.UUID
+ taskPrompt string
}{
// Should not send a notification when the agent app is not an AI task.
{
@@ -985,6 +988,7 @@ func TestTasksNotification(t *testing.T) {
newAppStatus: codersdk.WorkspaceAppStatusStateWorking,
isAITask: false,
isNotificationSent: false,
+ taskPrompt: "NoAITask",
},
// Should not send a notification when the new app status is neither 'Working' nor 'Idle'.
{
@@ -993,6 +997,7 @@ func TestTasksNotification(t *testing.T) {
newAppStatus: codersdk.WorkspaceAppStatusStateComplete,
isAITask: true,
isNotificationSent: false,
+ taskPrompt: "NonNotifiedState",
},
// Should not send a notification when the new app status equals the latest status (Working).
{
@@ -1001,6 +1006,7 @@ func TestTasksNotification(t *testing.T) {
newAppStatus: codersdk.WorkspaceAppStatusStateWorking,
isAITask: true,
isNotificationSent: false,
+ taskPrompt: "NonNotifiedTransition",
},
// Should send TemplateTaskWorking when the AI task transitions to 'Working'.
{
@@ -1010,6 +1016,7 @@ func TestTasksNotification(t *testing.T) {
isAITask: true,
isNotificationSent: true,
notificationTemplate: notifications.TemplateTaskWorking,
+ taskPrompt: "TemplateTaskWorking",
},
// Should send TemplateTaskWorking when the AI task transitions to 'Working' from 'Idle'.
{
@@ -1022,6 +1029,7 @@ func TestTasksNotification(t *testing.T) {
isAITask: true,
isNotificationSent: true,
notificationTemplate: notifications.TemplateTaskWorking,
+ taskPrompt: "TemplateTaskWorkingFromIdle",
},
// Should send TemplateTaskIdle when the AI task transitions to 'Idle'.
{
@@ -1031,6 +1039,17 @@ func TestTasksNotification(t *testing.T) {
isAITask: true,
isNotificationSent: true,
notificationTemplate: notifications.TemplateTaskIdle,
+ taskPrompt: "TemplateTaskIdle",
+ },
+ // Long task prompts should be truncated to 160 characters.
+ {
+ name: "LongTaskPrompt",
+ latestAppStatuses: []codersdk.WorkspaceAppStatusState{codersdk.WorkspaceAppStatusStateWorking},
+ newAppStatus: codersdk.WorkspaceAppStatusStateIdle,
+ isAITask: true,
+ isNotificationSent: true,
+ notificationTemplate: notifications.TemplateTaskIdle,
+ taskPrompt: "This is a very long task prompt that should be truncated to 160 characters. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
},
} {
t.Run(tc.name, func(t *testing.T) {
@@ -1067,7 +1086,7 @@ func TestTasksNotification(t *testing.T) {
}).Seed(workspaceBuildSeed).Params(database.WorkspaceBuildParameter{
WorkspaceBuildID: workspaceBuildID,
Name: codersdk.AITaskPromptParameterName,
- Value: "task prompt",
+ Value: tc.taskPrompt,
}).WithAgent(func(agent []*proto.Agent) []*proto.Agent {
agent[0].Apps = []*proto.App{{
Id: workspaceAgentAppID.String(),
@@ -1115,7 +1134,13 @@ func TestTasksNotification(t *testing.T) {
require.Len(t, sent, 1)
require.Equal(t, memberUser.ID, sent[0].UserID)
require.Len(t, sent[0].Labels, 2)
- require.Equal(t, "task prompt", sent[0].Labels["task"])
+ // NOTE: len(string) is the number of bytes in the string, not the number of runes.
+ require.LessOrEqual(t, utf8.RuneCountInString(sent[0].Labels["task"]), 160)
+ if len(tc.taskPrompt) > 160 {
+ require.Contains(t, tc.taskPrompt, strings.TrimSuffix(sent[0].Labels["task"], "…"))
+ } else {
+ require.Equal(t, tc.taskPrompt, sent[0].Labels["task"])
+ }
require.Equal(t, workspace.Name, sent[0].Labels["workspace"])
} else {
// Then: No notification is sent
diff --git a/coderd/util/strings/strings.go b/coderd/util/strings/strings.go
index 49aad579e83f5..e21908d488cd8 100644
--- a/coderd/util/strings/strings.go
+++ b/coderd/util/strings/strings.go
@@ -23,15 +23,64 @@ func JoinWithConjunction(s []string) string {
)
}
-// Truncate returns the first n characters of s.
-func Truncate(s string, n int) string {
+type TruncateOption int
+
+func (o TruncateOption) String() string {
+ switch o {
+ case TruncateWithEllipsis:
+ return "TruncateWithEllipsis"
+ case TruncateWithFullWords:
+ return "TruncateWithFullWords"
+ default:
+ return fmt.Sprintf("TruncateOption(%d)", o)
+ }
+}
+
+const (
+ // TruncateWithEllipsis adds a Unicode ellipsis character to the end of the string.
+ TruncateWithEllipsis TruncateOption = 1 << 0
+ // TruncateWithFullWords ensures that words are not split in the middle.
+ // As a special case, if there is no word boundary, the string is truncated.
+ TruncateWithFullWords TruncateOption = 1 << 1
+)
+
+// Truncate truncates s to n characters.
+// Additional behaviors can be specified using TruncateOptions.
+func Truncate(s string, n int, opts ...TruncateOption) string {
+ var options TruncateOption
+ for _, opt := range opts {
+ options |= opt
+ }
if n < 1 {
return ""
}
if len(s) <= n {
return s
}
- return s[:n]
+
+ maxLen := n
+ if options&TruncateWithEllipsis != 0 {
+ maxLen--
+ }
+ var sb strings.Builder
+ // If we need to truncate to full words, find the last word boundary before n.
+ if options&TruncateWithFullWords != 0 {
+ lastWordBoundary := strings.LastIndexFunc(s[:maxLen], unicode.IsSpace)
+ if lastWordBoundary < 0 {
+ // We cannot find a word boundary. At this point, we'll truncate the string.
+ // It's better than nothing.
+ _, _ = sb.WriteString(s[:maxLen])
+ } else { // lastWordBoundary <= maxLen
+ _, _ = sb.WriteString(s[:lastWordBoundary])
+ }
+ } else {
+ _, _ = sb.WriteString(s[:maxLen])
+ }
+
+ if options&TruncateWithEllipsis != 0 {
+ _, _ = sb.WriteString("…")
+ }
+ return sb.String()
}
var bmPolicy = bluemonday.StrictPolicy()
diff --git a/coderd/util/strings/strings_test.go b/coderd/util/strings/strings_test.go
index 7a20a06a25f28..000fa9efa11e5 100644
--- a/coderd/util/strings/strings_test.go
+++ b/coderd/util/strings/strings_test.go
@@ -1,6 +1,7 @@
package strings_test
import (
+ "fmt"
"testing"
"github.com/stretchr/testify/assert"
@@ -23,17 +24,47 @@ func TestTruncate(t *testing.T) {
s string
n int
expected string
+ options []strings.TruncateOption
}{
- {"foo", 4, "foo"},
- {"foo", 3, "foo"},
- {"foo", 2, "fo"},
- {"foo", 1, "f"},
- {"foo", 0, ""},
- {"foo", -1, ""},
+ {"foo", 4, "foo", nil},
+ {"foo", 3, "foo", nil},
+ {"foo", 2, "fo", nil},
+ {"foo", 1, "f", nil},
+ {"foo", 0, "", nil},
+ {"foo", -1, "", nil},
+ {"foo bar", 7, "foo bar", []strings.TruncateOption{strings.TruncateWithEllipsis}},
+ {"foo bar", 6, "foo b…", []strings.TruncateOption{strings.TruncateWithEllipsis}},
+ {"foo bar", 5, "foo …", []strings.TruncateOption{strings.TruncateWithEllipsis}},
+ {"foo bar", 4, "foo…", []strings.TruncateOption{strings.TruncateWithEllipsis}},
+ {"foo bar", 3, "fo…", []strings.TruncateOption{strings.TruncateWithEllipsis}},
+ {"foo bar", 2, "f…", []strings.TruncateOption{strings.TruncateWithEllipsis}},
+ {"foo bar", 1, "…", []strings.TruncateOption{strings.TruncateWithEllipsis}},
+ {"foo bar", 0, "", []strings.TruncateOption{strings.TruncateWithEllipsis}},
+ {"foo bar", 7, "foo bar", []strings.TruncateOption{strings.TruncateWithFullWords}},
+ {"foo bar", 6, "foo", []strings.TruncateOption{strings.TruncateWithFullWords}},
+ {"foo bar", 5, "foo", []strings.TruncateOption{strings.TruncateWithFullWords}},
+ {"foo bar", 4, "foo", []strings.TruncateOption{strings.TruncateWithFullWords}},
+ {"foo bar", 3, "foo", []strings.TruncateOption{strings.TruncateWithFullWords}},
+ {"foo bar", 2, "fo", []strings.TruncateOption{strings.TruncateWithFullWords}},
+ {"foo bar", 1, "f", []strings.TruncateOption{strings.TruncateWithFullWords}},
+ {"foo bar", 0, "", []strings.TruncateOption{strings.TruncateWithFullWords}},
+ {"foo bar", 7, "foo bar", []strings.TruncateOption{strings.TruncateWithFullWords, strings.TruncateWithEllipsis}},
+ {"foo bar", 6, "foo…", []strings.TruncateOption{strings.TruncateWithFullWords, strings.TruncateWithEllipsis}},
+ {"foo bar", 5, "foo…", []strings.TruncateOption{strings.TruncateWithFullWords, strings.TruncateWithEllipsis}},
+ {"foo bar", 4, "foo…", []strings.TruncateOption{strings.TruncateWithFullWords, strings.TruncateWithEllipsis}},
+ {"foo bar", 3, "fo…", []strings.TruncateOption{strings.TruncateWithFullWords, strings.TruncateWithEllipsis}},
+ {"foo bar", 2, "f…", []strings.TruncateOption{strings.TruncateWithFullWords, strings.TruncateWithEllipsis}},
+ {"foo bar", 1, "…", []strings.TruncateOption{strings.TruncateWithFullWords, strings.TruncateWithEllipsis}},
+ {"foo bar", 0, "", []strings.TruncateOption{strings.TruncateWithFullWords, strings.TruncateWithEllipsis}},
+ {"This is a very long task prompt that should be truncated to 160 characters. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.", 160, "This is a very long task prompt that should be truncated to 160 characters. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor…", []strings.TruncateOption{strings.TruncateWithFullWords, strings.TruncateWithEllipsis}},
} {
- t.Run(tt.expected, func(t *testing.T) {
+ tName := fmt.Sprintf("%s_%d", tt.s, tt.n)
+ for _, opt := range tt.options {
+ tName += fmt.Sprintf("_%v", opt)
+ }
+ t.Run(tName, func(t *testing.T) {
t.Parallel()
- actual := strings.Truncate(tt.s, tt.n)
+ actual := strings.Truncate(tt.s, tt.n, tt.options...)
require.Equal(t, tt.expected, actual)
})
}
diff --git a/coderd/workspaceagents.go b/coderd/workspaceagents.go
index eddd6510b634b..0e6d0430e3642 100644
--- a/coderd/workspaceagents.go
+++ b/coderd/workspaceagents.go
@@ -484,6 +484,11 @@ func (api *API) enqueueAITaskStateNotification(
}
}
+ // As task prompt may be particularly long, truncate it to 160 characters for notifications.
+ if len(taskName) > 160 {
+ taskName = strutil.Truncate(taskName, 160, strutil.TruncateWithEllipsis, strutil.TruncateWithFullWords)
+ }
+
if _, err := api.NotificationsEnqueuer.EnqueueWithData(
// nolint:gocritic // Need notifier actor to enqueue notifications
dbauthz.AsNotifier(ctx),
From 039fa894814fd95923e44988a4e6fb7c820390d6 Mon Sep 17 00:00:00 2001
From: yyefimov
Date: Thu, 2 Oct 2025 22:08:15 -0400
Subject: [PATCH 046/298] fix(coderd): correct the name of the unmarshall error
variable (#20150)
Incorrect error variable is used during reporting of the issue during
unmarshall operations and this makes it hard to understand the
underlying reason for OIDC failure: use `unmarshalError` instead of
`err`.
---
coderd/oauthpki/oidcpki.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/coderd/oauthpki/oidcpki.go b/coderd/oauthpki/oidcpki.go
index d761c43e446ff..fa1c3854af1dd 100644
--- a/coderd/oauthpki/oidcpki.go
+++ b/coderd/oauthpki/oidcpki.go
@@ -247,7 +247,7 @@ func (src *jwtTokenSource) Token() (*oauth2.Token, error) {
}
if unmarshalError != nil {
- return nil, xerrors.Errorf("oauth2: cannot unmarshal token: %w", err)
+ return nil, xerrors.Errorf("oauth2: cannot unmarshal token: %w", unmarshalError)
}
newToken := &oauth2.Token{
From 091b5c88d66d4e111209d39c79e005bfda4532db Mon Sep 17 00:00:00 2001
From: Cian Johnston
Date: Fri, 3 Oct 2025 09:24:55 +0100
Subject: [PATCH 047/298] =?UTF-8?q?ci(.github/workflows/traiage.yaml):=20a?=
=?UTF-8?q?djust=20prompt=20for=20legibility=20when=E2=80=A6=20(#20144)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
… truncated, just like this
---
.github/workflows/traiage.yaml | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/.github/workflows/traiage.yaml b/.github/workflows/traiage.yaml
index 30eeb5cb8bb48..483673d2ba798 100644
--- a/.github/workflows/traiage.yaml
+++ b/.github/workflows/traiage.yaml
@@ -203,11 +203,10 @@ jobs:
# Write a prompt to PROMPT_FILE
PROMPT=$(cat <
Date: Fri, 3 Oct 2025 10:01:08 +0100
Subject: [PATCH 048/298] ci(.github/workflows/traiage.yaml): remove extraneous
cleanup steps (#20154)
---
.github/workflows/traiage.yaml | 69 ----------------------------------
1 file changed, 69 deletions(-)
diff --git a/.github/workflows/traiage.yaml b/.github/workflows/traiage.yaml
index 483673d2ba798..15adf78242686 100644
--- a/.github/workflows/traiage.yaml
+++ b/.github/workflows/traiage.yaml
@@ -25,11 +25,6 @@ on:
required: false
default: "traiage"
type: string
- cleanup:
- description: "Cleanup workspace after triage."
- required: false
- default: false
- type: boolean
jobs:
traiage:
@@ -70,7 +65,6 @@ jobs:
GITHUB_EVENT_NAME: ${{ github.event_name }}
GITHUB_EVENT_USER_ID: ${{ github.event.sender.id }}
GITHUB_EVENT_USER_LOGIN: ${{ github.event.sender.login }}
- INPUTS_CLEANUP: ${{ inputs.cleanup || false }}
INPUTS_ISSUE_URL: ${{ inputs.issue_url }}
INPUTS_TEMPLATE_NAME: ${{ inputs.template_name || 'traiage' }}
INPUTS_TEMPLATE_PRESET: ${{ inputs.template_preset || 'Default'}}
@@ -86,9 +80,6 @@ jobs:
echo "Using prefix: ${INPUTS_PREFIX}"
echo "prefix=${INPUTS_PREFIX}" >> "${GITHUB_OUTPUT}"
- echo "Using cleanup: ${INPUTS_CLEANUP}"
- echo "cleanup=${INPUTS_CLEANUP}" >> "${GITHUB_OUTPUT}"
-
# For workflow_dispatch, use the actor who triggered it
# For issues events, use the issue author.
if [[ "${GITHUB_EVENT_NAME}" == "workflow_dispatch" ]]; then
@@ -222,63 +213,3 @@ jobs:
fi
echo "TASK_NAME=${CODER_USERNAME}/${TASK_NAME}" >> "${GITHUB_OUTPUT}"
echo "TASK_NAME=${CODER_USERNAME}/${TASK_NAME}" >> "${GITHUB_ENV}"
-
- - name: Create and upload archive
- id: create-archive
- if: steps.determine-inputs.outputs.cleanup == 'true'
- env:
- BUCKET_PREFIX: "gs://coder-traiage-outputs/traiage"
- CODER_USERNAME: ${{ steps.get-coder-username.outputs.coder_username }}
- TASK_NAME: ${{ steps.create-task.outputs.TASK_NAME }}
- run: |
- echo "Waiting for task to complete..."
- coder exp task status "${TASK_NAME}" --watch
- echo "Creating archive for workspace: ${TASK_NAME}"
- ./scripts/traiage.sh archive
- echo "archive_url=${BUCKET_PREFIX%%/}/$TASK_NAME.tar.gz" >> "${GITHUB_OUTPUT}"
-
- - name: Generate a summary of the changes and post a comment on GitHub.
- id: generate-summary
- if: steps.determine-inputs.outputs.cleanup == 'true'
- env:
- ARCHIVE_URL: ${{ steps.create-archive.outputs.archive_url }}
- BUCKET_PREFIX: "gs://coder-traiage-outputs/traiage"
- CODER_USERNAME: ${{ steps.get-coder-username.outputs.coder_username }}
- CONTEXT_KEY: ${{ steps.extract-context.outputs.context_key }}
- GH_TOKEN: ${{ github.token }}
- GITHUB_REPOSITORY: ${{ github.repository }}
- ISSUE_URL: ${{ steps.determine-inputs.outputs.issue_url }}
- TASK_NAME: ${{ steps.create-task.outputs.TASK_NAME }}
- run: |
- SUMMARY_FILE=$(mktemp)
- trap 'rm -f "${SUMMARY_FILE}"' EXIT
- AUTO_SUMMARY=$(./scripts/traiage.sh summary)
- {
- echo "## TrAIage Results"
- echo "- **Issue URL:** ${ISSUE_URL}"
- echo "- **Context Key:** ${CONTEXT_KEY}"
- echo "- **Workspace:** ${TASK_NAME}"
- echo "- **Archive URL:** ${ARCHIVE_URL}"
- echo
- echo "${AUTO_SUMMARY}"
- echo
- echo "To fetch the output to your own workspace:"
- echo
- echo '```bash'
- echo "BUCKET_PREFIX=${BUCKET_PREFIX} TASK_NAME=${TASK_NAME} ./scripts/traiage.sh resume"
- echo '```'
- echo
- } >> "${SUMMARY_FILE}"
-
- if [[ "${ISSUE_URL}" == "https://github.com/${GITHUB_REPOSITORY}"* ]]; then
- gh issue comment "${ISSUE_URL}" --body-file "${SUMMARY_FILE}" --create-if-none --edit-last
- else
- echo "Skipping comment on other repo."
- fi
- cat "${SUMMARY_FILE}" >> "${GITHUB_STEP_SUMMARY}"
-
- - name: Cleanup task
- if: steps.determine-inputs.outputs.cleanup == 'true' && steps.create-task.outputs.TASK_NAME != '' && steps.create-archive.outputs.archive_url != ''
- run: |
- echo "Cleaning up task: $TASK_NAME"
- ./scripts/traiage.sh delete || true
From e1619daacc95f00b8bd181f993f62fbc4fa3a27a Mon Sep 17 00:00:00 2001
From: Cian Johnston
Date: Fri, 3 Oct 2025 10:17:43 +0100
Subject: [PATCH 049/298] chore(coderd): update aitasks.go to leverage
agentapi-sdk-go (#20159)
I only recently became aware of the existence of `agentapi-sdk-go`.
Updates `aitasks.go` to make use of it.
---
coderd/aitasks.go | 168 ++++++++--------------------------------------
1 file changed, 27 insertions(+), 141 deletions(-)
diff --git a/coderd/aitasks.go b/coderd/aitasks.go
index 31600c69443b4..275cfe855621e 100644
--- a/coderd/aitasks.go
+++ b/coderd/aitasks.go
@@ -1,17 +1,13 @@
package coderd
import (
- "bytes"
"context"
"database/sql"
- "encoding/json"
"errors"
"fmt"
- "io"
"net"
"net/http"
"net/url"
- "path"
"slices"
"strings"
"time"
@@ -31,6 +27,8 @@ import (
"github.com/coder/coder/v2/coderd/taskname"
"github.com/coder/coder/v2/coderd/util/slice"
"github.com/coder/coder/v2/codersdk"
+
+ aiagentapi "github.com/coder/agentapi-sdk-go"
)
// This endpoint is experimental and not guaranteed to be stable, so we're not
@@ -629,61 +627,37 @@ func (api *API) taskSend(rw http.ResponseWriter, r *http.Request) {
}
if err = api.authAndDoWithTaskSidebarAppClient(r, taskID, func(ctx context.Context, client *http.Client, appURL *url.URL) error {
- status, err := agentapiDoStatusRequest(ctx, client, appURL)
+ agentAPIClient, err := aiagentapi.NewClient(appURL.String(), aiagentapi.WithHTTPClient(client))
if err != nil {
- return err
- }
-
- if status != "stable" {
return httperror.NewResponseError(http.StatusBadGateway, codersdk.Response{
- Message: "Task app is not ready to accept input.",
- Detail: fmt.Sprintf("Status: %s", status),
+ Message: "Failed to create agentapi client.",
+ Detail: err.Error(),
})
}
- var reqBody struct {
- Content string `json:"content"`
- Type string `json:"type"`
- }
- reqBody.Content = req.Input
- reqBody.Type = "user"
-
- req, err := agentapiNewRequest(ctx, http.MethodPost, appURL, "message", reqBody)
- if err != nil {
- return err
- }
-
- resp, err := client.Do(req)
+ statusResp, err := agentAPIClient.GetStatus(ctx)
if err != nil {
return httperror.NewResponseError(http.StatusBadGateway, codersdk.Response{
- Message: "Failed to reach task app endpoint.",
+ Message: "Failed to get status from task app.",
Detail: err.Error(),
})
}
- defer resp.Body.Close()
-
- if resp.StatusCode != http.StatusOK {
- body, _ := io.ReadAll(io.LimitReader(resp.Body, 128))
- return httperror.NewResponseError(http.StatusBadGateway, codersdk.Response{
- Message: "Task app rejected the message.",
- Detail: fmt.Sprintf("Upstream status: %d; Body: %s", resp.StatusCode, body),
- })
- }
- // {"$schema":"http://localhost:3284/schemas/MessageResponseBody.json","ok":true}
- // {"$schema":"http://localhost:3284/schemas/ErrorModel.json","title":"Unprocessable Entity","status":422,"detail":"validation failed","errors":[{"location":"body.type","value":"oof"}]}
- var respBody map[string]any
- if err := json.NewDecoder(resp.Body).Decode(&respBody); err != nil {
+ if statusResp.Status != aiagentapi.StatusStable {
return httperror.NewResponseError(http.StatusBadGateway, codersdk.Response{
- Message: "Failed to decode task app response body.",
- Detail: err.Error(),
+ Message: "Task app is not ready to accept input.",
+ Detail: fmt.Sprintf("Status: %s", statusResp.Status),
})
}
- if v, ok := respBody["ok"].(bool); !ok || !v {
+ _, err = agentAPIClient.PostMessage(ctx, aiagentapi.PostMessageParams{
+ Content: req.Input,
+ Type: aiagentapi.MessageTypeUser,
+ })
+ if err != nil {
return httperror.NewResponseError(http.StatusBadGateway, codersdk.Response{
Message: "Task app rejected the message.",
- Detail: fmt.Sprintf("Upstream response: %v", respBody),
+ Detail: err.Error(),
})
}
@@ -710,51 +684,29 @@ func (api *API) taskLogs(rw http.ResponseWriter, r *http.Request) {
var out codersdk.TaskLogsResponse
if err := api.authAndDoWithTaskSidebarAppClient(r, taskID, func(ctx context.Context, client *http.Client, appURL *url.URL) error {
- req, err := agentapiNewRequest(ctx, http.MethodGet, appURL, "messages", nil)
- if err != nil {
- return err
- }
-
- resp, err := client.Do(req)
+ agentAPIClient, err := aiagentapi.NewClient(appURL.String(), aiagentapi.WithHTTPClient(client))
if err != nil {
return httperror.NewResponseError(http.StatusBadGateway, codersdk.Response{
- Message: "Failed to reach task app endpoint.",
+ Message: "Failed to create agentapi client.",
Detail: err.Error(),
})
}
- defer resp.Body.Close()
-
- if resp.StatusCode != http.StatusOK {
- body, _ := io.ReadAll(io.LimitReader(resp.Body, 128))
- return httperror.NewResponseError(http.StatusBadGateway, codersdk.Response{
- Message: "Task app rejected the request.",
- Detail: fmt.Sprintf("Upstream status: %d; Body: %s", resp.StatusCode, body),
- })
- }
- // {"$schema":"http://localhost:3284/schemas/MessagesResponseBody.json","messages":[]}
- var respBody struct {
- Messages []struct {
- ID int `json:"id"`
- Content string `json:"content"`
- Role string `json:"role"`
- Time time.Time `json:"time"`
- } `json:"messages"`
- }
- if err := json.NewDecoder(resp.Body).Decode(&respBody); err != nil {
+ messagesResp, err := agentAPIClient.GetMessages(ctx)
+ if err != nil {
return httperror.NewResponseError(http.StatusBadGateway, codersdk.Response{
- Message: "Failed to decode task app response body.",
+ Message: "Failed to get messages from task app.",
Detail: err.Error(),
})
}
- logs := make([]codersdk.TaskLogEntry, 0, len(respBody.Messages))
- for _, m := range respBody.Messages {
+ logs := make([]codersdk.TaskLogEntry, 0, len(messagesResp.Messages))
+ for _, m := range messagesResp.Messages {
var typ codersdk.TaskLogType
- switch strings.ToLower(m.Role) {
- case "user":
+ switch m.Role {
+ case aiagentapi.RoleUser:
typ = codersdk.TaskLogTypeInput
- case "agent":
+ case aiagentapi.RoleAgent:
typ = codersdk.TaskLogTypeOutput
default:
return httperror.NewResponseError(http.StatusBadGateway, codersdk.Response{
@@ -763,7 +715,7 @@ func (api *API) taskLogs(rw http.ResponseWriter, r *http.Request) {
})
}
logs = append(logs, codersdk.TaskLogEntry{
- ID: m.ID,
+ ID: int(m.Id),
Content: m.Content,
Type: typ,
Time: m.Time,
@@ -903,69 +855,3 @@ func (api *API) authAndDoWithTaskSidebarAppClient(
}
return do(ctx, client, parsedURL)
}
-
-func agentapiNewRequest(ctx context.Context, method string, appURL *url.URL, appURLPath string, body any) (*http.Request, error) {
- u := *appURL
- u.Path = path.Join(appURL.Path, appURLPath)
-
- var bodyReader io.Reader
- if body != nil {
- b, err := json.Marshal(body)
- if err != nil {
- return nil, httperror.NewResponseError(http.StatusBadRequest, codersdk.Response{
- Message: "Failed to marshal task app request body.",
- Detail: err.Error(),
- })
- }
- bodyReader = bytes.NewReader(b)
- }
-
- req, err := http.NewRequestWithContext(ctx, method, u.String(), bodyReader)
- if err != nil {
- return nil, httperror.NewResponseError(http.StatusBadRequest, codersdk.Response{
- Message: "Failed to create task app request.",
- Detail: err.Error(),
- })
- }
- req.Header.Set("Content-Type", "application/json")
- req.Header.Set("Accept", "application/json")
-
- return req, nil
-}
-
-func agentapiDoStatusRequest(ctx context.Context, client *http.Client, appURL *url.URL) (string, error) {
- req, err := agentapiNewRequest(ctx, http.MethodGet, appURL, "status", nil)
- if err != nil {
- return "", err
- }
-
- resp, err := client.Do(req)
- if err != nil {
- return "", httperror.NewResponseError(http.StatusBadGateway, codersdk.Response{
- Message: "Failed to reach task app endpoint.",
- Detail: err.Error(),
- })
- }
- defer resp.Body.Close()
-
- if resp.StatusCode != http.StatusOK {
- return "", httperror.NewResponseError(http.StatusBadGateway, codersdk.Response{
- Message: "Task app status returned an error.",
- Detail: fmt.Sprintf("Status code: %d", resp.StatusCode),
- })
- }
-
- // {"$schema":"http://localhost:3284/schemas/StatusResponseBody.json","status":"stable"}
- var respBody struct {
- Status string `json:"status"`
- }
-
- if err := json.NewDecoder(resp.Body).Decode(&respBody); err != nil {
- return "", httperror.NewResponseError(http.StatusBadGateway, codersdk.Response{
- Message: "Failed to decode task app status response body.",
- Detail: err.Error(),
- })
- }
-
- return respBody.Status, nil
-}
From 2b4485575c1c095430a4f2a877cc6a37e5c25cf3 Mon Sep 17 00:00:00 2001
From: Ethan <39577870+ethanndickson@users.noreply.github.com>
Date: Fri, 3 Oct 2025 20:50:21 +1000
Subject: [PATCH 050/298] feat(scaletest): add `autostart` scaletest command
(#20161)
Closes https://github.com/coder/internal/issues/911
---
cli/exp_scaletest.go | 235 +++++++++++++++++++++++++++++++++++++
scaletest/autostart/run.go | 1 +
2 files changed, 236 insertions(+)
diff --git a/cli/exp_scaletest.go b/cli/exp_scaletest.go
index 4a8852cf8a4fc..e6a3993035512 100644
--- a/cli/exp_scaletest.go
+++ b/cli/exp_scaletest.go
@@ -33,6 +33,7 @@ import (
"github.com/coder/coder/v2/codersdk"
"github.com/coder/coder/v2/codersdk/workspacesdk"
"github.com/coder/coder/v2/scaletest/agentconn"
+ "github.com/coder/coder/v2/scaletest/autostart"
"github.com/coder/coder/v2/scaletest/createusers"
"github.com/coder/coder/v2/scaletest/createworkspaces"
"github.com/coder/coder/v2/scaletest/dashboard"
@@ -60,6 +61,7 @@ func (r *RootCmd) scaletestCmd() *serpent.Command {
r.scaletestCreateWorkspaces(),
r.scaletestWorkspaceUpdates(),
r.scaletestWorkspaceTraffic(),
+ r.scaletestAutostart(),
},
}
@@ -1682,6 +1684,239 @@ func (r *RootCmd) scaletestDashboard() *serpent.Command {
return cmd
}
+const (
+ autostartTestName = "autostart"
+)
+
+func (r *RootCmd) scaletestAutostart() *serpent.Command {
+ var (
+ workspaceCount int64
+ workspaceJobTimeout time.Duration
+ autostartDelay time.Duration
+ autostartTimeout time.Duration
+ template string
+ noCleanup bool
+
+ parameterFlags workspaceParameterFlags
+ tracingFlags = &scaletestTracingFlags{}
+ timeoutStrategy = &timeoutFlags{}
+ cleanupStrategy = newScaletestCleanupStrategy()
+ output = &scaletestOutputFlags{}
+ prometheusFlags = &scaletestPrometheusFlags{}
+ )
+
+ cmd := &serpent.Command{
+ Use: "autostart",
+ Short: "Replicate a thundering herd of autostarting workspaces",
+ Handler: func(inv *serpent.Invocation) error {
+ ctx := inv.Context()
+ client, err := r.InitClient(inv)
+ if err != nil {
+ return err
+ }
+
+ notifyCtx, stop := signal.NotifyContext(ctx, StopSignals...) // Checked later.
+ defer stop()
+ ctx = notifyCtx
+
+ me, err := requireAdmin(ctx, client)
+ if err != nil {
+ return err
+ }
+
+ client.HTTPClient = &http.Client{
+ Transport: &codersdk.HeaderTransport{
+ Transport: http.DefaultTransport,
+ Header: map[string][]string{
+ codersdk.BypassRatelimitHeader: {"true"},
+ },
+ },
+ }
+
+ if workspaceCount <= 0 {
+ return xerrors.Errorf("--workspace-count must be greater than zero")
+ }
+
+ outputs, err := output.parse()
+ if err != nil {
+ return xerrors.Errorf("could not parse --output flags")
+ }
+
+ tpl, err := parseTemplate(ctx, client, me.OrganizationIDs, template)
+ if err != nil {
+ return xerrors.Errorf("parse template: %w", err)
+ }
+
+ cliRichParameters, err := asWorkspaceBuildParameters(parameterFlags.richParameters)
+ if err != nil {
+ return xerrors.Errorf("can't parse given parameter values: %w", err)
+ }
+
+ richParameters, err := prepWorkspaceBuild(inv, client, prepWorkspaceBuildArgs{
+ Action: WorkspaceCreate,
+ TemplateVersionID: tpl.ActiveVersionID,
+
+ RichParameterFile: parameterFlags.richParameterFile,
+ RichParameters: cliRichParameters,
+ })
+ if err != nil {
+ return xerrors.Errorf("prepare build: %w", err)
+ }
+
+ tracerProvider, closeTracing, tracingEnabled, err := tracingFlags.provider(ctx)
+ if err != nil {
+ return xerrors.Errorf("create tracer provider: %w", err)
+ }
+ tracer := tracerProvider.Tracer(scaletestTracerName)
+
+ reg := prometheus.NewRegistry()
+ metrics := autostart.NewMetrics(reg)
+
+ setupBarrier := new(sync.WaitGroup)
+ setupBarrier.Add(int(workspaceCount))
+
+ th := harness.NewTestHarness(timeoutStrategy.wrapStrategy(harness.ConcurrentExecutionStrategy{}), cleanupStrategy.toStrategy())
+ for i := range workspaceCount {
+ id := strconv.Itoa(int(i))
+ config := autostart.Config{
+ User: createusers.Config{
+ OrganizationID: me.OrganizationIDs[0],
+ },
+ Workspace: workspacebuild.Config{
+ OrganizationID: me.OrganizationIDs[0],
+ Request: codersdk.CreateWorkspaceRequest{
+ TemplateID: tpl.ID,
+ RichParameterValues: richParameters,
+ },
+ },
+ WorkspaceJobTimeout: workspaceJobTimeout,
+ AutostartDelay: autostartDelay,
+ AutostartTimeout: autostartTimeout,
+ Metrics: metrics,
+ SetupBarrier: setupBarrier,
+ }
+ if err := config.Validate(); err != nil {
+ return xerrors.Errorf("validate config: %w", err)
+ }
+ var runner harness.Runnable = autostart.NewRunner(client, config)
+ if tracingEnabled {
+ runner = &runnableTraceWrapper{
+ tracer: tracer,
+ spanName: fmt.Sprintf("%s/%s", autostartTestName, id),
+ runner: runner,
+ }
+ }
+ th.AddRun(autostartTestName, id, runner)
+ }
+
+ logger := inv.Logger
+ prometheusSrvClose := ServeHandler(ctx, logger, promhttp.HandlerFor(reg, promhttp.HandlerOpts{}), prometheusFlags.Address, "prometheus")
+ defer prometheusSrvClose()
+
+ defer func() {
+ _, _ = fmt.Fprintln(inv.Stderr, "\nUploading traces...")
+ if err := closeTracing(ctx); err != nil {
+ _, _ = fmt.Fprintf(inv.Stderr, "\nError uploading traces: %+v\n", err)
+ }
+ // Wait for prometheus metrics to be scraped
+ _, _ = fmt.Fprintf(inv.Stderr, "Waiting %s for prometheus metrics to be scraped\n", prometheusFlags.Wait)
+ <-time.After(prometheusFlags.Wait)
+ }()
+
+ _, _ = fmt.Fprintln(inv.Stderr, "Running autostart load test...")
+ testCtx, testCancel := timeoutStrategy.toContext(ctx)
+ defer testCancel()
+ err = th.Run(testCtx)
+ if err != nil {
+ return xerrors.Errorf("run test harness (harness failure, not a test failure): %w", err)
+ }
+
+ // If the command was interrupted, skip stats.
+ if notifyCtx.Err() != nil {
+ return notifyCtx.Err()
+ }
+
+ res := th.Results()
+ for _, o := range outputs {
+ err = o.write(res, inv.Stdout)
+ if err != nil {
+ return xerrors.Errorf("write output %q to %q: %w", o.format, o.path, err)
+ }
+ }
+
+ if !noCleanup {
+ _, _ = fmt.Fprintln(inv.Stderr, "\nCleaning up...")
+ cleanupCtx, cleanupCancel := cleanupStrategy.toContext(ctx)
+ defer cleanupCancel()
+ err = th.Cleanup(cleanupCtx)
+ if err != nil {
+ return xerrors.Errorf("cleanup tests: %w", err)
+ }
+ }
+
+ if res.TotalFail > 0 {
+ return xerrors.New("load test failed, see above for more details")
+ }
+
+ return nil
+ },
+ }
+
+ cmd.Options = serpent.OptionSet{
+ {
+ Flag: "workspace-count",
+ FlagShorthand: "c",
+ Env: "CODER_SCALETEST_WORKSPACE_COUNT",
+ Description: "Required: Total number of workspaces to create.",
+ Value: serpent.Int64Of(&workspaceCount),
+ Required: true,
+ },
+ {
+ Flag: "workspace-job-timeout",
+ Env: "CODER_SCALETEST_WORKSPACE_JOB_TIMEOUT",
+ Default: "5m",
+ Description: "Timeout for workspace jobs (e.g. build, start).",
+ Value: serpent.DurationOf(&workspaceJobTimeout),
+ },
+ {
+ Flag: "autostart-delay",
+ Env: "CODER_SCALETEST_AUTOSTART_DELAY",
+ Default: "2m",
+ Description: "How long after all the workspaces have been stopped to schedule them to be started again.",
+ Value: serpent.DurationOf(&autostartDelay),
+ },
+ {
+ Flag: "autostart-timeout",
+ Env: "CODER_SCALETEST_AUTOSTART_TIMEOUT",
+ Default: "5m",
+ Description: "Timeout for the autostart build to be initiated after the scheduled start time.",
+ Value: serpent.DurationOf(&autostartTimeout),
+ },
+ {
+ Flag: "template",
+ FlagShorthand: "t",
+ Env: "CODER_SCALETEST_TEMPLATE",
+ Description: "Required: Name or ID of the template to use for workspaces.",
+ Value: serpent.StringOf(&template),
+ Required: true,
+ },
+ {
+ Flag: "no-cleanup",
+ Env: "CODER_SCALETEST_NO_CLEANUP",
+ Description: "Do not clean up resources after the test completes.",
+ Value: serpent.BoolOf(&noCleanup),
+ },
+ }
+
+ cmd.Options = append(cmd.Options, parameterFlags.cliParameters()...)
+ tracingFlags.attach(&cmd.Options)
+ timeoutStrategy.attach(&cmd.Options)
+ cleanupStrategy.attach(&cmd.Options)
+ output.attach(&cmd.Options)
+ prometheusFlags.attach(&cmd.Options)
+ return cmd
+}
+
type runnableTraceWrapper struct {
tracer trace.Tracer
spanName string
diff --git a/scaletest/autostart/run.go b/scaletest/autostart/run.go
index 59f50a04dd837..c37d843ad95c2 100644
--- a/scaletest/autostart/run.go
+++ b/scaletest/autostart/run.go
@@ -80,6 +80,7 @@ func (r *Runner) Run(ctx context.Context, id string, logs io.Writer) error {
workspaceBuildConfig.UserID = newUser.ID.String()
// We'll wait for the build ourselves to avoid multiple API requests
workspaceBuildConfig.NoWaitForBuild = true
+ workspaceBuildConfig.NoWaitForAgents = true
r.workspacebuildRunner = workspacebuild.NewRunner(newUserClient, workspaceBuildConfig)
workspace, err := r.workspacebuildRunner.RunReturningWorkspace(ctx, id, logs)
From a36078519952e4fcf20dfd0ca9d8e2777e9e3650 Mon Sep 17 00:00:00 2001
From: Cian Johnston
Date: Fri, 3 Oct 2025 15:04:20 +0100
Subject: [PATCH 051/298] ci(.github/workflows/traiage.yaml): check instead for
push access to repo (#20163)
---
.github/workflows/traiage.yaml | 13 ++++++-------
1 file changed, 6 insertions(+), 7 deletions(-)
diff --git a/.github/workflows/traiage.yaml b/.github/workflows/traiage.yaml
index 15adf78242686..566cfc78419bc 100644
--- a/.github/workflows/traiage.yaml
+++ b/.github/workflows/traiage.yaml
@@ -110,20 +110,19 @@ jobs:
exit 1
fi
- - name: Verify organization membership
+ - name: Verify push access
env:
- GITHUB_ORG: ${{ github.repository_owner }}
+ GITHUB_REPOSITORY: ${{ github.repository }}
GH_TOKEN: ${{ github.token }}
GITHUB_USERNAME: ${{ steps.determine-inputs.outputs.github_username }}
GITHUB_USER_ID: ${{ steps.determine-inputs.outputs.github_user_id }}
run: |
- # Check if the actor is a member of the organization
- if ! gh api "orgs/${GITHUB_ORG}/members/${GITHUB_USERNAME}" --silent 2>/dev/null; then
- echo "::error title=Access Denied::User ${GITHUB_USERNAME} is not a member of the ${GITHUB_ORG} organization"
- echo "::error::You must be a member of the ${GITHUB_ORG} GitHub organization to run this workflow."
+ # Query the actor’s permission on this repo
+ can_push="$(gh api "/repos/${GITHUB_REPOSITORY}/collaborators/${GITHUB_USERNAME}/permission" --jq '.user.permissions.push')"
+ if [[ "${can_push}" != "true" ]]; then
+ echo "::error title=Access Denied::${GITHUB_USERNAME} does not have push access to ${GITHUB_REPOSITORY}"
exit 1
fi
- echo "::notice::User ${GITHUB_USERNAME} verified as member of ${GITHUB_ORG} organization"
- name: Extract context key from issue
id: extract-context
From bb5884467d7cc441945a8fa9f5334c9b3f9620fd Mon Sep 17 00:00:00 2001
From: Rafael Rodriguez
Date: Fri, 3 Oct 2025 10:20:06 -0500
Subject: [PATCH 052/298] feat(cli): prompt for missing required template
variables on template creation (#19973)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
## Summary
In this pull request we're adding support in the CLI for prompting the
user for any missing required template variables in the `coder templates
push` command and automatically retrying the template build once a user
has provided any missing variable values.
Closes: https://github.com/coder/coder/issues/19782
### Demo
In the following recording I created a simple template terraform file
that used different variable types (string, number, boolean, and
sensitive) and prompted the user to enter a value for each variable.
See example template terraform file
```tf
...
# Required variables for testing interactive prompting
variable "docker_image" {
description = "Docker image to use for the workspace"
type = string
}
variable "workspace_name" {
description = "Name of the workspace"
type = string
}
variable "cpu_limit" {
description = "CPU limit for the container (number of cores)"
type = number
}
variable "enable_gpu" {
description = "Enable GPU access for the container"
type = bool
}
variable "api_key" {
description = "API key for external services (sensitive)"
type = string
sensitive = true
}
# Optional variable with default
variable "docker_socket" {
default = "/var/run/docker.sock"
description = "Docker socket path"
type = string
}
...
```
Once the user entered a valid value for each variable, the template
build would be retried.
https://github.com/user-attachments/assets/770cf954-3cbc-4464-925e-2be4e32a97de
See output from recording
```shell
$ ./scripts/coder-dev.sh templates push test-required-params -d examples/templates/test-required-params/
INFO : Overriding codersdk.SessionTokenCookie as we are developing inside a Coder workspace.
/home/coder/coder/build/coder-slim_2.26.0-devel+a68122ca3_linux_amd64
Provisioner tags:
WARN: No .terraform.lock.hcl file found
| When provisioning, Coder will be unable to cache providers without a lockfile and must download them from the internet each time.
| Create one by running terraform init in your template directory.
> Upload "examples/templates/test-required-params"? (yes/no) yes
=== ✔ Queued [0ms]
==> ⧗ Running
==> ⧗ Running
=== ✔ Running [4ms]
==> ⧗ Setting up
=== ✔ Setting up [0ms]
==> ⧗ Parsing template parameters
=== ✔ Parsing template parameters [8ms]
==> ⧗ Cleaning Up
=== ✘ Cleaning Up [4ms]
=== ✘ Cleaning Up [8ms]
Found 5 missing required variables:
- docker_image (string): Docker image to use for the workspace
- workspace_name (string): Name of the workspace
- cpu_limit (number): CPU limit for the container (number of cores)
- enable_gpu (bool): Enable GPU access for the container
- api_key (string): API key for external services (sensitive)
The template requires values for the following variables:
var.docker_image (required)
Description: Docker image to use for the workspace
Type: string
Current value:
> Enter value: image-name
var.workspace_name (required)
Description: Name of the workspace
Type: string
Current value:
> Enter value: workspace-name
var.cpu_limit (required)
Description: CPU limit for the container (number of cores)
Type: number
Current value:
> Enter value: 1
var.enable_gpu (required)
Description: Enable GPU access for the container
Type: bool
Current value:
? Select value: false
var.api_key (required), sensitive
Description: API key for external services (sensitive)
Type: string
Current value:
> Enter value: (*redacted*) ******
Retrying template build with provided variables...
=== ✔ Queued [0ms]
==> ⧗ Running
==> ⧗ Running
=== ✔ Running [2ms]
==> ⧗ Setting up
=== ✔ Setting up [0ms]
==> ⧗ Parsing template parameters
=== ✔ Parsing template parameters [7ms]
==> ⧗ Detecting persistent resources
2025-09-25 22:34:14.731Z Terraform 1.13.0
2025-09-25 22:34:15.140Z data.coder_provisioner.me: Refreshing...
2025-09-25 22:34:15.140Z data.coder_workspace.me: Refreshing...
2025-09-25 22:34:15.140Z data.coder_workspace_owner.me: Refreshing...
2025-09-25 22:34:15.141Z data.coder_provisioner.me: Refresh complete after 0s [id=2bd73098-d127-4362-b3a5-628e5bce6998]
2025-09-25 22:34:15.141Z data.coder_workspace_owner.me: Refresh complete after 0s [id=c2006933-4f3e-4c45-9e04-79612c3a5eca]
2025-09-25 22:34:15.141Z data.coder_workspace.me: Refresh complete after 0s [id=36f2dc6f-0bf2-43bd-bc4d-b29768334e02]
2025-09-25 22:34:15.186Z coder_agent.main: Plan to create
2025-09-25 22:34:15.186Z module.code-server[0].coder_app.code-server: Plan to create
2025-09-25 22:34:15.186Z docker_volume.home_volume: Plan to create
2025-09-25 22:34:15.186Z module.code-server[0].coder_script.code-server: Plan to create
2025-09-25 22:34:15.187Z docker_container.workspace[0]: Plan to create
2025-09-25 22:34:15.187Z Plan: 5 to add, 0 to change, 0 to destroy.
=== ✔ Detecting persistent resources [3104ms]
==> ⧗ Detecting ephemeral resources
2025-09-25 22:34:16.033Z Terraform 1.13.0
2025-09-25 22:34:16.428Z data.coder_workspace.me: Refreshing...
2025-09-25 22:34:16.428Z data.coder_provisioner.me: Refreshing...
2025-09-25 22:34:16.429Z data.coder_workspace_owner.me: Refreshing...
2025-09-25 22:34:16.429Z data.coder_provisioner.me: Refresh complete after 0s [id=2d2f7083-88e6-425c-9df3-856a3bf4cc73]
2025-09-25 22:34:16.429Z data.coder_workspace.me: Refresh complete after 0s [id=c723575e-c7d3-43d7-bf54-0e34d0959dc3]
2025-09-25 22:34:16.431Z data.coder_workspace_owner.me: Refresh complete after 0s [id=d43470c2-236e-4ae9-a977-6b53688c2cb1]
2025-09-25 22:34:16.453Z coder_agent.main: Plan to create
2025-09-25 22:34:16.453Z docker_volume.home_volume: Plan to create
2025-09-25 22:34:16.454Z Plan: 2 to add, 0 to change, 0 to destroy.
=== ✔ Detecting ephemeral resources [1278ms]
==> ⧗ Cleaning Up
=== ✔ Cleaning Up [6ms]
┌──────────────────────────────────┐
│ Template Preview │
├──────────────────────────────────┤
│ RESOURCE │
├──────────────────────────────────┤
│ docker_container.workspace │
│ └─ main (linux, amd64) │
├──────────────────────────────────┤
│ docker_volume.home_volume │
└──────────────────────────────────┘
The test-required-params template has been created at Sep 25
22:34:16! Developers can provision a workspace with this template using:
Updated version at Sep 25 22:34:16!
```
### Changes
- Added a new function to check if the provisioner failed due to a
template missing required variables
- Added a handler function that is called when a provisioner fails due
to the "missing required variables" error. The handler function will:
- Check for provided template variables and identify any missing
variables
- Prompt the user for any missing variables (prompt is adapted based on
the variable type)
- Validate user input for missing variables
- Retry the template build when all variables have been provided by the
user
### Testing
Added tests for the following scenarios:
- Ensure validation based on variable type
- Ensure users are not prompted for variables with a default value
- Ensure variables provided via a variables files (`--variables-file`)
or a variable flag (`--variable`) take precedence over a template
---
cli/templatepush.go | 161 ++++++++++++++++++-
cli/templatepush_test.go | 282 +++++++++++++++++++++++++++------
codersdk/provisionerdaemons.go | 6 +
codersdk/templatevariables.go | 4 +-
4 files changed, 400 insertions(+), 53 deletions(-)
diff --git a/cli/templatepush.go b/cli/templatepush.go
index 7a21a0f8defad..03e1ca1cee88c 100644
--- a/cli/templatepush.go
+++ b/cli/templatepush.go
@@ -9,6 +9,7 @@ import (
"os"
"path/filepath"
"slices"
+ "strconv"
"strings"
"time"
@@ -461,10 +462,14 @@ func createValidTemplateVersion(inv *serpent.Invocation, args createValidTemplat
})
if err != nil {
var jobErr *cliui.ProvisionerJobError
- if errors.As(err, &jobErr) && !codersdk.JobIsMissingParameterErrorCode(jobErr.Code) {
- return nil, err
+ if errors.As(err, &jobErr) {
+ if codersdk.JobIsMissingRequiredTemplateVariableErrorCode(jobErr.Code) {
+ return handleMissingTemplateVariables(inv, args, version.ID)
+ }
+ if !codersdk.JobIsMissingParameterErrorCode(jobErr.Code) {
+ return nil, err
+ }
}
-
return nil, err
}
version, err = client.TemplateVersion(inv.Context(), version.ID)
@@ -528,3 +533,153 @@ func prettyDirectoryPath(dir string) string {
}
return prettyDir
}
+
+func handleMissingTemplateVariables(inv *serpent.Invocation, args createValidTemplateVersionArgs, failedVersionID uuid.UUID) (*codersdk.TemplateVersion, error) {
+ client := args.Client
+
+ templateVariables, err := client.TemplateVersionVariables(inv.Context(), failedVersionID)
+ if err != nil {
+ return nil, xerrors.Errorf("fetch template variables: %w", err)
+ }
+
+ existingValues := make(map[string]string)
+ for _, v := range args.UserVariableValues {
+ existingValues[v.Name] = v.Value
+ }
+
+ var missingVariables []codersdk.TemplateVersionVariable
+ for _, variable := range templateVariables {
+ if !variable.Required {
+ continue
+ }
+
+ if existingValue, exists := existingValues[variable.Name]; exists && existingValue != "" {
+ continue
+ }
+
+ // Only prompt for variables that don't have a default value or have a redacted default
+ // Sensitive variables have a default value of "*redacted*"
+ // See: https://github.com/coder/coder/blob/a78790c632974e04babfef6de0e2ddf044787a7a/coderd/provisionerdserver/provisionerdserver.go#L3206
+ if variable.DefaultValue == "" || (variable.Sensitive && variable.DefaultValue == "*redacted*") {
+ missingVariables = append(missingVariables, variable)
+ }
+ }
+
+ if len(missingVariables) == 0 {
+ return nil, xerrors.New("no missing required variables found")
+ }
+
+ _, _ = fmt.Fprintf(inv.Stderr, "Found %d missing required variables:\n", len(missingVariables))
+ for _, v := range missingVariables {
+ _, _ = fmt.Fprintf(inv.Stderr, " - %s (%s): %s\n", v.Name, v.Type, v.Description)
+ }
+
+ _, _ = fmt.Fprintln(inv.Stderr, "\nThe template requires values for the following variables:")
+
+ var promptedValues []codersdk.VariableValue
+ for _, variable := range missingVariables {
+ value, err := promptForTemplateVariable(inv, variable)
+ if err != nil {
+ return nil, xerrors.Errorf("prompt for variable %q: %w", variable.Name, err)
+ }
+ promptedValues = append(promptedValues, codersdk.VariableValue{
+ Name: variable.Name,
+ Value: value,
+ })
+ }
+
+ combinedValues := codersdk.CombineVariableValues(args.UserVariableValues, promptedValues)
+
+ _, _ = fmt.Fprintln(inv.Stderr, "\nRetrying template build with provided variables...")
+
+ retryArgs := args
+ retryArgs.UserVariableValues = combinedValues
+
+ return createValidTemplateVersion(inv, retryArgs)
+}
+
+func promptForTemplateVariable(inv *serpent.Invocation, variable codersdk.TemplateVersionVariable) (string, error) {
+ displayVariableInfo(inv, variable)
+
+ switch variable.Type {
+ case "bool":
+ return promptForBoolVariable(inv, variable)
+ case "number":
+ return promptForNumberVariable(inv, variable)
+ default:
+ return promptForStringVariable(inv, variable)
+ }
+}
+
+func displayVariableInfo(inv *serpent.Invocation, variable codersdk.TemplateVersionVariable) {
+ _, _ = fmt.Fprintf(inv.Stderr, "var.%s", cliui.Bold(variable.Name))
+ if variable.Required {
+ _, _ = fmt.Fprint(inv.Stderr, pretty.Sprint(cliui.DefaultStyles.Error, " (required)"))
+ }
+ if variable.Sensitive {
+ _, _ = fmt.Fprint(inv.Stderr, pretty.Sprint(cliui.DefaultStyles.Warn, ", sensitive"))
+ }
+ _, _ = fmt.Fprintln(inv.Stderr, "")
+
+ if variable.Description != "" {
+ _, _ = fmt.Fprintf(inv.Stderr, " Description: %s\n", variable.Description)
+ }
+ _, _ = fmt.Fprintf(inv.Stderr, " Type: %s\n", variable.Type)
+ _, _ = fmt.Fprintf(inv.Stderr, " Current value: %s\n", pretty.Sprint(cliui.DefaultStyles.Placeholder, ""))
+}
+
+func promptForBoolVariable(inv *serpent.Invocation, variable codersdk.TemplateVersionVariable) (string, error) {
+ defaultValue := variable.DefaultValue
+ if defaultValue == "" {
+ defaultValue = "false"
+ }
+
+ return cliui.Select(inv, cliui.SelectOptions{
+ Options: []string{"true", "false"},
+ Default: defaultValue,
+ Message: "Select value:",
+ })
+}
+
+func promptForNumberVariable(inv *serpent.Invocation, variable codersdk.TemplateVersionVariable) (string, error) {
+ prompt := "Enter value:"
+ if !variable.Required && variable.DefaultValue != "" {
+ prompt = fmt.Sprintf("Enter value (default: %q):", variable.DefaultValue)
+ }
+
+ return cliui.Prompt(inv, cliui.PromptOptions{
+ Text: prompt,
+ Default: variable.DefaultValue,
+ Validate: createVariableValidator(variable),
+ })
+}
+
+func promptForStringVariable(inv *serpent.Invocation, variable codersdk.TemplateVersionVariable) (string, error) {
+ prompt := "Enter value:"
+ if !variable.Sensitive {
+ if !variable.Required && variable.DefaultValue != "" {
+ prompt = fmt.Sprintf("Enter value (default: %q):", variable.DefaultValue)
+ }
+ }
+
+ return cliui.Prompt(inv, cliui.PromptOptions{
+ Text: prompt,
+ Default: variable.DefaultValue,
+ Secret: variable.Sensitive,
+ Validate: createVariableValidator(variable),
+ })
+}
+
+func createVariableValidator(variable codersdk.TemplateVersionVariable) func(string) error {
+ return func(s string) error {
+ if variable.Required && s == "" && variable.DefaultValue == "" {
+ return xerrors.New("value is required")
+ }
+ if variable.Type == "number" && s != "" {
+ if _, err := strconv.ParseFloat(s, 64); err != nil {
+ return xerrors.Errorf("must be a valid number, got: %q", s)
+ }
+ }
+ return nil
+ }
+}
diff --git a/cli/templatepush_test.go b/cli/templatepush_test.go
index 7c8007c96a210..28c5adc20f213 100644
--- a/cli/templatepush_test.go
+++ b/cli/templatepush_test.go
@@ -852,54 +852,6 @@ func TestTemplatePush(t *testing.T) {
require.Equal(t, "foobar", templateVariables[1].Value)
})
- t.Run("VariableIsRequiredButNotProvided", func(t *testing.T) {
- t.Parallel()
- client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
- owner := coderdtest.CreateFirstUser(t, client)
- templateAdmin, _ := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID, rbac.RoleTemplateAdmin())
-
- templateVersion := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, createEchoResponsesWithTemplateVariables(initialTemplateVariables))
- _ = coderdtest.AwaitTemplateVersionJobCompleted(t, client, templateVersion.ID)
- template := coderdtest.CreateTemplate(t, client, owner.OrganizationID, templateVersion.ID)
-
- // Test the cli command.
- //nolint:gocritic
- modifiedTemplateVariables := append(initialTemplateVariables,
- &proto.TemplateVariable{
- Name: "second_variable",
- Description: "This is the second variable.",
- Type: "string",
- Required: true,
- },
- )
- source := clitest.CreateTemplateVersionSource(t, createEchoResponsesWithTemplateVariables(modifiedTemplateVariables))
- inv, root := clitest.New(t, "templates", "push", template.Name, "--directory", source, "--test.provisioner", string(database.ProvisionerTypeEcho), "--name", "example")
- clitest.SetupConfig(t, templateAdmin, root)
- pty := ptytest.New(t)
- inv.Stdin = pty.Input()
- inv.Stdout = pty.Output()
-
- execDone := make(chan error)
- go func() {
- execDone <- inv.Run()
- }()
-
- matches := []struct {
- match string
- write string
- }{
- {match: "Upload", write: "yes"},
- }
- for _, m := range matches {
- pty.ExpectMatch(m.match)
- pty.WriteLine(m.write)
- }
-
- wantErr := <-execDone
- require.Error(t, wantErr)
- require.Contains(t, wantErr.Error(), "required template variables need values")
- })
-
t.Run("VariableIsOptionalButNotProvided", func(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
@@ -1115,6 +1067,240 @@ func TestTemplatePush(t *testing.T) {
require.Len(t, templateVersions, 2)
require.Equal(t, "example", templateVersions[1].Name)
})
+
+ t.Run("PromptForDifferentRequiredTypes", func(t *testing.T) {
+ t.Parallel()
+ client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
+ owner := coderdtest.CreateFirstUser(t, client)
+ templateAdmin, _ := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID, rbac.RoleTemplateAdmin())
+
+ templateVariables := []*proto.TemplateVariable{
+ {
+ Name: "string_var",
+ Description: "A string variable",
+ Type: "string",
+ Required: true,
+ },
+ {
+ Name: "number_var",
+ Description: "A number variable",
+ Type: "number",
+ Required: true,
+ },
+ {
+ Name: "bool_var",
+ Description: "A boolean variable",
+ Type: "bool",
+ Required: true,
+ },
+ {
+ Name: "sensitive_var",
+ Description: "A sensitive variable",
+ Type: "string",
+ Required: true,
+ Sensitive: true,
+ },
+ }
+
+ source := clitest.CreateTemplateVersionSource(t, createEchoResponsesWithTemplateVariables(templateVariables))
+ inv, root := clitest.New(t, "templates", "push", "test-template", "--directory", source, "--test.provisioner", string(database.ProvisionerTypeEcho))
+ clitest.SetupConfig(t, templateAdmin, root)
+ pty := ptytest.New(t).Attach(inv)
+
+ execDone := make(chan error)
+ go func() {
+ execDone <- inv.Run()
+ }()
+
+ // Select "Yes" for the "Upload " prompt
+ pty.ExpectMatch("Upload")
+ pty.WriteLine("yes")
+
+ pty.ExpectMatch("var.string_var")
+ pty.ExpectMatch("Enter value:")
+ pty.WriteLine("test-string")
+
+ pty.ExpectMatch("var.number_var")
+ pty.ExpectMatch("Enter value:")
+ pty.WriteLine("42")
+
+ // Boolean variable automatically selects the first option ("true")
+ pty.ExpectMatch("var.bool_var")
+
+ pty.ExpectMatch("var.sensitive_var")
+ pty.ExpectMatch("Enter value:")
+ pty.WriteLine("secret-value")
+
+ require.NoError(t, <-execDone)
+ })
+
+ t.Run("ValidateNumberInput", func(t *testing.T) {
+ t.Parallel()
+ client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
+ owner := coderdtest.CreateFirstUser(t, client)
+ templateAdmin, _ := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID, rbac.RoleTemplateAdmin())
+
+ templateVariables := []*proto.TemplateVariable{
+ {
+ Name: "number_var",
+ Description: "A number that requires validation",
+ Type: "number",
+ Required: true,
+ },
+ }
+
+ source := clitest.CreateTemplateVersionSource(t, createEchoResponsesWithTemplateVariables(templateVariables))
+ inv, root := clitest.New(t, "templates", "push", "test-template", "--directory", source, "--test.provisioner", string(database.ProvisionerTypeEcho))
+ clitest.SetupConfig(t, templateAdmin, root)
+ pty := ptytest.New(t).Attach(inv)
+
+ execDone := make(chan error)
+ go func() {
+ execDone <- inv.Run()
+ }()
+
+ // Select "Yes" for the "Upload " prompt
+ pty.ExpectMatch("Upload")
+ pty.WriteLine("yes")
+
+ pty.ExpectMatch("var.number_var")
+
+ pty.WriteLine("not-a-number")
+ pty.ExpectMatch("must be a valid number")
+
+ pty.WriteLine("123.45")
+
+ require.NoError(t, <-execDone)
+ })
+
+ t.Run("DontPromptForDefaultValues", func(t *testing.T) {
+ t.Parallel()
+ client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
+ owner := coderdtest.CreateFirstUser(t, client)
+ templateAdmin, _ := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID, rbac.RoleTemplateAdmin())
+
+ templateVariables := []*proto.TemplateVariable{
+ {
+ Name: "with_default",
+ Type: "string",
+ Required: true,
+ DefaultValue: "default-value",
+ },
+ {
+ Name: "without_default",
+ Type: "string",
+ Required: true,
+ },
+ }
+
+ source := clitest.CreateTemplateVersionSource(t, createEchoResponsesWithTemplateVariables(templateVariables))
+ inv, root := clitest.New(t, "templates", "push", "test-template", "--directory", source, "--test.provisioner", string(database.ProvisionerTypeEcho))
+ clitest.SetupConfig(t, templateAdmin, root)
+ pty := ptytest.New(t).Attach(inv)
+
+ execDone := make(chan error)
+ go func() {
+ execDone <- inv.Run()
+ }()
+
+ // Select "Yes" for the "Upload " prompt
+ pty.ExpectMatch("Upload")
+ pty.WriteLine("yes")
+
+ pty.ExpectMatch("var.without_default")
+ pty.WriteLine("test-value")
+
+ require.NoError(t, <-execDone)
+ })
+
+ t.Run("VariableSourcesPriority", func(t *testing.T) {
+ t.Parallel()
+ client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
+ owner := coderdtest.CreateFirstUser(t, client)
+ templateAdmin, _ := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID, rbac.RoleTemplateAdmin())
+
+ templateVariables := []*proto.TemplateVariable{
+ {
+ Name: "cli_flag_var",
+ Description: "Variable provided via CLI flag",
+ Type: "string",
+ Required: true,
+ },
+ {
+ Name: "file_var",
+ Description: "Variable provided via file",
+ Type: "string",
+ Required: true,
+ },
+ {
+ Name: "prompt_var",
+ Description: "Variable provided via prompt",
+ Type: "string",
+ Required: true,
+ },
+ {
+ Name: "cli_overrides_file_var",
+ Description: "Variable in both CLI and file",
+ Type: "string",
+ Required: true,
+ },
+ }
+
+ source := clitest.CreateTemplateVersionSource(t, createEchoResponsesWithTemplateVariables(templateVariables))
+
+ // Create a temporary variables file.
+ tempDir := t.TempDir()
+ removeTmpDirUntilSuccessAfterTest(t, tempDir)
+ variablesFile, err := os.CreateTemp(tempDir, "variables*.yaml")
+ require.NoError(t, err)
+ _, err = variablesFile.WriteString(`file_var: from-file
+cli_overrides_file_var: from-file`)
+ require.NoError(t, err)
+ require.NoError(t, variablesFile.Close())
+
+ inv, root := clitest.New(t, "templates", "push", "test-template",
+ "--directory", source,
+ "--test.provisioner", string(database.ProvisionerTypeEcho),
+ "--variables-file", variablesFile.Name(),
+ "--variable", "cli_flag_var=from-cli-flag",
+ "--variable", "cli_overrides_file_var=from-cli-override",
+ )
+ clitest.SetupConfig(t, templateAdmin, root)
+ pty := ptytest.New(t).Attach(inv)
+
+ execDone := make(chan error)
+ go func() {
+ execDone <- inv.Run()
+ }()
+
+ // Select "Yes" for the "Upload " prompt
+ pty.ExpectMatch("Upload")
+ pty.WriteLine("yes")
+
+ // Only check for prompt_var, other variables should not prompt
+ pty.ExpectMatch("var.prompt_var")
+ pty.ExpectMatch("Enter value:")
+ pty.WriteLine("from-prompt")
+
+ require.NoError(t, <-execDone)
+
+ template, err := client.TemplateByName(context.Background(), owner.OrganizationID, "test-template")
+ require.NoError(t, err)
+
+ templateVersionVars, err := client.TemplateVersionVariables(context.Background(), template.ActiveVersionID)
+ require.NoError(t, err)
+ require.Len(t, templateVersionVars, 4)
+
+ varMap := make(map[string]string)
+ for _, tv := range templateVersionVars {
+ varMap[tv.Name] = tv.Value
+ }
+
+ require.Equal(t, "from-cli-flag", varMap["cli_flag_var"])
+ require.Equal(t, "from-file", varMap["file_var"])
+ require.Equal(t, "from-prompt", varMap["prompt_var"])
+ require.Equal(t, "from-cli-override", varMap["cli_overrides_file_var"])
+ })
})
}
diff --git a/codersdk/provisionerdaemons.go b/codersdk/provisionerdaemons.go
index 4bff7d7827aa1..b3cefa09110ec 100644
--- a/codersdk/provisionerdaemons.go
+++ b/codersdk/provisionerdaemons.go
@@ -175,6 +175,12 @@ func JobIsMissingParameterErrorCode(code JobErrorCode) bool {
return string(code) == runner.MissingParameterErrorCode
}
+// JobIsMissingRequiredTemplateVariableErrorCode returns whether the error is a missing a required template
+// variable error. This can indicate to consumers that they need to provide required template variables.
+func JobIsMissingRequiredTemplateVariableErrorCode(code JobErrorCode) bool {
+ return string(code) == runner.RequiredTemplateVariablesErrorCode
+}
+
// ProvisionerJob describes the job executed by the provisioning daemon.
type ProvisionerJob struct {
ID uuid.UUID `json:"id" format:"uuid" table:"id"`
diff --git a/codersdk/templatevariables.go b/codersdk/templatevariables.go
index 3e02f6910642f..19c614e796e1e 100644
--- a/codersdk/templatevariables.go
+++ b/codersdk/templatevariables.go
@@ -68,7 +68,7 @@ func ParseUserVariableValues(varsFiles []string, variablesFile string, commandLi
return nil, err
}
- return combineVariableValues(fromVars, fromFile, fromCommandLine), nil
+ return CombineVariableValues(fromVars, fromFile, fromCommandLine), nil
}
func parseVariableValuesFromVarsFiles(varsFiles []string) ([]VariableValue, error) {
@@ -252,7 +252,7 @@ func parseVariableValuesFromCommandLine(variables []string) ([]VariableValue, er
return values, nil
}
-func combineVariableValues(valuesSets ...[]VariableValue) []VariableValue {
+func CombineVariableValues(valuesSets ...[]VariableValue) []VariableValue {
combinedValues := make(map[string]string)
for _, values := range valuesSets {
From b48e367c58a5552e08fa2049e7433b3cea0359d3 Mon Sep 17 00:00:00 2001
From: Zach <3724288+zedkipp@users.noreply.github.com>
Date: Fri, 3 Oct 2025 09:42:34 -0600
Subject: [PATCH 053/298] chore: remove dead randtz package (#20156)
This package was added in 65db7a71 a couple years back and was seemingly
never used (backed up by `git log -S randtz`).
---
coderd/database/dbtestutil/randtz/randtz.go | 1034 -------------------
1 file changed, 1034 deletions(-)
delete mode 100644 coderd/database/dbtestutil/randtz/randtz.go
diff --git a/coderd/database/dbtestutil/randtz/randtz.go b/coderd/database/dbtestutil/randtz/randtz.go
deleted file mode 100644
index 1a53bfaf725fd..0000000000000
--- a/coderd/database/dbtestutil/randtz/randtz.go
+++ /dev/null
@@ -1,1034 +0,0 @@
-package randtz
-
-import (
- "math/rand"
- "sync"
- "testing"
- "time"
-)
-
-var (
- randTZName string
- randTZNameOnce sync.Once
-)
-
-// Name returns a random timezone name from the list of all
-// timezones known to PostgreSQL.
-func Name(t testing.TB) string {
- t.Helper()
-
- randTZNameOnce.Do(func() {
- // nolint: gosec // not used for cryptography
- rnd := rand.New(rand.NewSource(time.Now().Unix()))
- idx := rnd.Intn(len(tznames))
- randTZName = tznames[idx]
- t.Logf("Random db timezone is %q\nIf you need a specific timezone, use dbtestutil.WithTimezone()", randTZName)
- })
-
- return randTZName
-}
-
-// tznames is a list of all timezone names known to postgresql.
-// The below list was generated with the query
-// select name from pg_timezone_names order by name asc;
-var tznames = []string{
- "Africa/Abidjan",
- "Africa/Accra",
- "Africa/Addis_Ababa",
- "Africa/Algiers",
- "Africa/Asmara",
- "Africa/Asmera",
- "Africa/Bamako",
- "Africa/Bangui",
- "Africa/Banjul",
- "Africa/Bissau",
- "Africa/Blantyre",
- "Africa/Brazzaville",
- "Africa/Bujumbura",
- "Africa/Cairo",
- "Africa/Casablanca",
- "Africa/Ceuta",
- "Africa/Conakry",
- "Africa/Dakar",
- "Africa/Dar_es_Salaam",
- "Africa/Djibouti",
- "Africa/Douala",
- "Africa/El_Aaiun",
- "Africa/Freetown",
- "Africa/Gaborone",
- "Africa/Harare",
- "Africa/Johannesburg",
- "Africa/Juba",
- "Africa/Kampala",
- "Africa/Khartoum",
- "Africa/Kigali",
- "Africa/Kinshasa",
- "Africa/Lagos",
- "Africa/Libreville",
- "Africa/Lome",
- "Africa/Luanda",
- "Africa/Lubumbashi",
- "Africa/Lusaka",
- "Africa/Malabo",
- "Africa/Maputo",
- "Africa/Maseru",
- "Africa/Mbabane",
- "Africa/Mogadishu",
- "Africa/Monrovia",
- "Africa/Nairobi",
- "Africa/Ndjamena",
- "Africa/Niamey",
- "Africa/Nouakchott",
- "Africa/Ouagadougou",
- "Africa/Porto-Novo",
- "Africa/Sao_Tome",
- "Africa/Timbuktu",
- "Africa/Tripoli",
- "Africa/Tunis",
- "Africa/Windhoek",
- "America/Adak",
- "America/Anchorage",
- "America/Anguilla",
- "America/Antigua",
- "America/Araguaina",
- "America/Argentina/Buenos_Aires",
- "America/Argentina/Catamarca",
- "America/Argentina/ComodRivadavia",
- "America/Argentina/Cordoba",
- "America/Argentina/Jujuy",
- "America/Argentina/La_Rioja",
- "America/Argentina/Mendoza",
- "America/Argentina/Rio_Gallegos",
- "America/Argentina/Salta",
- "America/Argentina/San_Juan",
- "America/Argentina/San_Luis",
- "America/Argentina/Tucuman",
- "America/Argentina/Ushuaia",
- "America/Aruba",
- "America/Asuncion",
- "America/Atikokan",
- "America/Atka",
- "America/Bahia",
- "America/Bahia_Banderas",
- "America/Barbados",
- "America/Belem",
- "America/Belize",
- "America/Blanc-Sablon",
- "America/Boa_Vista",
- "America/Bogota",
- "America/Boise",
- "America/Buenos_Aires",
- "America/Cambridge_Bay",
- "America/Campo_Grande",
- "America/Cancun",
- "America/Caracas",
- "America/Catamarca",
- "America/Cayenne",
- "America/Cayman",
- "America/Chicago",
- "America/Chihuahua",
- "America/Ciudad_Juarez",
- "America/Coral_Harbor",
- "America/Cordoba",
- "America/Costa_Rica",
- "America/Creston",
- "America/Cuiaba",
- "America/Curacao",
- "America/Danmarkshavn",
- "America/Dawson",
- "America/Dawson_Creek",
- "America/Denver",
- "America/Detroit",
- "America/Dominica",
- "America/Edmonton",
- "America/Eirunepe",
- "America/El_Salvador",
- "America/Ensenada",
- "America/Fortaleza",
- "America/Fort_Nelson",
- "America/Fort_Wayne",
- "America/Glace_Bay",
- "America/Godthab",
- "America/Goose_Bay",
- "America/Grand_Turk",
- "America/Grenada",
- "America/Guadeloupe",
- "America/Guatemala",
- "America/Guayaquil",
- "America/Guyana",
- "America/Halifax",
- "America/Havana",
- "America/Hermosillo",
- "America/Indiana/Indianapolis",
- "America/Indiana/Knox",
- "America/Indiana/Marengo",
- "America/Indiana/Petersburg",
- "America/Indianapolis",
- "America/Indiana/Tell_City",
- "America/Indiana/Vevay",
- "America/Indiana/Vincennes",
- "America/Indiana/Winamac",
- "America/Inuvik",
- "America/Iqaluit",
- "America/Jamaica",
- "America/Jujuy",
- "America/Juneau",
- "America/Kentucky/Louisville",
- "America/Kentucky/Monticello",
- "America/Knox_IN",
- "America/Kralendijk",
- "America/La_Paz",
- "America/Lima",
- "America/Los_Angeles",
- "America/Louisville",
- "America/Lower_Princes",
- "America/Maceio",
- "America/Managua",
- "America/Manaus",
- "America/Marigot",
- "America/Martinique",
- "America/Matamoros",
- "America/Mazatlan",
- "America/Mendoza",
- "America/Menominee",
- "America/Merida",
- "America/Metlakatla",
- "America/Mexico_City",
- "America/Miquelon",
- "America/Moncton",
- "America/Monterrey",
- "America/Montevideo",
- "America/Montreal",
- "America/Montserrat",
- "America/Nassau",
- "America/New_York",
- "America/Nipigon",
- "America/Nome",
- "America/Noronha",
- "America/North_Dakota/Beulah",
- "America/North_Dakota/Center",
- "America/North_Dakota/New_Salem",
- "America/Nuuk",
- "America/Ojinaga",
- "America/Panama",
- "America/Pangnirtung",
- "America/Paramaribo",
- "America/Phoenix",
- "America/Port-au-Prince",
- "America/Porto_Acre",
- "America/Port_of_Spain",
- "America/Porto_Velho",
- "America/Puerto_Rico",
- "America/Punta_Arenas",
- "America/Rainy_River",
- "America/Rankin_Inlet",
- "America/Recife",
- "America/Regina",
- "America/Resolute",
- "America/Rio_Branco",
- "America/Rosario",
- "America/Santa_Isabel",
- "America/Santarem",
- "America/Santiago",
- "America/Santo_Domingo",
- "America/Sao_Paulo",
- "America/Scoresbysund",
- "America/Shiprock",
- "America/Sitka",
- "America/St_Barthelemy",
- "America/St_Johns",
- "America/St_Kitts",
- "America/St_Lucia",
- "America/St_Thomas",
- "America/St_Vincent",
- "America/Swift_Current",
- "America/Tegucigalpa",
- "America/Thule",
- "America/Thunder_Bay",
- "America/Tijuana",
- "America/Toronto",
- "America/Tortola",
- "America/Vancouver",
- "America/Virgin",
- "America/Whitehorse",
- "America/Winnipeg",
- "America/Yakutat",
- "America/Yellowknife",
- "Antarctica/Casey",
- "Antarctica/Davis",
- "Antarctica/DumontDUrville",
- "Antarctica/Macquarie",
- "Antarctica/Mawson",
- "Antarctica/McMurdo",
- "Antarctica/Palmer",
- "Antarctica/Rothera",
- "Antarctica/South_Pole",
- "Antarctica/Syowa",
- "Antarctica/Troll",
- "Antarctica/Vostok",
- "Arctic/Longyearbyen",
- "Asia/Aden",
- "Asia/Almaty",
- "Asia/Amman",
- "Asia/Anadyr",
- "Asia/Aqtau",
- "Asia/Aqtobe",
- "Asia/Ashgabat",
- "Asia/Ashkhabad",
- "Asia/Atyrau",
- "Asia/Baghdad",
- "Asia/Bahrain",
- "Asia/Baku",
- "Asia/Bangkok",
- "Asia/Barnaul",
- "Asia/Beirut",
- "Asia/Bishkek",
- "Asia/Brunei",
- "Asia/Calcutta",
- "Asia/Chita",
- "Asia/Choibalsan",
- "Asia/Chongqing",
- "Asia/Chungking",
- "Asia/Colombo",
- "Asia/Dacca",
- "Asia/Damascus",
- "Asia/Dhaka",
- "Asia/Dili",
- "Asia/Dubai",
- "Asia/Dushanbe",
- "Asia/Famagusta",
- "Asia/Gaza",
- "Asia/Harbin",
- "Asia/Hebron",
- "Asia/Ho_Chi_Minh",
- "Asia/Hong_Kong",
- "Asia/Hovd",
- "Asia/Irkutsk",
- "Asia/Istanbul",
- "Asia/Jakarta",
- "Asia/Jayapura",
- "Asia/Jerusalem",
- "Asia/Kabul",
- "Asia/Kamchatka",
- "Asia/Karachi",
- "Asia/Kashgar",
- "Asia/Kathmandu",
- "Asia/Katmandu",
- "Asia/Khandyga",
- "Asia/Kolkata",
- "Asia/Krasnoyarsk",
- "Asia/Kuala_Lumpur",
- "Asia/Kuching",
- "Asia/Kuwait",
- "Asia/Macao",
- "Asia/Macau",
- "Asia/Magadan",
- "Asia/Makassar",
- "Asia/Manila",
- "Asia/Muscat",
- "Asia/Nicosia",
- "Asia/Novokuznetsk",
- "Asia/Novosibirsk",
- "Asia/Omsk",
- "Asia/Oral",
- "Asia/Phnom_Penh",
- "Asia/Pontianak",
- "Asia/Pyongyang",
- "Asia/Qatar",
- "Asia/Qostanay",
- "Asia/Qyzylorda",
- "Asia/Rangoon",
- "Asia/Riyadh",
- "Asia/Saigon",
- "Asia/Sakhalin",
- "Asia/Samarkand",
- "Asia/Seoul",
- "Asia/Shanghai",
- "Asia/Singapore",
- "Asia/Srednekolymsk",
- "Asia/Taipei",
- "Asia/Tashkent",
- "Asia/Tbilisi",
- "Asia/Tehran",
- "Asia/Tel_Aviv",
- "Asia/Thimbu",
- "Asia/Thimphu",
- "Asia/Tokyo",
- "Asia/Tomsk",
- "Asia/Ujung_Pandang",
- "Asia/Ulaanbaatar",
- "Asia/Ulan_Bator",
- "Asia/Urumqi",
- "Asia/Ust-Nera",
- "Asia/Vientiane",
- "Asia/Vladivostok",
- "Asia/Yakutsk",
- "Asia/Yangon",
- "Asia/Yekaterinburg",
- "Asia/Yerevan",
- "Atlantic/Azores",
- "Atlantic/Bermuda",
- "Atlantic/Canary",
- "Atlantic/Cape_Verde",
- "Atlantic/Faeroe",
- "Atlantic/Faroe",
- "Atlantic/Jan_Mayen",
- "Atlantic/Madeira",
- "Atlantic/Reykjavik",
- "Atlantic/South_Georgia",
- "Atlantic/Stanley",
- "Atlantic/St_Helena",
- "Australia/ACT",
- "Australia/Adelaide",
- "Australia/Brisbane",
- "Australia/Broken_Hill",
- "Australia/Canberra",
- "Australia/Currie",
- "Australia/Darwin",
- "Australia/Eucla",
- "Australia/Hobart",
- "Australia/LHI",
- "Australia/Lindeman",
- "Australia/Lord_Howe",
- "Australia/Melbourne",
- "Australia/North",
- "Australia/NSW",
- "Australia/Perth",
- "Australia/Queensland",
- "Australia/South",
- "Australia/Sydney",
- "Australia/Tasmania",
- "Australia/Victoria",
- "Australia/West",
- "Australia/Yancowinna",
- "Brazil/Acre",
- "Brazil/DeNoronha",
- "Brazil/East",
- "Brazil/West",
- "Canada/Atlantic",
- "Canada/Central",
- "Canada/Eastern",
- "Canada/Mountain",
- "Canada/Newfoundland",
- "Canada/Pacific",
- "Canada/Saskatchewan",
- "Canada/Yukon",
- "CET",
- "Chile/Continental",
- "Chile/EasterIsland",
- "CST6CDT",
- "Cuba",
- "EET",
- "Egypt",
- "Eire",
- "EST",
- "EST5EDT",
- "Etc/GMT",
- "Etc/GMT+0",
- "Etc/GMT-0",
- "Etc/GMT0",
- "Etc/GMT+1",
- "Etc/GMT-1",
- "Etc/GMT+10",
- "Etc/GMT-10",
- "Etc/GMT+11",
- "Etc/GMT-11",
- "Etc/GMT+12",
- "Etc/GMT-12",
- "Etc/GMT-13",
- "Etc/GMT-14",
- "Etc/GMT+2",
- "Etc/GMT-2",
- "Etc/GMT+3",
- "Etc/GMT-3",
- "Etc/GMT+4",
- "Etc/GMT-4",
- "Etc/GMT+5",
- "Etc/GMT-5",
- "Etc/GMT+6",
- "Etc/GMT-6",
- "Etc/GMT+7",
- "Etc/GMT-7",
- "Etc/GMT+8",
- "Etc/GMT-8",
- "Etc/GMT+9",
- "Etc/GMT-9",
- "Etc/Greenwich",
- "Etc/UCT",
- "Etc/Universal",
- "Etc/UTC",
- "Etc/Zulu",
- "Europe/Amsterdam",
- "Europe/Andorra",
- "Europe/Astrakhan",
- "Europe/Athens",
- "Europe/Belfast",
- "Europe/Belgrade",
- "Europe/Berlin",
- "Europe/Bratislava",
- "Europe/Brussels",
- "Europe/Bucharest",
- "Europe/Budapest",
- "Europe/Busingen",
- "Europe/Chisinau",
- "Europe/Copenhagen",
- "Europe/Dublin",
- "Europe/Gibraltar",
- "Europe/Guernsey",
- "Europe/Helsinki",
- "Europe/Isle_of_Man",
- "Europe/Istanbul",
- "Europe/Jersey",
- "Europe/Kaliningrad",
- "Europe/Kiev",
- "Europe/Kirov",
- "Europe/Lisbon",
- "Europe/Ljubljana",
- "Europe/London",
- "Europe/Luxembourg",
- "Europe/Madrid",
- "Europe/Malta",
- "Europe/Mariehamn",
- "Europe/Minsk",
- "Europe/Monaco",
- "Europe/Moscow",
- "Europe/Nicosia",
- "Europe/Oslo",
- "Europe/Paris",
- "Europe/Podgorica",
- "Europe/Prague",
- "Europe/Riga",
- "Europe/Rome",
- "Europe/Samara",
- "Europe/San_Marino",
- "Europe/Sarajevo",
- "Europe/Saratov",
- "Europe/Simferopol",
- "Europe/Skopje",
- "Europe/Sofia",
- "Europe/Stockholm",
- "Europe/Tallinn",
- "Europe/Tirane",
- "Europe/Tiraspol",
- "Europe/Ulyanovsk",
- "Europe/Uzhgorod",
- "Europe/Vaduz",
- "Europe/Vatican",
- "Europe/Vienna",
- "Europe/Vilnius",
- "Europe/Volgograd",
- "Europe/Warsaw",
- "Europe/Zagreb",
- "Europe/Zaporozhye",
- "Europe/Zurich",
- "Factory",
- "GB",
- "GB-Eire",
- "GMT",
- "GMT+0",
- "GMT-0",
- "GMT0",
- "Greenwich",
- "Hongkong",
- "HST",
- "Iceland",
- "Indian/Antananarivo",
- "Indian/Chagos",
- "Indian/Christmas",
- "Indian/Cocos",
- "Indian/Comoro",
- "Indian/Kerguelen",
- "Indian/Mahe",
- "Indian/Maldives",
- "Indian/Mauritius",
- "Indian/Mayotte",
- "Indian/Reunion",
- "Iran",
- "Israel",
- "Jamaica",
- "Japan",
- "Kwajalein",
- "Libya",
- "localtime",
- "MET",
- "Mexico/BajaNorte",
- "Mexico/BajaSur",
- "Mexico/General",
- "MST",
- "MST7MDT",
- "Navajo",
- "NZ",
- "NZ-CHAT",
- "Pacific/Apia",
- "Pacific/Auckland",
- "Pacific/Bougainville",
- "Pacific/Chatham",
- "Pacific/Chuuk",
- "Pacific/Easter",
- "Pacific/Efate",
- "Pacific/Enderbury",
- "Pacific/Fakaofo",
- "Pacific/Fiji",
- "Pacific/Funafuti",
- "Pacific/Galapagos",
- "Pacific/Gambier",
- "Pacific/Guadalcanal",
- "Pacific/Guam",
- "Pacific/Honolulu",
- "Pacific/Johnston",
- "Pacific/Kiritimati",
- "Pacific/Kosrae",
- "Pacific/Kwajalein",
- "Pacific/Majuro",
- "Pacific/Marquesas",
- "Pacific/Midway",
- "Pacific/Nauru",
- "Pacific/Niue",
- "Pacific/Norfolk",
- "Pacific/Noumea",
- "Pacific/Pago_Pago",
- "Pacific/Palau",
- "Pacific/Pitcairn",
- "Pacific/Pohnpei",
- "Pacific/Ponape",
- "Pacific/Port_Moresby",
- "Pacific/Rarotonga",
- "Pacific/Saipan",
- "Pacific/Samoa",
- "Pacific/Tahiti",
- "Pacific/Tarawa",
- "Pacific/Tongatapu",
- "Pacific/Truk",
- "Pacific/Wake",
- "Pacific/Wallis",
- "Pacific/Yap",
- "Poland",
- "Portugal",
- "posix/Africa/Abidjan",
- "posix/Africa/Accra",
- "posix/Africa/Addis_Ababa",
- "posix/Africa/Algiers",
- "posix/Africa/Asmara",
- "posix/Africa/Asmera",
- "posix/Africa/Bamako",
- "posix/Africa/Bangui",
- "posix/Africa/Banjul",
- "posix/Africa/Bissau",
- "posix/Africa/Blantyre",
- "posix/Africa/Brazzaville",
- "posix/Africa/Bujumbura",
- "posix/Africa/Cairo",
- "posix/Africa/Casablanca",
- "posix/Africa/Ceuta",
- "posix/Africa/Conakry",
- "posix/Africa/Dakar",
- "posix/Africa/Dar_es_Salaam",
- "posix/Africa/Djibouti",
- "posix/Africa/Douala",
- "posix/Africa/El_Aaiun",
- "posix/Africa/Freetown",
- "posix/Africa/Gaborone",
- "posix/Africa/Harare",
- "posix/Africa/Johannesburg",
- "posix/Africa/Juba",
- "posix/Africa/Kampala",
- "posix/Africa/Khartoum",
- "posix/Africa/Kigali",
- "posix/Africa/Kinshasa",
- "posix/Africa/Lagos",
- "posix/Africa/Libreville",
- "posix/Africa/Lome",
- "posix/Africa/Luanda",
- "posix/Africa/Lubumbashi",
- "posix/Africa/Lusaka",
- "posix/Africa/Malabo",
- "posix/Africa/Maputo",
- "posix/Africa/Maseru",
- "posix/Africa/Mbabane",
- "posix/Africa/Mogadishu",
- "posix/Africa/Monrovia",
- "posix/Africa/Nairobi",
- "posix/Africa/Ndjamena",
- "posix/Africa/Niamey",
- "posix/Africa/Nouakchott",
- "posix/Africa/Ouagadougou",
- "posix/Africa/Porto-Novo",
- "posix/Africa/Sao_Tome",
- "posix/Africa/Timbuktu",
- "posix/Africa/Tripoli",
- "posix/Africa/Tunis",
- "posix/Africa/Windhoek",
- "posix/America/Adak",
- "posix/America/Anchorage",
- "posix/America/Anguilla",
- "posix/America/Antigua",
- "posix/America/Araguaina",
- "posix/America/Argentina/Buenos_Aires",
- "posix/America/Argentina/Catamarca",
- "posix/America/Argentina/ComodRivadavia",
- "posix/America/Argentina/Cordoba",
- "posix/America/Argentina/Jujuy",
- "posix/America/Argentina/La_Rioja",
- "posix/America/Argentina/Mendoza",
- "posix/America/Argentina/Rio_Gallegos",
- "posix/America/Argentina/Salta",
- "posix/America/Argentina/San_Juan",
- "posix/America/Argentina/San_Luis",
- "posix/America/Argentina/Tucuman",
- "posix/America/Argentina/Ushuaia",
- "posix/America/Aruba",
- "posix/America/Asuncion",
- "posix/America/Atikokan",
- "posix/America/Atka",
- "posix/America/Bahia",
- "posix/America/Bahia_Banderas",
- "posix/America/Barbados",
- "posix/America/Belem",
- "posix/America/Belize",
- "posix/America/Blanc-Sablon",
- "posix/America/Boa_Vista",
- "posix/America/Bogota",
- "posix/America/Boise",
- "posix/America/Buenos_Aires",
- "posix/America/Cambridge_Bay",
- "posix/America/Campo_Grande",
- "posix/America/Cancun",
- "posix/America/Caracas",
- "posix/America/Catamarca",
- "posix/America/Cayenne",
- "posix/America/Cayman",
- "posix/America/Chicago",
- "posix/America/Chihuahua",
- "posix/America/Ciudad_Juarez",
- "posix/America/Coral_Harbor",
- "posix/America/Cordoba",
- "posix/America/Costa_Rica",
- "posix/America/Creston",
- "posix/America/Cuiaba",
- "posix/America/Curacao",
- "posix/America/Danmarkshavn",
- "posix/America/Dawson",
- "posix/America/Dawson_Creek",
- "posix/America/Denver",
- "posix/America/Detroit",
- "posix/America/Dominica",
- "posix/America/Edmonton",
- "posix/America/Eirunepe",
- "posix/America/El_Salvador",
- "posix/America/Ensenada",
- "posix/America/Fortaleza",
- "posix/America/Fort_Nelson",
- "posix/America/Fort_Wayne",
- "posix/America/Glace_Bay",
- "posix/America/Godthab",
- "posix/America/Goose_Bay",
- "posix/America/Grand_Turk",
- "posix/America/Grenada",
- "posix/America/Guadeloupe",
- "posix/America/Guatemala",
- "posix/America/Guayaquil",
- "posix/America/Guyana",
- "posix/America/Halifax",
- "posix/America/Havana",
- "posix/America/Hermosillo",
- "posix/America/Indiana/Indianapolis",
- "posix/America/Indiana/Knox",
- "posix/America/Indiana/Marengo",
- "posix/America/Indiana/Petersburg",
- "posix/America/Indianapolis",
- "posix/America/Indiana/Tell_City",
- "posix/America/Indiana/Vevay",
- "posix/America/Indiana/Vincennes",
- "posix/America/Indiana/Winamac",
- "posix/America/Inuvik",
- "posix/America/Iqaluit",
- "posix/America/Jamaica",
- "posix/America/Jujuy",
- "posix/America/Juneau",
- "posix/America/Kentucky/Louisville",
- "posix/America/Kentucky/Monticello",
- "posix/America/Knox_IN",
- "posix/America/Kralendijk",
- "posix/America/La_Paz",
- "posix/America/Lima",
- "posix/America/Los_Angeles",
- "posix/America/Louisville",
- "posix/America/Lower_Princes",
- "posix/America/Maceio",
- "posix/America/Managua",
- "posix/America/Manaus",
- "posix/America/Marigot",
- "posix/America/Martinique",
- "posix/America/Matamoros",
- "posix/America/Mazatlan",
- "posix/America/Mendoza",
- "posix/America/Menominee",
- "posix/America/Merida",
- "posix/America/Metlakatla",
- "posix/America/Mexico_City",
- "posix/America/Miquelon",
- "posix/America/Moncton",
- "posix/America/Monterrey",
- "posix/America/Montevideo",
- "posix/America/Montreal",
- "posix/America/Montserrat",
- "posix/America/Nassau",
- "posix/America/New_York",
- "posix/America/Nipigon",
- "posix/America/Nome",
- "posix/America/Noronha",
- "posix/America/North_Dakota/Beulah",
- "posix/America/North_Dakota/Center",
- "posix/America/North_Dakota/New_Salem",
- "posix/America/Nuuk",
- "posix/America/Ojinaga",
- "posix/America/Panama",
- "posix/America/Pangnirtung",
- "posix/America/Paramaribo",
- "posix/America/Phoenix",
- "posix/America/Port-au-Prince",
- "posix/America/Porto_Acre",
- "posix/America/Port_of_Spain",
- "posix/America/Porto_Velho",
- "posix/America/Puerto_Rico",
- "posix/America/Punta_Arenas",
- "posix/America/Rainy_River",
- "posix/America/Rankin_Inlet",
- "posix/America/Recife",
- "posix/America/Regina",
- "posix/America/Resolute",
- "posix/America/Rio_Branco",
- "posix/America/Rosario",
- "posix/America/Santa_Isabel",
- "posix/America/Santarem",
- "posix/America/Santiago",
- "posix/America/Santo_Domingo",
- "posix/America/Sao_Paulo",
- "posix/America/Scoresbysund",
- "posix/America/Shiprock",
- "posix/America/Sitka",
- "posix/America/St_Barthelemy",
- "posix/America/St_Johns",
- "posix/America/St_Kitts",
- "posix/America/St_Lucia",
- "posix/America/St_Thomas",
- "posix/America/St_Vincent",
- "posix/America/Swift_Current",
- "posix/America/Tegucigalpa",
- "posix/America/Thule",
- "posix/America/Thunder_Bay",
- "posix/America/Tijuana",
- "posix/America/Toronto",
- "posix/America/Tortola",
- "posix/America/Vancouver",
- "posix/America/Virgin",
- "posix/America/Whitehorse",
- "posix/America/Winnipeg",
- "posix/America/Yakutat",
- "posix/America/Yellowknife",
- "posix/Antarctica/Casey",
- "posix/Antarctica/Davis",
- "posix/Antarctica/DumontDUrville",
- "posix/Antarctica/Macquarie",
- "posix/Antarctica/Mawson",
- "posix/Antarctica/McMurdo",
- "posix/Antarctica/Palmer",
- "posix/Antarctica/Rothera",
- "posix/Antarctica/South_Pole",
- "posix/Antarctica/Syowa",
- "posix/Antarctica/Troll",
- "posix/Antarctica/Vostok",
- "posix/Arctic/Longyearbyen",
- "posix/Asia/Aden",
- "posix/Asia/Almaty",
- "posix/Asia/Amman",
- "posix/Asia/Anadyr",
- "posix/Asia/Aqtau",
- "posix/Asia/Aqtobe",
- "posix/Asia/Ashgabat",
- "posix/Asia/Ashkhabad",
- "posix/Asia/Atyrau",
- "posix/Asia/Baghdad",
- "posix/Asia/Bahrain",
- "posix/Asia/Baku",
- "posix/Asia/Bangkok",
- "posix/Asia/Barnaul",
- "posix/Asia/Beirut",
- "posix/Asia/Bishkek",
- "posix/Asia/Brunei",
- "posix/Asia/Calcutta",
- "posix/Asia/Chita",
- "posix/Asia/Choibalsan",
- "posix/Asia/Chongqing",
- "posix/Asia/Chungking",
- "posix/Asia/Colombo",
- "posix/Asia/Dacca",
- "posix/Asia/Damascus",
- "posix/Asia/Dhaka",
- "posix/Asia/Dili",
- "posix/Asia/Dubai",
- "posix/Asia/Dushanbe",
- "posix/Asia/Famagusta",
- "posix/Asia/Gaza",
- "posix/Asia/Harbin",
- "posix/Asia/Hebron",
- "posix/Asia/Ho_Chi_Minh",
- "posix/Asia/Hong_Kong",
- "posix/Asia/Hovd",
- "posix/Asia/Irkutsk",
- "posix/Asia/Istanbul",
- "posix/Asia/Jakarta",
- "posix/Asia/Jayapura",
- "posix/Asia/Jerusalem",
- "posix/Asia/Kabul",
- "posix/Asia/Kamchatka",
- "posix/Asia/Karachi",
- "posix/Asia/Kashgar",
- "posix/Asia/Kathmandu",
- "posix/Asia/Katmandu",
- "posix/Asia/Khandyga",
- "posix/Asia/Kolkata",
- "posix/Asia/Krasnoyarsk",
- "posix/Asia/Kuala_Lumpur",
- "posix/Asia/Kuching",
- "posix/Asia/Kuwait",
- "posix/Asia/Macao",
- "posix/Asia/Macau",
- "posix/Asia/Magadan",
- "posix/Asia/Makassar",
- "posix/Asia/Manila",
- "posix/Asia/Muscat",
- "posix/Asia/Nicosia",
- "posix/Asia/Novokuznetsk",
- "posix/Asia/Novosibirsk",
- "posix/Asia/Omsk",
- "posix/Asia/Oral",
- "posix/Asia/Phnom_Penh",
- "posix/Asia/Pontianak",
- "posix/Asia/Pyongyang",
- "posix/Asia/Qatar",
- "posix/Asia/Qostanay",
- "posix/Asia/Qyzylorda",
- "posix/Asia/Rangoon",
- "posix/Asia/Riyadh",
- "posix/Asia/Saigon",
- "posix/Asia/Sakhalin",
- "posix/Asia/Samarkand",
- "posix/Asia/Seoul",
- "posix/Asia/Shanghai",
- "posix/Asia/Singapore",
- "posix/Asia/Srednekolymsk",
- "posix/Asia/Taipei",
- "posix/Asia/Tashkent",
- "posix/Asia/Tbilisi",
- "posix/Asia/Tehran",
- "posix/Asia/Tel_Aviv",
- "posix/Asia/Thimbu",
- "posix/Asia/Thimphu",
- "posix/Asia/Tokyo",
- "posix/Asia/Tomsk",
- "posix/Asia/Ujung_Pandang",
- "posix/Asia/Ulaanbaatar",
- "posix/Asia/Ulan_Bator",
- "posix/Asia/Urumqi",
- "posix/Asia/Ust-Nera",
- "posix/Asia/Vientiane",
- "posix/Asia/Vladivostok",
- "posix/Asia/Yakutsk",
- "posix/Asia/Yangon",
- "posix/Asia/Yekaterinburg",
- "posix/Asia/Yerevan",
- "posix/Atlantic/Azores",
- "posix/Atlantic/Bermuda",
- "posix/Atlantic/Canary",
- "posix/Atlantic/Cape_Verde",
- "posix/Atlantic/Faeroe",
- "posix/Atlantic/Faroe",
- "posix/Atlantic/Jan_Mayen",
- "posix/Atlantic/Madeira",
- "posix/Atlantic/Reykjavik",
- "posix/Atlantic/South_Georgia",
- "posix/Atlantic/Stanley",
- "posix/Atlantic/St_Helena",
- "posix/Australia/ACT",
- "posix/Australia/Adelaide",
- "posix/Australia/Brisbane",
- "posix/Australia/Broken_Hill",
- "posix/Australia/Canberra",
- "posix/Australia/Currie",
- "posix/Australia/Darwin",
- "posix/Australia/Eucla",
- "posix/Australia/Hobart",
- "posix/Australia/LHI",
- "posix/Australia/Lindeman",
- "posix/Australia/Lord_Howe",
- "posix/Australia/Melbourne",
- "posix/Australia/North",
- "posix/Australia/NSW",
- "posix/Australia/Perth",
- "posix/Australia/Queensland",
- "posix/Australia/South",
- "posix/Australia/Sydney",
- "posix/Australia/Tasmania",
- "posix/Australia/Victoria",
- "posix/Australia/West",
- "posix/Australia/Yancowinna",
- "posix/Brazil/Acre",
- "posix/Brazil/DeNoronha",
- "posix/Brazil/East",
- "posix/Brazil/West",
- "posix/Canada/Atlantic",
- "posix/Canada/Central",
- "posix/Canada/Eastern",
- "posix/Canada/Mountain",
- "posix/Canada/Newfoundland",
- "posix/Canada/Pacific",
- "posix/Canada/Saskatchewan",
- "posix/Canada/Yukon",
- "posix/CET",
- "posix/Chile/Continental",
- "posix/Chile/EasterIsland",
- "posix/CST6CDT",
- "posix/Cuba",
- "posix/EET",
- "posix/Egypt",
- "posix/Eire",
- "posix/EST",
- "posix/EST5EDT",
- "posix/Etc/GMT",
- "posix/Etc/GMT+0",
- "posix/Etc/GMT-0",
- "posix/Etc/GMT0",
- "posix/Etc/GMT+1",
- "posix/Etc/GMT-1",
- "posix/Etc/GMT+10",
- "posix/Etc/GMT-10",
- "posix/Etc/GMT+11",
- "posix/Etc/GMT-11",
- "posix/Etc/GMT+12",
- "posix/Etc/GMT-12",
- "posix/Etc/GMT-13",
- "posix/Etc/GMT-14",
- "posix/Etc/GMT+2",
- "posix/Etc/GMT-2",
- "posix/Etc/GMT+3",
- "posix/Etc/GMT-3",
- "posix/Etc/GMT+4",
- "posix/Etc/GMT-4",
- "posix/Etc/GMT+5",
- "posix/Etc/GMT-5",
- "posix/Etc/GMT+6",
- "posix/Etc/GMT-6",
- "posix/Etc/GMT+7",
- "posix/Etc/GMT-7",
- "posix/Etc/GMT+8",
- "posix/Etc/GMT-8",
- "posix/Etc/GMT+9",
- "posix/Etc/GMT-9",
- "posix/Etc/Greenwich",
- "posix/Etc/UCT",
- "posix/Etc/Universal",
- "posix/Etc/UTC",
- "posix/Etc/Zulu",
- "posix/Europe/Amsterdam",
-}
From 2ec9be2203e559016955d6280d39c2d193599610 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=82=B1=E3=82=A4=E3=83=A9?=
Date: Fri, 3 Oct 2025 14:11:08 -0600
Subject: [PATCH 054/298] fix: only show error once when failing to update org
member roles (#20155)
---
.../OrganizationMembersPageView.tsx | 8 +++-----
1 file changed, 3 insertions(+), 5 deletions(-)
diff --git a/site/src/pages/OrganizationSettingsPage/OrganizationMembersPageView.tsx b/site/src/pages/OrganizationSettingsPage/OrganizationMembersPageView.tsx
index f720ba692d0ca..106f2d17d4914 100644
--- a/site/src/pages/OrganizationSettingsPage/OrganizationMembersPageView.tsx
+++ b/site/src/pages/OrganizationSettingsPage/OrganizationMembersPageView.tsx
@@ -149,14 +149,12 @@ export const OrganizationMembersPageView: FC<
isLoading={isUpdatingMemberRoles}
canEditUsers={canEditMembers}
onEditRoles={async (roles) => {
+ // React doesn't mind uncaught errors in event handlers,
+ // but testing-library does.
try {
await updateMemberRoles(member, roles);
displaySuccess("Roles updated successfully.");
- } catch (error) {
- displayError(
- getErrorMessage(error, "Failed to update roles."),
- );
- }
+ } catch {}
}}
/>
From c1357d4e275559221007a6efaef7a647af5217d0 Mon Sep 17 00:00:00 2001
From: Atif Ali
Date: Sat, 4 Oct 2025 15:58:17 +0500
Subject: [PATCH 055/298] chore(dogfood): dogfood latest version of agentAPI
(#20165)
---
dogfood/coder/main.tf | 1 +
1 file changed, 1 insertion(+)
diff --git a/dogfood/coder/main.tf b/dogfood/coder/main.tf
index 614b25cdb9ec8..cc223996ba7e9 100644
--- a/dogfood/coder/main.tf
+++ b/dogfood/coder/main.tf
@@ -872,6 +872,7 @@ module "claude-code" {
claude_code_version = "latest"
order = 999
claude_api_key = data.coder_workspace_owner.me.session_token
+ agentapi_version = "latest"
system_prompt = local.claude_system_prompt
ai_prompt = data.coder_parameter.ai_prompt.value
From d17dd5d7879f44518f9f0ce1ff2bd462e25d5ddc Mon Sep 17 00:00:00 2001
From: Sas Swart
Date: Mon, 6 Oct 2025 10:56:43 +0200
Subject: [PATCH 056/298] feat: add filtering by initiator to provisioner job
listing in the CLI (#20137)
Relates to https://github.com/coder/internal/issues/934
This PR provides a mechanism to filter provisioner jobs according to who
initiated the job.
This will be used to find pending prebuild jobs when prebuilds have
overwhelmed the provisioner job queue. They can then be canceled.
If prebuilds are overwhelming provisioners, the following steps will be
taken:
```bash
# pause prebuild reconciliation to limit provisioner queue pollution:
coder prebuilds pause
# cancel pending provisioner jobs to clear the queue
coder provisioner jobs list --initiator="prebuilds" --status="pending" | jq ... | xargs -n1 -I{} coder provisioner jobs cancel {}
# push a fixed template and wait for the import to complete
coder templates push ... # push a fixed template
# resume prebuild reconciliation
coder prebuilds resume
```
This interface differs somewhat from what was specified in the issue,
but still provides a mechanism that addresses the issue. The original
proposal was made by myself and this simpler implementation makes sense.
I might add a `--search` parameter in a follow-up if there is appetite
for it.
Potential follow ups:
* Support for this usage: `coder provisioner jobs list --search
"initiator:prebuilds status:pending"`
* Adding the same parameters to `coder provisioner jobs cancel` as a
convenience feature so that operators don't have to pipe through `jq`
and `xargs`
---
cli/provisionerjobs.go | 27 ++-
cli/provisionerjobs_test.go | 192 +++++++++++++++---
cli/testdata/coder_list_--output_json.golden | 1 +
.../coder_provisioner_jobs_list_--help.golden | 5 +-
...provisioner_jobs_list_--output_json.golden | 2 +
coderd/apidoc/docs.go | 11 +
coderd/apidoc/swagger.json | 11 +
coderd/database/dbauthz/dbauthz_test.go | 2 +
coderd/database/queries.sql.go | 5 +-
coderd/database/queries/provisionerjobs.sql | 1 +
coderd/provisionerjobs.go | 4 +
coderd/provisionerjobs_test.go | 102 ++++++++++
codersdk/organizations.go | 12 +-
codersdk/provisionerdaemons.go | 1 +
docs/reference/api/builds.md | 6 +
docs/reference/api/organizations.md | 4 +
docs/reference/api/schemas.md | 6 +
docs/reference/api/templates.md | 11 +
docs/reference/api/workspaces.md | 6 +
docs/reference/cli/provisioner_jobs_list.md | 17 +-
.../coder_provisioner_jobs_list_--help.golden | 5 +-
site/src/api/typesGenerated.ts | 2 +
site/src/testHelpers/entities.ts | 1 +
23 files changed, 395 insertions(+), 39 deletions(-)
diff --git a/cli/provisionerjobs.go b/cli/provisionerjobs.go
index 3ce7da20b7dcb..3f441a1758045 100644
--- a/cli/provisionerjobs.go
+++ b/cli/provisionerjobs.go
@@ -43,8 +43,9 @@ func (r *RootCmd) provisionerJobsList() *serpent.Command {
cliui.TableFormat([]provisionerJobRow{}, []string{"created at", "id", "type", "template display name", "status", "queue", "tags"}),
cliui.JSONFormat(),
)
- status []string
- limit int64
+ status []string
+ limit int64
+ initiator string
)
cmd := &serpent.Command{
@@ -65,9 +66,20 @@ func (r *RootCmd) provisionerJobsList() *serpent.Command {
return xerrors.Errorf("current organization: %w", err)
}
+ var initiatorID *uuid.UUID
+
+ if initiator != "" {
+ user, err := client.User(ctx, initiator)
+ if err != nil {
+ return xerrors.Errorf("initiator not found: %s", initiator)
+ }
+ initiatorID = &user.ID
+ }
+
jobs, err := client.OrganizationProvisionerJobs(ctx, org.ID, &codersdk.OrganizationProvisionerJobsOptions{
- Status: slice.StringEnums[codersdk.ProvisionerJobStatus](status),
- Limit: int(limit),
+ Status: slice.StringEnums[codersdk.ProvisionerJobStatus](status),
+ Limit: int(limit),
+ InitiatorID: initiatorID,
})
if err != nil {
return xerrors.Errorf("list provisioner jobs: %w", err)
@@ -122,6 +134,13 @@ func (r *RootCmd) provisionerJobsList() *serpent.Command {
Default: "50",
Value: serpent.Int64Of(&limit),
},
+ {
+ Flag: "initiator",
+ FlagShorthand: "i",
+ Env: "CODER_PROVISIONER_JOB_LIST_INITIATOR",
+ Description: "Filter by initiator (user ID or username).",
+ Value: serpent.StringOf(&initiator),
+ },
}...)
orgContext.AttachOptions(cmd)
diff --git a/cli/provisionerjobs_test.go b/cli/provisionerjobs_test.go
index 4db42e8e3c9e7..57072a6156738 100644
--- a/cli/provisionerjobs_test.go
+++ b/cli/provisionerjobs_test.go
@@ -5,6 +5,7 @@ import (
"database/sql"
"encoding/json"
"fmt"
+ "strings"
"testing"
"time"
@@ -26,33 +27,32 @@ import (
func TestProvisionerJobs(t *testing.T) {
t.Parallel()
- db, ps := dbtestutil.NewDB(t)
- client, _, coderdAPI := coderdtest.NewWithAPI(t, &coderdtest.Options{
- IncludeProvisionerDaemon: false,
- Database: db,
- Pubsub: ps,
- })
- owner := coderdtest.CreateFirstUser(t, client)
- templateAdminClient, templateAdmin := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID, rbac.ScopedRoleOrgTemplateAdmin(owner.OrganizationID))
- memberClient, member := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID)
-
- // These CLI tests are related to provisioner job CRUD operations and as such
- // do not require the overhead of starting a provisioner. Other provisioner job
- // functionalities (acquisition etc.) are tested elsewhere.
- template := dbgen.Template(t, db, database.Template{
- OrganizationID: owner.OrganizationID,
- CreatedBy: owner.UserID,
- AllowUserCancelWorkspaceJobs: true,
- })
- version := dbgen.TemplateVersion(t, db, database.TemplateVersion{
- OrganizationID: owner.OrganizationID,
- CreatedBy: owner.UserID,
- TemplateID: uuid.NullUUID{UUID: template.ID, Valid: true},
- })
-
t.Run("Cancel", func(t *testing.T) {
t.Parallel()
+ db, ps := dbtestutil.NewDB(t)
+ client, _, coderdAPI := coderdtest.NewWithAPI(t, &coderdtest.Options{
+ IncludeProvisionerDaemon: false,
+ Database: db,
+ Pubsub: ps,
+ })
+ owner := coderdtest.CreateFirstUser(t, client)
+ templateAdminClient, templateAdmin := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID, rbac.ScopedRoleOrgTemplateAdmin(owner.OrganizationID))
+ memberClient, member := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID)
+
+ // These CLI tests are related to provisioner job CRUD operations and as such
+ // do not require the overhead of starting a provisioner. Other provisioner job
+ // functionalities (acquisition etc.) are tested elsewhere.
+ template := dbgen.Template(t, db, database.Template{
+ OrganizationID: owner.OrganizationID,
+ CreatedBy: owner.UserID,
+ AllowUserCancelWorkspaceJobs: true,
+ })
+ version := dbgen.TemplateVersion(t, db, database.TemplateVersion{
+ OrganizationID: owner.OrganizationID,
+ CreatedBy: owner.UserID,
+ TemplateID: uuid.NullUUID{UUID: template.ID, Valid: true},
+ })
// Test helper to create a provisioner job of a given type with a given input.
prepareJob := func(t *testing.T, jobType database.ProvisionerJobType, input json.RawMessage) database.ProvisionerJob {
t.Helper()
@@ -178,4 +178,148 @@ func TestProvisionerJobs(t *testing.T) {
})
}
})
+
+ t.Run("List", func(t *testing.T) {
+ t.Parallel()
+
+ db, ps := dbtestutil.NewDB(t)
+ client, _, coderdAPI := coderdtest.NewWithAPI(t, &coderdtest.Options{
+ IncludeProvisionerDaemon: false,
+ Database: db,
+ Pubsub: ps,
+ })
+ owner := coderdtest.CreateFirstUser(t, client)
+ _, member := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID)
+
+ // These CLI tests are related to provisioner job CRUD operations and as such
+ // do not require the overhead of starting a provisioner. Other provisioner job
+ // functionalities (acquisition etc.) are tested elsewhere.
+ template := dbgen.Template(t, db, database.Template{
+ OrganizationID: owner.OrganizationID,
+ CreatedBy: owner.UserID,
+ AllowUserCancelWorkspaceJobs: true,
+ })
+ version := dbgen.TemplateVersion(t, db, database.TemplateVersion{
+ OrganizationID: owner.OrganizationID,
+ CreatedBy: owner.UserID,
+ TemplateID: uuid.NullUUID{UUID: template.ID, Valid: true},
+ })
+ // Create some test jobs
+ job1 := dbgen.ProvisionerJob(t, db, coderdAPI.Pubsub, database.ProvisionerJob{
+ OrganizationID: owner.OrganizationID,
+ InitiatorID: owner.UserID,
+ Type: database.ProvisionerJobTypeTemplateVersionImport,
+ Input: []byte(`{"template_version_id":"` + version.ID.String() + `"}`),
+ Tags: database.StringMap{provisionersdk.TagScope: provisionersdk.ScopeOrganization},
+ })
+
+ job2 := dbgen.ProvisionerJob(t, db, coderdAPI.Pubsub, database.ProvisionerJob{
+ OrganizationID: owner.OrganizationID,
+ InitiatorID: member.ID,
+ Type: database.ProvisionerJobTypeWorkspaceBuild,
+ Input: []byte(`{"workspace_build_id":"` + uuid.New().String() + `"}`),
+ Tags: database.StringMap{provisionersdk.TagScope: provisionersdk.ScopeOrganization},
+ })
+ // Test basic list command
+ t.Run("Basic", func(t *testing.T) {
+ t.Parallel()
+
+ inv, root := clitest.New(t, "provisioner", "jobs", "list")
+ clitest.SetupConfig(t, client, root)
+ var buf bytes.Buffer
+ inv.Stdout = &buf
+ err := inv.Run()
+ require.NoError(t, err)
+
+ // Should contain both jobs
+ output := buf.String()
+ assert.Contains(t, output, job1.ID.String())
+ assert.Contains(t, output, job2.ID.String())
+ })
+
+ // Test list with JSON output
+ t.Run("JSON", func(t *testing.T) {
+ t.Parallel()
+
+ inv, root := clitest.New(t, "provisioner", "jobs", "list", "--output", "json")
+ clitest.SetupConfig(t, client, root)
+ var buf bytes.Buffer
+ inv.Stdout = &buf
+ err := inv.Run()
+ require.NoError(t, err)
+
+ // Parse JSON output
+ var jobs []codersdk.ProvisionerJob
+ err = json.Unmarshal(buf.Bytes(), &jobs)
+ require.NoError(t, err)
+
+ // Should contain both jobs
+ jobIDs := make([]uuid.UUID, len(jobs))
+ for i, job := range jobs {
+ jobIDs[i] = job.ID
+ }
+ assert.Contains(t, jobIDs, job1.ID)
+ assert.Contains(t, jobIDs, job2.ID)
+ })
+
+ // Test list with limit
+ t.Run("Limit", func(t *testing.T) {
+ t.Parallel()
+
+ inv, root := clitest.New(t, "provisioner", "jobs", "list", "--limit", "1")
+ clitest.SetupConfig(t, client, root)
+ var buf bytes.Buffer
+ inv.Stdout = &buf
+ err := inv.Run()
+ require.NoError(t, err)
+
+ // Should contain at most 1 job
+ output := buf.String()
+ jobCount := 0
+ if strings.Contains(output, job1.ID.String()) {
+ jobCount++
+ }
+ if strings.Contains(output, job2.ID.String()) {
+ jobCount++
+ }
+ assert.LessOrEqual(t, jobCount, 1)
+ })
+
+ // Test list with initiator filter
+ t.Run("InitiatorFilter", func(t *testing.T) {
+ t.Parallel()
+
+ // Get owner user details to access username
+ ctx := testutil.Context(t, testutil.WaitShort)
+ ownerUser, err := client.User(ctx, owner.UserID.String())
+ require.NoError(t, err)
+
+ // Test filtering by initiator (using username)
+ inv, root := clitest.New(t, "provisioner", "jobs", "list", "--initiator", ownerUser.Username)
+ clitest.SetupConfig(t, client, root)
+ var buf bytes.Buffer
+ inv.Stdout = &buf
+ err = inv.Run()
+ require.NoError(t, err)
+
+ // Should only contain job1 (initiated by owner)
+ output := buf.String()
+ assert.Contains(t, output, job1.ID.String())
+ assert.NotContains(t, output, job2.ID.String())
+ })
+
+ // Test list with invalid user
+ t.Run("InvalidUser", func(t *testing.T) {
+ t.Parallel()
+
+ // Test with non-existent user
+ inv, root := clitest.New(t, "provisioner", "jobs", "list", "--initiator", "nonexistent-user")
+ clitest.SetupConfig(t, client, root)
+ var buf bytes.Buffer
+ inv.Stdout = &buf
+ err := inv.Run()
+ require.Error(t, err)
+ assert.Contains(t, err.Error(), "initiator not found: nonexistent-user")
+ })
+ })
}
diff --git a/cli/testdata/coder_list_--output_json.golden b/cli/testdata/coder_list_--output_json.golden
index 82b73f7b24989..66afcf563dfbd 100644
--- a/cli/testdata/coder_list_--output_json.golden
+++ b/cli/testdata/coder_list_--output_json.golden
@@ -45,6 +45,7 @@
"queue_position": 0,
"queue_size": 0,
"organization_id": "===========[first org ID]===========",
+ "initiator_id": "==========[first user ID]===========",
"input": {
"workspace_build_id": "========[workspace build ID]========"
},
diff --git a/cli/testdata/coder_provisioner_jobs_list_--help.golden b/cli/testdata/coder_provisioner_jobs_list_--help.golden
index 8e22f78e978f2..3a581bd880829 100644
--- a/cli/testdata/coder_provisioner_jobs_list_--help.golden
+++ b/cli/testdata/coder_provisioner_jobs_list_--help.golden
@@ -11,9 +11,12 @@ OPTIONS:
-O, --org string, $CODER_ORGANIZATION
Select which organization (uuid or name) to use.
- -c, --column [id|created at|started at|completed at|canceled at|error|error code|status|worker id|worker name|file id|tags|queue position|queue size|organization id|template version id|workspace build id|type|available workers|template version name|template id|template name|template display name|template icon|workspace id|workspace name|logs overflowed|organization|queue] (default: created at,id,type,template display name,status,queue,tags)
+ -c, --column [id|created at|started at|completed at|canceled at|error|error code|status|worker id|worker name|file id|tags|queue position|queue size|organization id|initiator id|template version id|workspace build id|type|available workers|template version name|template id|template name|template display name|template icon|workspace id|workspace name|logs overflowed|organization|queue] (default: created at,id,type,template display name,status,queue,tags)
Columns to display in table output.
+ -i, --initiator string, $CODER_PROVISIONER_JOB_LIST_INITIATOR
+ Filter by initiator (user ID or username).
+
-l, --limit int, $CODER_PROVISIONER_JOB_LIST_LIMIT (default: 50)
Limit the number of jobs returned.
diff --git a/cli/testdata/coder_provisioner_jobs_list_--output_json.golden b/cli/testdata/coder_provisioner_jobs_list_--output_json.golden
index 6ccf672360a55..3ee6c25e34082 100644
--- a/cli/testdata/coder_provisioner_jobs_list_--output_json.golden
+++ b/cli/testdata/coder_provisioner_jobs_list_--output_json.golden
@@ -15,6 +15,7 @@
"queue_position": 0,
"queue_size": 0,
"organization_id": "===========[first org ID]===========",
+ "initiator_id": "==========[first user ID]===========",
"input": {
"template_version_id": "============[version ID]============"
},
@@ -45,6 +46,7 @@
"queue_position": 0,
"queue_size": 0,
"organization_id": "===========[first org ID]===========",
+ "initiator_id": "==========[first user ID]===========",
"input": {
"workspace_build_id": "========[workspace build ID]========"
},
diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go
index b93c647dad689..289e4c9a3fee9 100644
--- a/coderd/apidoc/docs.go
+++ b/coderd/apidoc/docs.go
@@ -3744,6 +3744,13 @@ const docTemplate = `{
"description": "Provisioner tags to filter by (JSON of the form {'tag1':'value1','tag2':'value2'})",
"name": "tags",
"in": "query"
+ },
+ {
+ "type": "string",
+ "format": "uuid",
+ "description": "Filter results by initiator",
+ "name": "initiator",
+ "in": "query"
}
],
"responses": {
@@ -15974,6 +15981,10 @@ const docTemplate = `{
"type": "string",
"format": "uuid"
},
+ "initiator_id": {
+ "type": "string",
+ "format": "uuid"
+ },
"input": {
"$ref": "#/definitions/codersdk.ProvisionerJobInput"
},
diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json
index 731e1720c09bc..4b3d4c86aaf34 100644
--- a/coderd/apidoc/swagger.json
+++ b/coderd/apidoc/swagger.json
@@ -3299,6 +3299,13 @@
"description": "Provisioner tags to filter by (JSON of the form {'tag1':'value1','tag2':'value2'})",
"name": "tags",
"in": "query"
+ },
+ {
+ "type": "string",
+ "format": "uuid",
+ "description": "Filter results by initiator",
+ "name": "initiator",
+ "in": "query"
}
],
"responses": {
@@ -14532,6 +14539,10 @@
"type": "string",
"format": "uuid"
},
+ "initiator_id": {
+ "type": "string",
+ "format": "uuid"
+ },
"input": {
"$ref": "#/definitions/codersdk.ProvisionerJobInput"
},
diff --git a/coderd/database/dbauthz/dbauthz_test.go b/coderd/database/dbauthz/dbauthz_test.go
index 730d5f3198478..39350ad948ff0 100644
--- a/coderd/database/dbauthz/dbauthz_test.go
+++ b/coderd/database/dbauthz/dbauthz_test.go
@@ -2484,10 +2484,12 @@ func (s *MethodTestSuite) TestExtraMethods() {
ds, err := db.GetProvisionerJobsByOrganizationAndStatusWithQueuePositionAndProvisioner(context.Background(), database.GetProvisionerJobsByOrganizationAndStatusWithQueuePositionAndProvisionerParams{
OrganizationID: org.ID,
+ InitiatorID: uuid.Nil,
})
s.NoError(err, "get provisioner jobs by org")
check.Args(database.GetProvisionerJobsByOrganizationAndStatusWithQueuePositionAndProvisionerParams{
OrganizationID: org.ID,
+ InitiatorID: uuid.Nil,
}).Asserts(j1, policy.ActionRead, j2, policy.ActionRead).Returns(ds)
}))
}
diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go
index 6bf1a3e25d8a0..3612375b8b26c 100644
--- a/coderd/database/queries.sql.go
+++ b/coderd/database/queries.sql.go
@@ -9834,6 +9834,7 @@ WHERE
AND (COALESCE(array_length($2::uuid[], 1), 0) = 0 OR pj.id = ANY($2::uuid[]))
AND (COALESCE(array_length($3::provisioner_job_status[], 1), 0) = 0 OR pj.job_status = ANY($3::provisioner_job_status[]))
AND ($4::tagset = 'null'::tagset OR provisioner_tagset_contains(pj.tags::tagset, $4::tagset))
+ AND ($5::uuid = '00000000-0000-0000-0000-000000000000'::uuid OR pj.initiator_id = $5::uuid)
GROUP BY
pj.id,
qp.queue_position,
@@ -9849,7 +9850,7 @@ GROUP BY
ORDER BY
pj.created_at DESC
LIMIT
- $5::int
+ $6::int
`
type GetProvisionerJobsByOrganizationAndStatusWithQueuePositionAndProvisionerParams struct {
@@ -9857,6 +9858,7 @@ type GetProvisionerJobsByOrganizationAndStatusWithQueuePositionAndProvisionerPar
IDs []uuid.UUID `db:"ids" json:"ids"`
Status []ProvisionerJobStatus `db:"status" json:"status"`
Tags StringMap `db:"tags" json:"tags"`
+ InitiatorID uuid.UUID `db:"initiator_id" json:"initiator_id"`
Limit sql.NullInt32 `db:"limit" json:"limit"`
}
@@ -9881,6 +9883,7 @@ func (q *sqlQuerier) GetProvisionerJobsByOrganizationAndStatusWithQueuePositionA
pq.Array(arg.IDs),
pq.Array(arg.Status),
arg.Tags,
+ arg.InitiatorID,
arg.Limit,
)
if err != nil {
diff --git a/coderd/database/queries/provisionerjobs.sql b/coderd/database/queries/provisionerjobs.sql
index dfc95a0bb4570..02d67d628a861 100644
--- a/coderd/database/queries/provisionerjobs.sql
+++ b/coderd/database/queries/provisionerjobs.sql
@@ -224,6 +224,7 @@ WHERE
AND (COALESCE(array_length(@ids::uuid[], 1), 0) = 0 OR pj.id = ANY(@ids::uuid[]))
AND (COALESCE(array_length(@status::provisioner_job_status[], 1), 0) = 0 OR pj.job_status = ANY(@status::provisioner_job_status[]))
AND (@tags::tagset = 'null'::tagset OR provisioner_tagset_contains(pj.tags::tagset, @tags::tagset))
+ AND (@initiator_id::uuid = '00000000-0000-0000-0000-000000000000'::uuid OR pj.initiator_id = @initiator_id::uuid)
GROUP BY
pj.id,
qp.queue_position,
diff --git a/coderd/provisionerjobs.go b/coderd/provisionerjobs.go
index e9ab5260988d4..4ba923dae2477 100644
--- a/coderd/provisionerjobs.go
+++ b/coderd/provisionerjobs.go
@@ -76,6 +76,7 @@ func (api *API) provisionerJob(rw http.ResponseWriter, r *http.Request) {
// @Param ids query []string false "Filter results by job IDs" format(uuid)
// @Param status query codersdk.ProvisionerJobStatus false "Filter results by status" enums(pending,running,succeeded,canceling,canceled,failed)
// @Param tags query object false "Provisioner tags to filter by (JSON of the form {'tag1':'value1','tag2':'value2'})"
+// @Param initiator query string false "Filter results by initiator" format(uuid)
// @Success 200 {array} codersdk.ProvisionerJob
// @Router /organizations/{organization}/provisionerjobs [get]
func (api *API) provisionerJobs(rw http.ResponseWriter, r *http.Request) {
@@ -110,6 +111,7 @@ func (api *API) handleAuthAndFetchProvisionerJobs(rw http.ResponseWriter, r *htt
ids = p.UUIDs(qp, nil, "ids")
}
tags := p.JSONStringMap(qp, database.StringMap{}, "tags")
+ initiatorID := p.UUID(qp, uuid.Nil, "initiator_id")
p.ErrorExcessParams(qp)
if len(p.Errors) > 0 {
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
@@ -125,6 +127,7 @@ func (api *API) handleAuthAndFetchProvisionerJobs(rw http.ResponseWriter, r *htt
Limit: sql.NullInt32{Int32: limit, Valid: limit > 0},
IDs: ids,
Tags: tags,
+ InitiatorID: initiatorID,
})
if err != nil {
if httpapi.Is404Error(err) {
@@ -355,6 +358,7 @@ func convertProvisionerJob(pj database.GetProvisionerJobsByIDsWithQueuePositionR
job := codersdk.ProvisionerJob{
ID: provisionerJob.ID,
OrganizationID: provisionerJob.OrganizationID,
+ InitiatorID: provisionerJob.InitiatorID,
CreatedAt: provisionerJob.CreatedAt,
Type: codersdk.ProvisionerJobType(provisionerJob.Type),
Error: provisionerJob.Error.String,
diff --git a/coderd/provisionerjobs_test.go b/coderd/provisionerjobs_test.go
index 98da3ae5584e6..829c72aa4dbd0 100644
--- a/coderd/provisionerjobs_test.go
+++ b/coderd/provisionerjobs_test.go
@@ -58,6 +58,8 @@ func TestProvisionerJobs(t *testing.T) {
StartedAt: sql.NullTime{Time: dbtime.Now(), Valid: true},
Type: database.ProvisionerJobTypeWorkspaceBuild,
Input: json.RawMessage(`{"workspace_build_id":"` + wbID.String() + `"}`),
+ InitiatorID: member.ID,
+ Tags: database.StringMap{"initiatorTest": "true"},
})
dbgen.WorkspaceBuild(t, db, database.WorkspaceBuild{
ID: wbID,
@@ -71,6 +73,7 @@ func TestProvisionerJobs(t *testing.T) {
dbgen.ProvisionerJob(t, db, nil, database.ProvisionerJob{
OrganizationID: owner.OrganizationID,
Tags: database.StringMap{"count": strconv.Itoa(i)},
+ InitiatorID: owner.UserID,
})
}
@@ -165,6 +168,94 @@ func TestProvisionerJobs(t *testing.T) {
require.Len(t, jobs, 1)
})
+ t.Run("Initiator", func(t *testing.T) {
+ t.Parallel()
+ ctx := testutil.Context(t, testutil.WaitMedium)
+
+ jobs, err := templateAdminClient.OrganizationProvisionerJobs(ctx, owner.OrganizationID, &codersdk.OrganizationProvisionerJobsOptions{
+ InitiatorID: &member.ID,
+ })
+ require.NoError(t, err)
+ require.GreaterOrEqual(t, len(jobs), 1)
+ require.Equal(t, member.ID, jobs[0].InitiatorID)
+ })
+
+ t.Run("InitiatorWithOtherFilters", func(t *testing.T) {
+ t.Parallel()
+ ctx := testutil.Context(t, testutil.WaitMedium)
+
+ // Test filtering by initiator ID combined with status filter
+ jobs, err := templateAdminClient.OrganizationProvisionerJobs(ctx, owner.OrganizationID, &codersdk.OrganizationProvisionerJobsOptions{
+ InitiatorID: &owner.UserID,
+ Status: []codersdk.ProvisionerJobStatus{codersdk.ProvisionerJobSucceeded},
+ })
+ require.NoError(t, err)
+
+ // Verify all returned jobs have the correct initiator and status
+ for _, job := range jobs {
+ require.Equal(t, owner.UserID, job.InitiatorID)
+ require.Equal(t, codersdk.ProvisionerJobSucceeded, job.Status)
+ }
+ })
+
+ t.Run("InitiatorWithLimit", func(t *testing.T) {
+ t.Parallel()
+ ctx := testutil.Context(t, testutil.WaitMedium)
+
+ // Test filtering by initiator ID with limit
+ jobs, err := templateAdminClient.OrganizationProvisionerJobs(ctx, owner.OrganizationID, &codersdk.OrganizationProvisionerJobsOptions{
+ InitiatorID: &owner.UserID,
+ Limit: 1,
+ })
+ require.NoError(t, err)
+ require.Len(t, jobs, 1)
+
+ // Verify the returned job has the correct initiator
+ require.Equal(t, owner.UserID, jobs[0].InitiatorID)
+ })
+
+ t.Run("InitiatorWithTags", func(t *testing.T) {
+ t.Parallel()
+ ctx := testutil.Context(t, testutil.WaitMedium)
+
+ // Test filtering by initiator ID combined with tags
+ jobs, err := templateAdminClient.OrganizationProvisionerJobs(ctx, owner.OrganizationID, &codersdk.OrganizationProvisionerJobsOptions{
+ InitiatorID: &member.ID,
+ Tags: map[string]string{"initiatorTest": "true"},
+ })
+ require.NoError(t, err)
+ require.Len(t, jobs, 1)
+
+ // Verify the returned job has the correct initiator and tags
+ require.Equal(t, member.ID, jobs[0].InitiatorID)
+ require.Equal(t, "true", jobs[0].Tags["initiatorTest"])
+ })
+
+ t.Run("InitiatorNotFound", func(t *testing.T) {
+ t.Parallel()
+ ctx := testutil.Context(t, testutil.WaitMedium)
+
+ // Test with non-existent initiator ID
+ nonExistentID := uuid.New()
+ jobs, err := templateAdminClient.OrganizationProvisionerJobs(ctx, owner.OrganizationID, &codersdk.OrganizationProvisionerJobsOptions{
+ InitiatorID: &nonExistentID,
+ })
+ require.NoError(t, err)
+ require.Len(t, jobs, 0)
+ })
+
+ t.Run("InitiatorNil", func(t *testing.T) {
+ t.Parallel()
+ ctx := testutil.Context(t, testutil.WaitMedium)
+
+ // Test with nil initiator ID (should return all jobs)
+ jobs, err := templateAdminClient.OrganizationProvisionerJobs(ctx, owner.OrganizationID, &codersdk.OrganizationProvisionerJobsOptions{
+ InitiatorID: nil,
+ })
+ require.NoError(t, err)
+ require.GreaterOrEqual(t, len(jobs), 50) // Should return all jobs (up to default limit)
+ })
+
t.Run("Limit", func(t *testing.T) {
t.Parallel()
ctx := testutil.Context(t, testutil.WaitMedium)
@@ -185,6 +276,17 @@ func TestProvisionerJobs(t *testing.T) {
require.Error(t, err)
require.Len(t, jobs, 0)
})
+
+ t.Run("MemberDeniedWithInitiator", func(t *testing.T) {
+ t.Parallel()
+ ctx := testutil.Context(t, testutil.WaitMedium)
+ // Member should not be able to access jobs even with initiator filter
+ jobs, err := memberClient.OrganizationProvisionerJobs(ctx, owner.OrganizationID, &codersdk.OrganizationProvisionerJobsOptions{
+ InitiatorID: &member.ID,
+ })
+ require.Error(t, err)
+ require.Len(t, jobs, 0)
+ })
})
// Ensures that when a provisioner job is in the succeeded state,
diff --git a/codersdk/organizations.go b/codersdk/organizations.go
index bca87c7bd4591..291bb9ac1baf7 100644
--- a/codersdk/organizations.go
+++ b/codersdk/organizations.go
@@ -397,10 +397,11 @@ func (c *Client) OrganizationProvisionerDaemons(ctx context.Context, organizatio
}
type OrganizationProvisionerJobsOptions struct {
- Limit int
- IDs []uuid.UUID
- Status []ProvisionerJobStatus
- Tags map[string]string
+ Limit int
+ IDs []uuid.UUID
+ Status []ProvisionerJobStatus
+ Tags map[string]string
+ InitiatorID *uuid.UUID
}
func (c *Client) OrganizationProvisionerJobs(ctx context.Context, organizationID uuid.UUID, opts *OrganizationProvisionerJobsOptions) ([]ProvisionerJob, error) {
@@ -422,6 +423,9 @@ func (c *Client) OrganizationProvisionerJobs(ctx context.Context, organizationID
}
qp.Add("tags", string(tagsRaw))
}
+ if opts.InitiatorID != nil {
+ qp.Add("initiator_id", opts.InitiatorID.String())
+ }
}
res, err := c.Request(ctx, http.MethodGet,
diff --git a/codersdk/provisionerdaemons.go b/codersdk/provisionerdaemons.go
index b3cefa09110ec..19f8cae546118 100644
--- a/codersdk/provisionerdaemons.go
+++ b/codersdk/provisionerdaemons.go
@@ -198,6 +198,7 @@ type ProvisionerJob struct {
QueuePosition int `json:"queue_position" table:"queue position"`
QueueSize int `json:"queue_size" table:"queue size"`
OrganizationID uuid.UUID `json:"organization_id" format:"uuid" table:"organization id"`
+ InitiatorID uuid.UUID `json:"initiator_id" format:"uuid" table:"initiator id"`
Input ProvisionerJobInput `json:"input" table:"input,recursive_inline"`
Type ProvisionerJobType `json:"type" table:"type"`
AvailableWorkers []uuid.UUID `json:"available_workers,omitempty" format:"uuid" table:"available workers"`
diff --git a/docs/reference/api/builds.md b/docs/reference/api/builds.md
index 232509052b7b0..41df0b9efaf30 100644
--- a/docs/reference/api/builds.md
+++ b/docs/reference/api/builds.md
@@ -48,6 +48,7 @@ curl -X GET http://coder-server:8080/api/v2/users/{user}/workspace/{workspacenam
"error_code": "REQUIRED_TEMPLATE_VARIABLES",
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+ "initiator_id": "06588898-9a84-4b35-ba8f-f9cbd64946f3",
"input": {
"error": "string",
"template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1",
@@ -288,6 +289,7 @@ curl -X GET http://coder-server:8080/api/v2/workspacebuilds/{workspacebuild} \
"error_code": "REQUIRED_TEMPLATE_VARIABLES",
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+ "initiator_id": "06588898-9a84-4b35-ba8f-f9cbd64946f3",
"input": {
"error": "string",
"template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1",
@@ -1019,6 +1021,7 @@ curl -X GET http://coder-server:8080/api/v2/workspacebuilds/{workspacebuild}/sta
"error_code": "REQUIRED_TEMPLATE_VARIABLES",
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+ "initiator_id": "06588898-9a84-4b35-ba8f-f9cbd64946f3",
"input": {
"error": "string",
"template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1",
@@ -1332,6 +1335,7 @@ curl -X GET http://coder-server:8080/api/v2/workspaces/{workspace}/builds \
"error_code": "REQUIRED_TEMPLATE_VARIABLES",
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+ "initiator_id": "06588898-9a84-4b35-ba8f-f9cbd64946f3",
"input": {
"error": "string",
"template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1",
@@ -1551,6 +1555,7 @@ Status Code **200**
| `»» error_code` | [codersdk.JobErrorCode](schemas.md#codersdkjoberrorcode) | false | | |
| `»» file_id` | string(uuid) | false | | |
| `»» id` | string(uuid) | false | | |
+| `»» initiator_id` | string(uuid) | false | | |
| `»» input` | [codersdk.ProvisionerJobInput](schemas.md#codersdkprovisionerjobinput) | false | | |
| `»»» error` | string | false | | |
| `»»» template_version_id` | string(uuid) | false | | |
@@ -1829,6 +1834,7 @@ curl -X POST http://coder-server:8080/api/v2/workspaces/{workspace}/builds \
"error_code": "REQUIRED_TEMPLATE_VARIABLES",
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+ "initiator_id": "06588898-9a84-4b35-ba8f-f9cbd64946f3",
"input": {
"error": "string",
"template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1",
diff --git a/docs/reference/api/organizations.md b/docs/reference/api/organizations.md
index d418a1fcba106..ffd6f78405fb1 100644
--- a/docs/reference/api/organizations.md
+++ b/docs/reference/api/organizations.md
@@ -366,6 +366,7 @@ curl -X GET http://coder-server:8080/api/v2/organizations/{organization}/provisi
| `ids` | query | array(uuid) | false | Filter results by job IDs |
| `status` | query | string | false | Filter results by status |
| `tags` | query | object | false | Provisioner tags to filter by (JSON of the form {'tag1':'value1','tag2':'value2'}) |
+| `initiator` | query | string(uuid) | false | Filter results by initiator |
#### Enumerated Values
@@ -402,6 +403,7 @@ curl -X GET http://coder-server:8080/api/v2/organizations/{organization}/provisi
"error_code": "REQUIRED_TEMPLATE_VARIABLES",
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+ "initiator_id": "06588898-9a84-4b35-ba8f-f9cbd64946f3",
"input": {
"error": "string",
"template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1",
@@ -454,6 +456,7 @@ Status Code **200**
| `» error_code` | [codersdk.JobErrorCode](schemas.md#codersdkjoberrorcode) | false | | |
| `» file_id` | string(uuid) | false | | |
| `» id` | string(uuid) | false | | |
+| `» initiator_id` | string(uuid) | false | | |
| `» input` | [codersdk.ProvisionerJobInput](schemas.md#codersdkprovisionerjobinput) | false | | |
| `»» error` | string | false | | |
| `»» template_version_id` | string(uuid) | false | | |
@@ -531,6 +534,7 @@ curl -X GET http://coder-server:8080/api/v2/organizations/{organization}/provisi
"error_code": "REQUIRED_TEMPLATE_VARIABLES",
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+ "initiator_id": "06588898-9a84-4b35-ba8f-f9cbd64946f3",
"input": {
"error": "string",
"template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1",
diff --git a/docs/reference/api/schemas.md b/docs/reference/api/schemas.md
index 98324941a1c70..33cb280ae15c0 100644
--- a/docs/reference/api/schemas.md
+++ b/docs/reference/api/schemas.md
@@ -6390,6 +6390,7 @@ Only certain features set these fields: - FeatureManagedAgentLimit|
"error_code": "REQUIRED_TEMPLATE_VARIABLES",
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+ "initiator_id": "06588898-9a84-4b35-ba8f-f9cbd64946f3",
"input": {
"error": "string",
"template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1",
@@ -6432,6 +6433,7 @@ Only certain features set these fields: - FeatureManagedAgentLimit|
| `error_code` | [codersdk.JobErrorCode](#codersdkjoberrorcode) | false | | |
| `file_id` | string | false | | |
| `id` | string | false | | |
+| `initiator_id` | string | false | | |
| `input` | [codersdk.ProvisionerJobInput](#codersdkprovisionerjobinput) | false | | |
| `logs_overflowed` | boolean | false | | |
| `metadata` | [codersdk.ProvisionerJobMetadata](#codersdkprovisionerjobmetadata) | false | | |
@@ -8118,6 +8120,7 @@ Restarts will only happen on weekdays in this list on weeks which line up with W
"error_code": "REQUIRED_TEMPLATE_VARIABLES",
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+ "initiator_id": "06588898-9a84-4b35-ba8f-f9cbd64946f3",
"input": {
"error": "string",
"template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1",
@@ -9386,6 +9389,7 @@ If the schedule is empty, the user will be updated to use the default schedule.|
"error_code": "REQUIRED_TEMPLATE_VARIABLES",
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+ "initiator_id": "06588898-9a84-4b35-ba8f-f9cbd64946f3",
"input": {
"error": "string",
"template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1",
@@ -10553,6 +10557,7 @@ If the schedule is empty, the user will be updated to use the default schedule.|
"error_code": "REQUIRED_TEMPLATE_VARIABLES",
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+ "initiator_id": "06588898-9a84-4b35-ba8f-f9cbd64946f3",
"input": {
"error": "string",
"template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1",
@@ -11389,6 +11394,7 @@ If the schedule is empty, the user will be updated to use the default schedule.|
"error_code": "REQUIRED_TEMPLATE_VARIABLES",
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+ "initiator_id": "06588898-9a84-4b35-ba8f-f9cbd64946f3",
"input": {
"error": "string",
"template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1",
diff --git a/docs/reference/api/templates.md b/docs/reference/api/templates.md
index efc59cf7b5743..9d69949ac7cf9 100644
--- a/docs/reference/api/templates.md
+++ b/docs/reference/api/templates.md
@@ -475,6 +475,7 @@ curl -X GET http://coder-server:8080/api/v2/organizations/{organization}/templat
"error_code": "REQUIRED_TEMPLATE_VARIABLES",
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+ "initiator_id": "06588898-9a84-4b35-ba8f-f9cbd64946f3",
"input": {
"error": "string",
"template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1",
@@ -575,6 +576,7 @@ curl -X GET http://coder-server:8080/api/v2/organizations/{organization}/templat
"error_code": "REQUIRED_TEMPLATE_VARIABLES",
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+ "initiator_id": "06588898-9a84-4b35-ba8f-f9cbd64946f3",
"input": {
"error": "string",
"template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1",
@@ -699,6 +701,7 @@ curl -X POST http://coder-server:8080/api/v2/organizations/{organization}/templa
"error_code": "REQUIRED_TEMPLATE_VARIABLES",
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+ "initiator_id": "06588898-9a84-4b35-ba8f-f9cbd64946f3",
"input": {
"error": "string",
"template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1",
@@ -1306,6 +1309,7 @@ curl -X GET http://coder-server:8080/api/v2/templates/{template}/versions \
"error_code": "REQUIRED_TEMPLATE_VARIABLES",
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+ "initiator_id": "06588898-9a84-4b35-ba8f-f9cbd64946f3",
"input": {
"error": "string",
"template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1",
@@ -1382,6 +1386,7 @@ Status Code **200**
| `»» error_code` | [codersdk.JobErrorCode](schemas.md#codersdkjoberrorcode) | false | | |
| `»» file_id` | string(uuid) | false | | |
| `»» id` | string(uuid) | false | | |
+| `»» initiator_id` | string(uuid) | false | | |
| `»» input` | [codersdk.ProvisionerJobInput](schemas.md#codersdkprovisionerjobinput) | false | | |
| `»»» error` | string | false | | |
| `»»» template_version_id` | string(uuid) | false | | |
@@ -1589,6 +1594,7 @@ curl -X GET http://coder-server:8080/api/v2/templates/{template}/versions/{templ
"error_code": "REQUIRED_TEMPLATE_VARIABLES",
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+ "initiator_id": "06588898-9a84-4b35-ba8f-f9cbd64946f3",
"input": {
"error": "string",
"template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1",
@@ -1665,6 +1671,7 @@ Status Code **200**
| `»» error_code` | [codersdk.JobErrorCode](schemas.md#codersdkjoberrorcode) | false | | |
| `»» file_id` | string(uuid) | false | | |
| `»» id` | string(uuid) | false | | |
+| `»» initiator_id` | string(uuid) | false | | |
| `»» input` | [codersdk.ProvisionerJobInput](schemas.md#codersdkprovisionerjobinput) | false | | |
| `»»» error` | string | false | | |
| `»»» template_version_id` | string(uuid) | false | | |
@@ -1762,6 +1769,7 @@ curl -X GET http://coder-server:8080/api/v2/templateversions/{templateversion} \
"error_code": "REQUIRED_TEMPLATE_VARIABLES",
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+ "initiator_id": "06588898-9a84-4b35-ba8f-f9cbd64946f3",
"input": {
"error": "string",
"template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1",
@@ -1871,6 +1879,7 @@ curl -X PATCH http://coder-server:8080/api/v2/templateversions/{templateversion}
"error_code": "REQUIRED_TEMPLATE_VARIABLES",
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+ "initiator_id": "06588898-9a84-4b35-ba8f-f9cbd64946f3",
"input": {
"error": "string",
"template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1",
@@ -2069,6 +2078,7 @@ curl -X POST http://coder-server:8080/api/v2/templateversions/{templateversion}/
"error_code": "REQUIRED_TEMPLATE_VARIABLES",
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+ "initiator_id": "06588898-9a84-4b35-ba8f-f9cbd64946f3",
"input": {
"error": "string",
"template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1",
@@ -2143,6 +2153,7 @@ curl -X GET http://coder-server:8080/api/v2/templateversions/{templateversion}/d
"error_code": "REQUIRED_TEMPLATE_VARIABLES",
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+ "initiator_id": "06588898-9a84-4b35-ba8f-f9cbd64946f3",
"input": {
"error": "string",
"template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1",
diff --git a/docs/reference/api/workspaces.md b/docs/reference/api/workspaces.md
index 455fefcb57749..e2a95613ed263 100644
--- a/docs/reference/api/workspaces.md
+++ b/docs/reference/api/workspaces.md
@@ -103,6 +103,7 @@ of the template will be used.
"error_code": "REQUIRED_TEMPLATE_VARIABLES",
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+ "initiator_id": "06588898-9a84-4b35-ba8f-f9cbd64946f3",
"input": {
"error": "string",
"template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1",
@@ -393,6 +394,7 @@ curl -X GET http://coder-server:8080/api/v2/users/{user}/workspace/{workspacenam
"error_code": "REQUIRED_TEMPLATE_VARIABLES",
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+ "initiator_id": "06588898-9a84-4b35-ba8f-f9cbd64946f3",
"input": {
"error": "string",
"template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1",
@@ -708,6 +710,7 @@ of the template will be used.
"error_code": "REQUIRED_TEMPLATE_VARIABLES",
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+ "initiator_id": "06588898-9a84-4b35-ba8f-f9cbd64946f3",
"input": {
"error": "string",
"template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1",
@@ -1001,6 +1004,7 @@ curl -X GET http://coder-server:8080/api/v2/workspaces \
"error_code": "REQUIRED_TEMPLATE_VARIABLES",
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+ "initiator_id": "06588898-9a84-4b35-ba8f-f9cbd64946f3",
"input": {
"error": "string",
"template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1",
@@ -1275,6 +1279,7 @@ curl -X GET http://coder-server:8080/api/v2/workspaces/{workspace} \
"error_code": "REQUIRED_TEMPLATE_VARIABLES",
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+ "initiator_id": "06588898-9a84-4b35-ba8f-f9cbd64946f3",
"input": {
"error": "string",
"template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1",
@@ -1824,6 +1829,7 @@ curl -X PUT http://coder-server:8080/api/v2/workspaces/{workspace}/dormant \
"error_code": "REQUIRED_TEMPLATE_VARIABLES",
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
+ "initiator_id": "06588898-9a84-4b35-ba8f-f9cbd64946f3",
"input": {
"error": "string",
"template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1",
diff --git a/docs/reference/cli/provisioner_jobs_list.md b/docs/reference/cli/provisioner_jobs_list.md
index a0bff8554d610..0167dd467d60a 100644
--- a/docs/reference/cli/provisioner_jobs_list.md
+++ b/docs/reference/cli/provisioner_jobs_list.md
@@ -34,6 +34,15 @@ Filter by job status.
Limit the number of jobs returned.
+### -i, --initiator
+
+| | |
+|-------------|----------------------------------------------------|
+| Type | string |
+| Environment | $CODER_PROVISIONER_JOB_LIST_INITIATOR |
+
+Filter by initiator (user ID or username).
+
### -O, --org
| | |
@@ -45,10 +54,10 @@ Select which organization (uuid or name) to use.
### -c, --column
-| | |
-|---------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| Type | [id\|created at\|started at\|completed at\|canceled at\|error\|error code\|status\|worker id\|worker name\|file id\|tags\|queue position\|queue size\|organization id\|template version id\|workspace build id\|type\|available workers\|template version name\|template id\|template name\|template display name\|template icon\|workspace id\|workspace name\|logs overflowed\|organization\|queue] |
-| Default | created at,id,type,template display name,status,queue,tags |
+| | |
+|---------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| Type | [id\|created at\|started at\|completed at\|canceled at\|error\|error code\|status\|worker id\|worker name\|file id\|tags\|queue position\|queue size\|organization id\|initiator id\|template version id\|workspace build id\|type\|available workers\|template version name\|template id\|template name\|template display name\|template icon\|workspace id\|workspace name\|logs overflowed\|organization\|queue] |
+| Default | created at,id,type,template display name,status,queue,tags |
Columns to display in table output.
diff --git a/enterprise/cli/testdata/coder_provisioner_jobs_list_--help.golden b/enterprise/cli/testdata/coder_provisioner_jobs_list_--help.golden
index 8e22f78e978f2..3a581bd880829 100644
--- a/enterprise/cli/testdata/coder_provisioner_jobs_list_--help.golden
+++ b/enterprise/cli/testdata/coder_provisioner_jobs_list_--help.golden
@@ -11,9 +11,12 @@ OPTIONS:
-O, --org string, $CODER_ORGANIZATION
Select which organization (uuid or name) to use.
- -c, --column [id|created at|started at|completed at|canceled at|error|error code|status|worker id|worker name|file id|tags|queue position|queue size|organization id|template version id|workspace build id|type|available workers|template version name|template id|template name|template display name|template icon|workspace id|workspace name|logs overflowed|organization|queue] (default: created at,id,type,template display name,status,queue,tags)
+ -c, --column [id|created at|started at|completed at|canceled at|error|error code|status|worker id|worker name|file id|tags|queue position|queue size|organization id|initiator id|template version id|workspace build id|type|available workers|template version name|template id|template name|template display name|template icon|workspace id|workspace name|logs overflowed|organization|queue] (default: created at,id,type,template display name,status,queue,tags)
Columns to display in table output.
+ -i, --initiator string, $CODER_PROVISIONER_JOB_LIST_INITIATOR
+ Filter by initiator (user ID or username).
+
-l, --limit int, $CODER_PROVISIONER_JOB_LIST_LIMIT (default: 50)
Limit the number of jobs returned.
diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts
index 0519c9c136cec..e7c612078b6f3 100644
--- a/site/src/api/typesGenerated.ts
+++ b/site/src/api/typesGenerated.ts
@@ -2060,6 +2060,7 @@ export interface OrganizationProvisionerJobsOptions {
readonly IDs: readonly string[];
readonly Status: readonly ProvisionerJobStatus[];
readonly Tags: Record;
+ readonly InitiatorID: string | null;
}
// From codersdk/idpsync.go
@@ -2379,6 +2380,7 @@ export interface ProvisionerJob {
readonly queue_position: number;
readonly queue_size: number;
readonly organization_id: string;
+ readonly initiator_id: string;
readonly input: ProvisionerJobInput;
readonly type: ProvisionerJobType;
readonly available_workers?: readonly string[];
diff --git a/site/src/testHelpers/entities.ts b/site/src/testHelpers/entities.ts
index 19c414bdd3158..0b8d87f8111ef 100644
--- a/site/src/testHelpers/entities.ts
+++ b/site/src/testHelpers/entities.ts
@@ -679,6 +679,7 @@ export const MockProvisionerJob: TypesGen.ProvisionerJob = {
status: "succeeded",
file_id: MockOrganization.id,
completed_at: "2022-05-17T17:39:01.382927298Z",
+ initiator_id: MockUserMember.id,
tags: {
scope: "organization",
owner: "",
From b60ae0a0c44457c7c655faa3fd4b5f13d1d0af15 Mon Sep 17 00:00:00 2001
From: Thomas Kosiewski
Date: Mon, 6 Oct 2025 12:08:17 +0200
Subject: [PATCH 057/298] refactor: add wildcard scope entries for API key
scopes (#20032)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
# Add API Key Scope Wildcards
This PR adds wildcard API key scopes (`resource:*`) for all RBAC resources to ensure every resource has a matching wildcard value. It also adds all individual `resource:action` scopes to the API documentation and TypeScript definitions.
The changes include:
- Adding a new database migration (000377) that adds wildcard API key scopes
- Updating the API documentation to include all available scopes
- Enhancing the scope generation scripts to include all resource wildcards
- Updating the TypeScript definitions to match the expanded scope list
These changes make creating API keys with comprehensive permissions for specific resource types easier.
---
coderd/apidoc/docs.go | 300 +++++++++++++++++-
coderd/apidoc/swagger.json | 300 +++++++++++++++++-
coderd/database/dump.sql | 42 ++-
...00377_add_api_key_scope_wildcards.down.sql | 2 +
.../000377_add_api_key_scope_wildcards.up.sql | 42 +++
coderd/database/models.go | 122 ++++++-
codersdk/apikey_scopes_gen.go | 228 ++++++++++---
docs/reference/api/schemas.md | 234 +++++++++++---
scripts/apikeyscopesgen/main.go | 70 +++-
scripts/check-scopes/main.go | 24 +-
scripts/generate_api_key_scope_enum/main.go | 32 --
site/src/api/typesGenerated.ts | 296 +++++++++++++++++
12 files changed, 1551 insertions(+), 141 deletions(-)
create mode 100644 coderd/database/migrations/000377_add_api_key_scope_wildcards.down.sql
create mode 100644 coderd/database/migrations/000377_add_api_key_scope_wildcards.up.sql
delete mode 100644 scripts/generate_api_key_scope_enum/main.go
diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go
index 289e4c9a3fee9..b444d50a8c63b 100644
--- a/coderd/apidoc/docs.go
+++ b/coderd/apidoc/docs.go
@@ -11530,11 +11530,29 @@ const docTemplate = `{
"enum": [
"all",
"application_connect",
+ "aibridge_interception:*",
+ "aibridge_interception:create",
+ "aibridge_interception:read",
+ "aibridge_interception:update",
"api_key:*",
"api_key:create",
"api_key:delete",
"api_key:read",
"api_key:update",
+ "assign_org_role:*",
+ "assign_org_role:assign",
+ "assign_org_role:create",
+ "assign_org_role:delete",
+ "assign_org_role:read",
+ "assign_org_role:unassign",
+ "assign_org_role:update",
+ "assign_role:*",
+ "assign_role:assign",
+ "assign_role:read",
+ "assign_role:unassign",
+ "audit_log:*",
+ "audit_log:create",
+ "audit_log:read",
"coder:all",
"coder:apikeys.manage_self",
"coder:application_connect",
@@ -11544,40 +11562,188 @@ const docTemplate = `{
"coder:workspaces.create",
"coder:workspaces.delete",
"coder:workspaces.operate",
+ "connection_log:*",
+ "connection_log:read",
+ "connection_log:update",
+ "crypto_key:*",
+ "crypto_key:create",
+ "crypto_key:delete",
+ "crypto_key:read",
+ "crypto_key:update",
+ "debug_info:*",
+ "debug_info:read",
+ "deployment_config:*",
+ "deployment_config:read",
+ "deployment_config:update",
+ "deployment_stats:*",
+ "deployment_stats:read",
"file:*",
"file:create",
"file:read",
+ "group:*",
+ "group:create",
+ "group:delete",
+ "group:read",
+ "group:update",
+ "group_member:*",
+ "group_member:read",
+ "idpsync_settings:*",
+ "idpsync_settings:read",
+ "idpsync_settings:update",
+ "inbox_notification:*",
+ "inbox_notification:create",
+ "inbox_notification:read",
+ "inbox_notification:update",
+ "license:*",
+ "license:create",
+ "license:delete",
+ "license:read",
+ "notification_message:*",
+ "notification_message:create",
+ "notification_message:delete",
+ "notification_message:read",
+ "notification_message:update",
+ "notification_preference:*",
+ "notification_preference:read",
+ "notification_preference:update",
+ "notification_template:*",
+ "notification_template:read",
+ "notification_template:update",
+ "oauth2_app:*",
+ "oauth2_app:create",
+ "oauth2_app:delete",
+ "oauth2_app:read",
+ "oauth2_app:update",
+ "oauth2_app_code_token:*",
+ "oauth2_app_code_token:create",
+ "oauth2_app_code_token:delete",
+ "oauth2_app_code_token:read",
+ "oauth2_app_secret:*",
+ "oauth2_app_secret:create",
+ "oauth2_app_secret:delete",
+ "oauth2_app_secret:read",
+ "oauth2_app_secret:update",
+ "organization:*",
+ "organization:create",
+ "organization:delete",
+ "organization:read",
+ "organization:update",
+ "organization_member:*",
+ "organization_member:create",
+ "organization_member:delete",
+ "organization_member:read",
+ "organization_member:update",
+ "prebuilt_workspace:*",
+ "prebuilt_workspace:delete",
+ "prebuilt_workspace:update",
+ "provisioner_daemon:*",
+ "provisioner_daemon:create",
+ "provisioner_daemon:delete",
+ "provisioner_daemon:read",
+ "provisioner_daemon:update",
+ "provisioner_jobs:*",
+ "provisioner_jobs:create",
+ "provisioner_jobs:read",
+ "provisioner_jobs:update",
+ "replicas:*",
+ "replicas:read",
+ "system:*",
+ "system:create",
+ "system:delete",
+ "system:read",
+ "system:update",
+ "tailnet_coordinator:*",
+ "tailnet_coordinator:create",
+ "tailnet_coordinator:delete",
+ "tailnet_coordinator:read",
+ "tailnet_coordinator:update",
"template:*",
"template:create",
"template:delete",
"template:read",
"template:update",
"template:use",
+ "template:view_insights",
+ "usage_event:*",
+ "usage_event:create",
+ "usage_event:read",
+ "usage_event:update",
+ "user:*",
+ "user:create",
+ "user:delete",
+ "user:read",
"user:read_personal",
+ "user:update",
"user:update_personal",
"user_secret:*",
"user_secret:create",
"user_secret:delete",
"user_secret:read",
"user_secret:update",
+ "webpush_subscription:*",
+ "webpush_subscription:create",
+ "webpush_subscription:delete",
+ "webpush_subscription:read",
"workspace:*",
"workspace:application_connect",
"workspace:create",
+ "workspace:create_agent",
"workspace:delete",
+ "workspace:delete_agent",
"workspace:read",
"workspace:ssh",
"workspace:start",
"workspace:stop",
- "workspace:update"
+ "workspace:update",
+ "workspace_agent_devcontainers:*",
+ "workspace_agent_devcontainers:create",
+ "workspace_agent_resource_monitor:*",
+ "workspace_agent_resource_monitor:create",
+ "workspace_agent_resource_monitor:read",
+ "workspace_agent_resource_monitor:update",
+ "workspace_dormant:*",
+ "workspace_dormant:application_connect",
+ "workspace_dormant:create",
+ "workspace_dormant:create_agent",
+ "workspace_dormant:delete",
+ "workspace_dormant:delete_agent",
+ "workspace_dormant:read",
+ "workspace_dormant:ssh",
+ "workspace_dormant:start",
+ "workspace_dormant:stop",
+ "workspace_dormant:update",
+ "workspace_proxy:*",
+ "workspace_proxy:create",
+ "workspace_proxy:delete",
+ "workspace_proxy:read",
+ "workspace_proxy:update"
],
"x-enum-varnames": [
"APIKeyScopeAll",
"APIKeyScopeApplicationConnect",
+ "APIKeyScopeAibridgeInterceptionAll",
+ "APIKeyScopeAibridgeInterceptionCreate",
+ "APIKeyScopeAibridgeInterceptionRead",
+ "APIKeyScopeAibridgeInterceptionUpdate",
"APIKeyScopeApiKeyAll",
"APIKeyScopeApiKeyCreate",
"APIKeyScopeApiKeyDelete",
"APIKeyScopeApiKeyRead",
"APIKeyScopeApiKeyUpdate",
+ "APIKeyScopeAssignOrgRoleAll",
+ "APIKeyScopeAssignOrgRoleAssign",
+ "APIKeyScopeAssignOrgRoleCreate",
+ "APIKeyScopeAssignOrgRoleDelete",
+ "APIKeyScopeAssignOrgRoleRead",
+ "APIKeyScopeAssignOrgRoleUnassign",
+ "APIKeyScopeAssignOrgRoleUpdate",
+ "APIKeyScopeAssignRoleAll",
+ "APIKeyScopeAssignRoleAssign",
+ "APIKeyScopeAssignRoleRead",
+ "APIKeyScopeAssignRoleUnassign",
+ "APIKeyScopeAuditLogAll",
+ "APIKeyScopeAuditLogCreate",
+ "APIKeyScopeAuditLogRead",
"APIKeyScopeCoderAll",
"APIKeyScopeCoderApikeysManageSelf",
"APIKeyScopeCoderApplicationConnect",
@@ -11587,31 +11753,161 @@ const docTemplate = `{
"APIKeyScopeCoderWorkspacesCreate",
"APIKeyScopeCoderWorkspacesDelete",
"APIKeyScopeCoderWorkspacesOperate",
+ "APIKeyScopeConnectionLogAll",
+ "APIKeyScopeConnectionLogRead",
+ "APIKeyScopeConnectionLogUpdate",
+ "APIKeyScopeCryptoKeyAll",
+ "APIKeyScopeCryptoKeyCreate",
+ "APIKeyScopeCryptoKeyDelete",
+ "APIKeyScopeCryptoKeyRead",
+ "APIKeyScopeCryptoKeyUpdate",
+ "APIKeyScopeDebugInfoAll",
+ "APIKeyScopeDebugInfoRead",
+ "APIKeyScopeDeploymentConfigAll",
+ "APIKeyScopeDeploymentConfigRead",
+ "APIKeyScopeDeploymentConfigUpdate",
+ "APIKeyScopeDeploymentStatsAll",
+ "APIKeyScopeDeploymentStatsRead",
"APIKeyScopeFileAll",
"APIKeyScopeFileCreate",
"APIKeyScopeFileRead",
+ "APIKeyScopeGroupAll",
+ "APIKeyScopeGroupCreate",
+ "APIKeyScopeGroupDelete",
+ "APIKeyScopeGroupRead",
+ "APIKeyScopeGroupUpdate",
+ "APIKeyScopeGroupMemberAll",
+ "APIKeyScopeGroupMemberRead",
+ "APIKeyScopeIdpsyncSettingsAll",
+ "APIKeyScopeIdpsyncSettingsRead",
+ "APIKeyScopeIdpsyncSettingsUpdate",
+ "APIKeyScopeInboxNotificationAll",
+ "APIKeyScopeInboxNotificationCreate",
+ "APIKeyScopeInboxNotificationRead",
+ "APIKeyScopeInboxNotificationUpdate",
+ "APIKeyScopeLicenseAll",
+ "APIKeyScopeLicenseCreate",
+ "APIKeyScopeLicenseDelete",
+ "APIKeyScopeLicenseRead",
+ "APIKeyScopeNotificationMessageAll",
+ "APIKeyScopeNotificationMessageCreate",
+ "APIKeyScopeNotificationMessageDelete",
+ "APIKeyScopeNotificationMessageRead",
+ "APIKeyScopeNotificationMessageUpdate",
+ "APIKeyScopeNotificationPreferenceAll",
+ "APIKeyScopeNotificationPreferenceRead",
+ "APIKeyScopeNotificationPreferenceUpdate",
+ "APIKeyScopeNotificationTemplateAll",
+ "APIKeyScopeNotificationTemplateRead",
+ "APIKeyScopeNotificationTemplateUpdate",
+ "APIKeyScopeOauth2AppAll",
+ "APIKeyScopeOauth2AppCreate",
+ "APIKeyScopeOauth2AppDelete",
+ "APIKeyScopeOauth2AppRead",
+ "APIKeyScopeOauth2AppUpdate",
+ "APIKeyScopeOauth2AppCodeTokenAll",
+ "APIKeyScopeOauth2AppCodeTokenCreate",
+ "APIKeyScopeOauth2AppCodeTokenDelete",
+ "APIKeyScopeOauth2AppCodeTokenRead",
+ "APIKeyScopeOauth2AppSecretAll",
+ "APIKeyScopeOauth2AppSecretCreate",
+ "APIKeyScopeOauth2AppSecretDelete",
+ "APIKeyScopeOauth2AppSecretRead",
+ "APIKeyScopeOauth2AppSecretUpdate",
+ "APIKeyScopeOrganizationAll",
+ "APIKeyScopeOrganizationCreate",
+ "APIKeyScopeOrganizationDelete",
+ "APIKeyScopeOrganizationRead",
+ "APIKeyScopeOrganizationUpdate",
+ "APIKeyScopeOrganizationMemberAll",
+ "APIKeyScopeOrganizationMemberCreate",
+ "APIKeyScopeOrganizationMemberDelete",
+ "APIKeyScopeOrganizationMemberRead",
+ "APIKeyScopeOrganizationMemberUpdate",
+ "APIKeyScopePrebuiltWorkspaceAll",
+ "APIKeyScopePrebuiltWorkspaceDelete",
+ "APIKeyScopePrebuiltWorkspaceUpdate",
+ "APIKeyScopeProvisionerDaemonAll",
+ "APIKeyScopeProvisionerDaemonCreate",
+ "APIKeyScopeProvisionerDaemonDelete",
+ "APIKeyScopeProvisionerDaemonRead",
+ "APIKeyScopeProvisionerDaemonUpdate",
+ "APIKeyScopeProvisionerJobsAll",
+ "APIKeyScopeProvisionerJobsCreate",
+ "APIKeyScopeProvisionerJobsRead",
+ "APIKeyScopeProvisionerJobsUpdate",
+ "APIKeyScopeReplicasAll",
+ "APIKeyScopeReplicasRead",
+ "APIKeyScopeSystemAll",
+ "APIKeyScopeSystemCreate",
+ "APIKeyScopeSystemDelete",
+ "APIKeyScopeSystemRead",
+ "APIKeyScopeSystemUpdate",
+ "APIKeyScopeTailnetCoordinatorAll",
+ "APIKeyScopeTailnetCoordinatorCreate",
+ "APIKeyScopeTailnetCoordinatorDelete",
+ "APIKeyScopeTailnetCoordinatorRead",
+ "APIKeyScopeTailnetCoordinatorUpdate",
"APIKeyScopeTemplateAll",
"APIKeyScopeTemplateCreate",
"APIKeyScopeTemplateDelete",
"APIKeyScopeTemplateRead",
"APIKeyScopeTemplateUpdate",
"APIKeyScopeTemplateUse",
+ "APIKeyScopeTemplateViewInsights",
+ "APIKeyScopeUsageEventAll",
+ "APIKeyScopeUsageEventCreate",
+ "APIKeyScopeUsageEventRead",
+ "APIKeyScopeUsageEventUpdate",
+ "APIKeyScopeUserAll",
+ "APIKeyScopeUserCreate",
+ "APIKeyScopeUserDelete",
+ "APIKeyScopeUserRead",
"APIKeyScopeUserReadPersonal",
+ "APIKeyScopeUserUpdate",
"APIKeyScopeUserUpdatePersonal",
"APIKeyScopeUserSecretAll",
"APIKeyScopeUserSecretCreate",
"APIKeyScopeUserSecretDelete",
"APIKeyScopeUserSecretRead",
"APIKeyScopeUserSecretUpdate",
+ "APIKeyScopeWebpushSubscriptionAll",
+ "APIKeyScopeWebpushSubscriptionCreate",
+ "APIKeyScopeWebpushSubscriptionDelete",
+ "APIKeyScopeWebpushSubscriptionRead",
"APIKeyScopeWorkspaceAll",
"APIKeyScopeWorkspaceApplicationConnect",
"APIKeyScopeWorkspaceCreate",
+ "APIKeyScopeWorkspaceCreateAgent",
"APIKeyScopeWorkspaceDelete",
+ "APIKeyScopeWorkspaceDeleteAgent",
"APIKeyScopeWorkspaceRead",
"APIKeyScopeWorkspaceSsh",
"APIKeyScopeWorkspaceStart",
"APIKeyScopeWorkspaceStop",
- "APIKeyScopeWorkspaceUpdate"
+ "APIKeyScopeWorkspaceUpdate",
+ "APIKeyScopeWorkspaceAgentDevcontainersAll",
+ "APIKeyScopeWorkspaceAgentDevcontainersCreate",
+ "APIKeyScopeWorkspaceAgentResourceMonitorAll",
+ "APIKeyScopeWorkspaceAgentResourceMonitorCreate",
+ "APIKeyScopeWorkspaceAgentResourceMonitorRead",
+ "APIKeyScopeWorkspaceAgentResourceMonitorUpdate",
+ "APIKeyScopeWorkspaceDormantAll",
+ "APIKeyScopeWorkspaceDormantApplicationConnect",
+ "APIKeyScopeWorkspaceDormantCreate",
+ "APIKeyScopeWorkspaceDormantCreateAgent",
+ "APIKeyScopeWorkspaceDormantDelete",
+ "APIKeyScopeWorkspaceDormantDeleteAgent",
+ "APIKeyScopeWorkspaceDormantRead",
+ "APIKeyScopeWorkspaceDormantSsh",
+ "APIKeyScopeWorkspaceDormantStart",
+ "APIKeyScopeWorkspaceDormantStop",
+ "APIKeyScopeWorkspaceDormantUpdate",
+ "APIKeyScopeWorkspaceProxyAll",
+ "APIKeyScopeWorkspaceProxyCreate",
+ "APIKeyScopeWorkspaceProxyDelete",
+ "APIKeyScopeWorkspaceProxyRead",
+ "APIKeyScopeWorkspaceProxyUpdate"
]
},
"codersdk.AddLicenseRequest": {
diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json
index 4b3d4c86aaf34..1a222932de75a 100644
--- a/coderd/apidoc/swagger.json
+++ b/coderd/apidoc/swagger.json
@@ -10246,11 +10246,29 @@
"enum": [
"all",
"application_connect",
+ "aibridge_interception:*",
+ "aibridge_interception:create",
+ "aibridge_interception:read",
+ "aibridge_interception:update",
"api_key:*",
"api_key:create",
"api_key:delete",
"api_key:read",
"api_key:update",
+ "assign_org_role:*",
+ "assign_org_role:assign",
+ "assign_org_role:create",
+ "assign_org_role:delete",
+ "assign_org_role:read",
+ "assign_org_role:unassign",
+ "assign_org_role:update",
+ "assign_role:*",
+ "assign_role:assign",
+ "assign_role:read",
+ "assign_role:unassign",
+ "audit_log:*",
+ "audit_log:create",
+ "audit_log:read",
"coder:all",
"coder:apikeys.manage_self",
"coder:application_connect",
@@ -10260,40 +10278,188 @@
"coder:workspaces.create",
"coder:workspaces.delete",
"coder:workspaces.operate",
+ "connection_log:*",
+ "connection_log:read",
+ "connection_log:update",
+ "crypto_key:*",
+ "crypto_key:create",
+ "crypto_key:delete",
+ "crypto_key:read",
+ "crypto_key:update",
+ "debug_info:*",
+ "debug_info:read",
+ "deployment_config:*",
+ "deployment_config:read",
+ "deployment_config:update",
+ "deployment_stats:*",
+ "deployment_stats:read",
"file:*",
"file:create",
"file:read",
+ "group:*",
+ "group:create",
+ "group:delete",
+ "group:read",
+ "group:update",
+ "group_member:*",
+ "group_member:read",
+ "idpsync_settings:*",
+ "idpsync_settings:read",
+ "idpsync_settings:update",
+ "inbox_notification:*",
+ "inbox_notification:create",
+ "inbox_notification:read",
+ "inbox_notification:update",
+ "license:*",
+ "license:create",
+ "license:delete",
+ "license:read",
+ "notification_message:*",
+ "notification_message:create",
+ "notification_message:delete",
+ "notification_message:read",
+ "notification_message:update",
+ "notification_preference:*",
+ "notification_preference:read",
+ "notification_preference:update",
+ "notification_template:*",
+ "notification_template:read",
+ "notification_template:update",
+ "oauth2_app:*",
+ "oauth2_app:create",
+ "oauth2_app:delete",
+ "oauth2_app:read",
+ "oauth2_app:update",
+ "oauth2_app_code_token:*",
+ "oauth2_app_code_token:create",
+ "oauth2_app_code_token:delete",
+ "oauth2_app_code_token:read",
+ "oauth2_app_secret:*",
+ "oauth2_app_secret:create",
+ "oauth2_app_secret:delete",
+ "oauth2_app_secret:read",
+ "oauth2_app_secret:update",
+ "organization:*",
+ "organization:create",
+ "organization:delete",
+ "organization:read",
+ "organization:update",
+ "organization_member:*",
+ "organization_member:create",
+ "organization_member:delete",
+ "organization_member:read",
+ "organization_member:update",
+ "prebuilt_workspace:*",
+ "prebuilt_workspace:delete",
+ "prebuilt_workspace:update",
+ "provisioner_daemon:*",
+ "provisioner_daemon:create",
+ "provisioner_daemon:delete",
+ "provisioner_daemon:read",
+ "provisioner_daemon:update",
+ "provisioner_jobs:*",
+ "provisioner_jobs:create",
+ "provisioner_jobs:read",
+ "provisioner_jobs:update",
+ "replicas:*",
+ "replicas:read",
+ "system:*",
+ "system:create",
+ "system:delete",
+ "system:read",
+ "system:update",
+ "tailnet_coordinator:*",
+ "tailnet_coordinator:create",
+ "tailnet_coordinator:delete",
+ "tailnet_coordinator:read",
+ "tailnet_coordinator:update",
"template:*",
"template:create",
"template:delete",
"template:read",
"template:update",
"template:use",
+ "template:view_insights",
+ "usage_event:*",
+ "usage_event:create",
+ "usage_event:read",
+ "usage_event:update",
+ "user:*",
+ "user:create",
+ "user:delete",
+ "user:read",
"user:read_personal",
+ "user:update",
"user:update_personal",
"user_secret:*",
"user_secret:create",
"user_secret:delete",
"user_secret:read",
"user_secret:update",
+ "webpush_subscription:*",
+ "webpush_subscription:create",
+ "webpush_subscription:delete",
+ "webpush_subscription:read",
"workspace:*",
"workspace:application_connect",
"workspace:create",
+ "workspace:create_agent",
"workspace:delete",
+ "workspace:delete_agent",
"workspace:read",
"workspace:ssh",
"workspace:start",
"workspace:stop",
- "workspace:update"
+ "workspace:update",
+ "workspace_agent_devcontainers:*",
+ "workspace_agent_devcontainers:create",
+ "workspace_agent_resource_monitor:*",
+ "workspace_agent_resource_monitor:create",
+ "workspace_agent_resource_monitor:read",
+ "workspace_agent_resource_monitor:update",
+ "workspace_dormant:*",
+ "workspace_dormant:application_connect",
+ "workspace_dormant:create",
+ "workspace_dormant:create_agent",
+ "workspace_dormant:delete",
+ "workspace_dormant:delete_agent",
+ "workspace_dormant:read",
+ "workspace_dormant:ssh",
+ "workspace_dormant:start",
+ "workspace_dormant:stop",
+ "workspace_dormant:update",
+ "workspace_proxy:*",
+ "workspace_proxy:create",
+ "workspace_proxy:delete",
+ "workspace_proxy:read",
+ "workspace_proxy:update"
],
"x-enum-varnames": [
"APIKeyScopeAll",
"APIKeyScopeApplicationConnect",
+ "APIKeyScopeAibridgeInterceptionAll",
+ "APIKeyScopeAibridgeInterceptionCreate",
+ "APIKeyScopeAibridgeInterceptionRead",
+ "APIKeyScopeAibridgeInterceptionUpdate",
"APIKeyScopeApiKeyAll",
"APIKeyScopeApiKeyCreate",
"APIKeyScopeApiKeyDelete",
"APIKeyScopeApiKeyRead",
"APIKeyScopeApiKeyUpdate",
+ "APIKeyScopeAssignOrgRoleAll",
+ "APIKeyScopeAssignOrgRoleAssign",
+ "APIKeyScopeAssignOrgRoleCreate",
+ "APIKeyScopeAssignOrgRoleDelete",
+ "APIKeyScopeAssignOrgRoleRead",
+ "APIKeyScopeAssignOrgRoleUnassign",
+ "APIKeyScopeAssignOrgRoleUpdate",
+ "APIKeyScopeAssignRoleAll",
+ "APIKeyScopeAssignRoleAssign",
+ "APIKeyScopeAssignRoleRead",
+ "APIKeyScopeAssignRoleUnassign",
+ "APIKeyScopeAuditLogAll",
+ "APIKeyScopeAuditLogCreate",
+ "APIKeyScopeAuditLogRead",
"APIKeyScopeCoderAll",
"APIKeyScopeCoderApikeysManageSelf",
"APIKeyScopeCoderApplicationConnect",
@@ -10303,31 +10469,161 @@
"APIKeyScopeCoderWorkspacesCreate",
"APIKeyScopeCoderWorkspacesDelete",
"APIKeyScopeCoderWorkspacesOperate",
+ "APIKeyScopeConnectionLogAll",
+ "APIKeyScopeConnectionLogRead",
+ "APIKeyScopeConnectionLogUpdate",
+ "APIKeyScopeCryptoKeyAll",
+ "APIKeyScopeCryptoKeyCreate",
+ "APIKeyScopeCryptoKeyDelete",
+ "APIKeyScopeCryptoKeyRead",
+ "APIKeyScopeCryptoKeyUpdate",
+ "APIKeyScopeDebugInfoAll",
+ "APIKeyScopeDebugInfoRead",
+ "APIKeyScopeDeploymentConfigAll",
+ "APIKeyScopeDeploymentConfigRead",
+ "APIKeyScopeDeploymentConfigUpdate",
+ "APIKeyScopeDeploymentStatsAll",
+ "APIKeyScopeDeploymentStatsRead",
"APIKeyScopeFileAll",
"APIKeyScopeFileCreate",
"APIKeyScopeFileRead",
+ "APIKeyScopeGroupAll",
+ "APIKeyScopeGroupCreate",
+ "APIKeyScopeGroupDelete",
+ "APIKeyScopeGroupRead",
+ "APIKeyScopeGroupUpdate",
+ "APIKeyScopeGroupMemberAll",
+ "APIKeyScopeGroupMemberRead",
+ "APIKeyScopeIdpsyncSettingsAll",
+ "APIKeyScopeIdpsyncSettingsRead",
+ "APIKeyScopeIdpsyncSettingsUpdate",
+ "APIKeyScopeInboxNotificationAll",
+ "APIKeyScopeInboxNotificationCreate",
+ "APIKeyScopeInboxNotificationRead",
+ "APIKeyScopeInboxNotificationUpdate",
+ "APIKeyScopeLicenseAll",
+ "APIKeyScopeLicenseCreate",
+ "APIKeyScopeLicenseDelete",
+ "APIKeyScopeLicenseRead",
+ "APIKeyScopeNotificationMessageAll",
+ "APIKeyScopeNotificationMessageCreate",
+ "APIKeyScopeNotificationMessageDelete",
+ "APIKeyScopeNotificationMessageRead",
+ "APIKeyScopeNotificationMessageUpdate",
+ "APIKeyScopeNotificationPreferenceAll",
+ "APIKeyScopeNotificationPreferenceRead",
+ "APIKeyScopeNotificationPreferenceUpdate",
+ "APIKeyScopeNotificationTemplateAll",
+ "APIKeyScopeNotificationTemplateRead",
+ "APIKeyScopeNotificationTemplateUpdate",
+ "APIKeyScopeOauth2AppAll",
+ "APIKeyScopeOauth2AppCreate",
+ "APIKeyScopeOauth2AppDelete",
+ "APIKeyScopeOauth2AppRead",
+ "APIKeyScopeOauth2AppUpdate",
+ "APIKeyScopeOauth2AppCodeTokenAll",
+ "APIKeyScopeOauth2AppCodeTokenCreate",
+ "APIKeyScopeOauth2AppCodeTokenDelete",
+ "APIKeyScopeOauth2AppCodeTokenRead",
+ "APIKeyScopeOauth2AppSecretAll",
+ "APIKeyScopeOauth2AppSecretCreate",
+ "APIKeyScopeOauth2AppSecretDelete",
+ "APIKeyScopeOauth2AppSecretRead",
+ "APIKeyScopeOauth2AppSecretUpdate",
+ "APIKeyScopeOrganizationAll",
+ "APIKeyScopeOrganizationCreate",
+ "APIKeyScopeOrganizationDelete",
+ "APIKeyScopeOrganizationRead",
+ "APIKeyScopeOrganizationUpdate",
+ "APIKeyScopeOrganizationMemberAll",
+ "APIKeyScopeOrganizationMemberCreate",
+ "APIKeyScopeOrganizationMemberDelete",
+ "APIKeyScopeOrganizationMemberRead",
+ "APIKeyScopeOrganizationMemberUpdate",
+ "APIKeyScopePrebuiltWorkspaceAll",
+ "APIKeyScopePrebuiltWorkspaceDelete",
+ "APIKeyScopePrebuiltWorkspaceUpdate",
+ "APIKeyScopeProvisionerDaemonAll",
+ "APIKeyScopeProvisionerDaemonCreate",
+ "APIKeyScopeProvisionerDaemonDelete",
+ "APIKeyScopeProvisionerDaemonRead",
+ "APIKeyScopeProvisionerDaemonUpdate",
+ "APIKeyScopeProvisionerJobsAll",
+ "APIKeyScopeProvisionerJobsCreate",
+ "APIKeyScopeProvisionerJobsRead",
+ "APIKeyScopeProvisionerJobsUpdate",
+ "APIKeyScopeReplicasAll",
+ "APIKeyScopeReplicasRead",
+ "APIKeyScopeSystemAll",
+ "APIKeyScopeSystemCreate",
+ "APIKeyScopeSystemDelete",
+ "APIKeyScopeSystemRead",
+ "APIKeyScopeSystemUpdate",
+ "APIKeyScopeTailnetCoordinatorAll",
+ "APIKeyScopeTailnetCoordinatorCreate",
+ "APIKeyScopeTailnetCoordinatorDelete",
+ "APIKeyScopeTailnetCoordinatorRead",
+ "APIKeyScopeTailnetCoordinatorUpdate",
"APIKeyScopeTemplateAll",
"APIKeyScopeTemplateCreate",
"APIKeyScopeTemplateDelete",
"APIKeyScopeTemplateRead",
"APIKeyScopeTemplateUpdate",
"APIKeyScopeTemplateUse",
+ "APIKeyScopeTemplateViewInsights",
+ "APIKeyScopeUsageEventAll",
+ "APIKeyScopeUsageEventCreate",
+ "APIKeyScopeUsageEventRead",
+ "APIKeyScopeUsageEventUpdate",
+ "APIKeyScopeUserAll",
+ "APIKeyScopeUserCreate",
+ "APIKeyScopeUserDelete",
+ "APIKeyScopeUserRead",
"APIKeyScopeUserReadPersonal",
+ "APIKeyScopeUserUpdate",
"APIKeyScopeUserUpdatePersonal",
"APIKeyScopeUserSecretAll",
"APIKeyScopeUserSecretCreate",
"APIKeyScopeUserSecretDelete",
"APIKeyScopeUserSecretRead",
"APIKeyScopeUserSecretUpdate",
+ "APIKeyScopeWebpushSubscriptionAll",
+ "APIKeyScopeWebpushSubscriptionCreate",
+ "APIKeyScopeWebpushSubscriptionDelete",
+ "APIKeyScopeWebpushSubscriptionRead",
"APIKeyScopeWorkspaceAll",
"APIKeyScopeWorkspaceApplicationConnect",
"APIKeyScopeWorkspaceCreate",
+ "APIKeyScopeWorkspaceCreateAgent",
"APIKeyScopeWorkspaceDelete",
+ "APIKeyScopeWorkspaceDeleteAgent",
"APIKeyScopeWorkspaceRead",
"APIKeyScopeWorkspaceSsh",
"APIKeyScopeWorkspaceStart",
"APIKeyScopeWorkspaceStop",
- "APIKeyScopeWorkspaceUpdate"
+ "APIKeyScopeWorkspaceUpdate",
+ "APIKeyScopeWorkspaceAgentDevcontainersAll",
+ "APIKeyScopeWorkspaceAgentDevcontainersCreate",
+ "APIKeyScopeWorkspaceAgentResourceMonitorAll",
+ "APIKeyScopeWorkspaceAgentResourceMonitorCreate",
+ "APIKeyScopeWorkspaceAgentResourceMonitorRead",
+ "APIKeyScopeWorkspaceAgentResourceMonitorUpdate",
+ "APIKeyScopeWorkspaceDormantAll",
+ "APIKeyScopeWorkspaceDormantApplicationConnect",
+ "APIKeyScopeWorkspaceDormantCreate",
+ "APIKeyScopeWorkspaceDormantCreateAgent",
+ "APIKeyScopeWorkspaceDormantDelete",
+ "APIKeyScopeWorkspaceDormantDeleteAgent",
+ "APIKeyScopeWorkspaceDormantRead",
+ "APIKeyScopeWorkspaceDormantSsh",
+ "APIKeyScopeWorkspaceDormantStart",
+ "APIKeyScopeWorkspaceDormantStop",
+ "APIKeyScopeWorkspaceDormantUpdate",
+ "APIKeyScopeWorkspaceProxyAll",
+ "APIKeyScopeWorkspaceProxyCreate",
+ "APIKeyScopeWorkspaceProxyDelete",
+ "APIKeyScopeWorkspaceProxyRead",
+ "APIKeyScopeWorkspaceProxyUpdate"
]
},
"codersdk.AddLicenseRequest": {
diff --git a/coderd/database/dump.sql b/coderd/database/dump.sql
index 7a4be98b95045..b2cac7185bfcf 100644
--- a/coderd/database/dump.sql
+++ b/coderd/database/dump.sql
@@ -157,7 +157,47 @@ CREATE TYPE api_key_scope AS ENUM (
'coder:workspaces.access',
'coder:templates.build',
'coder:templates.author',
- 'coder:apikeys.manage_self'
+ 'coder:apikeys.manage_self',
+ 'aibridge_interception:*',
+ 'api_key:*',
+ 'assign_org_role:*',
+ 'assign_role:*',
+ 'audit_log:*',
+ 'connection_log:*',
+ 'crypto_key:*',
+ 'debug_info:*',
+ 'deployment_config:*',
+ 'deployment_stats:*',
+ 'file:*',
+ 'group:*',
+ 'group_member:*',
+ 'idpsync_settings:*',
+ 'inbox_notification:*',
+ 'license:*',
+ 'notification_message:*',
+ 'notification_preference:*',
+ 'notification_template:*',
+ 'oauth2_app:*',
+ 'oauth2_app_code_token:*',
+ 'oauth2_app_secret:*',
+ 'organization:*',
+ 'organization_member:*',
+ 'prebuilt_workspace:*',
+ 'provisioner_daemon:*',
+ 'provisioner_jobs:*',
+ 'replicas:*',
+ 'system:*',
+ 'tailnet_coordinator:*',
+ 'template:*',
+ 'usage_event:*',
+ 'user:*',
+ 'user_secret:*',
+ 'webpush_subscription:*',
+ 'workspace:*',
+ 'workspace_agent_devcontainers:*',
+ 'workspace_agent_resource_monitor:*',
+ 'workspace_dormant:*',
+ 'workspace_proxy:*'
);
CREATE TYPE app_sharing_level AS ENUM (
diff --git a/coderd/database/migrations/000377_add_api_key_scope_wildcards.down.sql b/coderd/database/migrations/000377_add_api_key_scope_wildcards.down.sql
new file mode 100644
index 0000000000000..a414b39a912ee
--- /dev/null
+++ b/coderd/database/migrations/000377_add_api_key_scope_wildcards.down.sql
@@ -0,0 +1,2 @@
+-- No-op: enum values remain to avoid churn. Removing enum values requires
+-- doing a create/cast/drop cycle which is intentionally omitted here.
diff --git a/coderd/database/migrations/000377_add_api_key_scope_wildcards.up.sql b/coderd/database/migrations/000377_add_api_key_scope_wildcards.up.sql
new file mode 100644
index 0000000000000..aed5a18a3e31d
--- /dev/null
+++ b/coderd/database/migrations/000377_add_api_key_scope_wildcards.up.sql
@@ -0,0 +1,42 @@
+-- Add wildcard api_key_scope entries so every RBAC resource has a matching resource:* value.
+-- Generated via: CGO_ENABLED=0 go run ./scripts/generate_api_key_scope_enum
+ALTER TYPE api_key_scope ADD VALUE IF NOT EXISTS 'aibridge_interception:*';
+ALTER TYPE api_key_scope ADD VALUE IF NOT EXISTS 'api_key:*';
+ALTER TYPE api_key_scope ADD VALUE IF NOT EXISTS 'assign_org_role:*';
+ALTER TYPE api_key_scope ADD VALUE IF NOT EXISTS 'assign_role:*';
+ALTER TYPE api_key_scope ADD VALUE IF NOT EXISTS 'audit_log:*';
+ALTER TYPE api_key_scope ADD VALUE IF NOT EXISTS 'connection_log:*';
+ALTER TYPE api_key_scope ADD VALUE IF NOT EXISTS 'crypto_key:*';
+ALTER TYPE api_key_scope ADD VALUE IF NOT EXISTS 'debug_info:*';
+ALTER TYPE api_key_scope ADD VALUE IF NOT EXISTS 'deployment_config:*';
+ALTER TYPE api_key_scope ADD VALUE IF NOT EXISTS 'deployment_stats:*';
+ALTER TYPE api_key_scope ADD VALUE IF NOT EXISTS 'file:*';
+ALTER TYPE api_key_scope ADD VALUE IF NOT EXISTS 'group:*';
+ALTER TYPE api_key_scope ADD VALUE IF NOT EXISTS 'group_member:*';
+ALTER TYPE api_key_scope ADD VALUE IF NOT EXISTS 'idpsync_settings:*';
+ALTER TYPE api_key_scope ADD VALUE IF NOT EXISTS 'inbox_notification:*';
+ALTER TYPE api_key_scope ADD VALUE IF NOT EXISTS 'license:*';
+ALTER TYPE api_key_scope ADD VALUE IF NOT EXISTS 'notification_message:*';
+ALTER TYPE api_key_scope ADD VALUE IF NOT EXISTS 'notification_preference:*';
+ALTER TYPE api_key_scope ADD VALUE IF NOT EXISTS 'notification_template:*';
+ALTER TYPE api_key_scope ADD VALUE IF NOT EXISTS 'oauth2_app:*';
+ALTER TYPE api_key_scope ADD VALUE IF NOT EXISTS 'oauth2_app_code_token:*';
+ALTER TYPE api_key_scope ADD VALUE IF NOT EXISTS 'oauth2_app_secret:*';
+ALTER TYPE api_key_scope ADD VALUE IF NOT EXISTS 'organization:*';
+ALTER TYPE api_key_scope ADD VALUE IF NOT EXISTS 'organization_member:*';
+ALTER TYPE api_key_scope ADD VALUE IF NOT EXISTS 'prebuilt_workspace:*';
+ALTER TYPE api_key_scope ADD VALUE IF NOT EXISTS 'provisioner_daemon:*';
+ALTER TYPE api_key_scope ADD VALUE IF NOT EXISTS 'provisioner_jobs:*';
+ALTER TYPE api_key_scope ADD VALUE IF NOT EXISTS 'replicas:*';
+ALTER TYPE api_key_scope ADD VALUE IF NOT EXISTS 'system:*';
+ALTER TYPE api_key_scope ADD VALUE IF NOT EXISTS 'tailnet_coordinator:*';
+ALTER TYPE api_key_scope ADD VALUE IF NOT EXISTS 'template:*';
+ALTER TYPE api_key_scope ADD VALUE IF NOT EXISTS 'usage_event:*';
+ALTER TYPE api_key_scope ADD VALUE IF NOT EXISTS 'user:*';
+ALTER TYPE api_key_scope ADD VALUE IF NOT EXISTS 'user_secret:*';
+ALTER TYPE api_key_scope ADD VALUE IF NOT EXISTS 'webpush_subscription:*';
+ALTER TYPE api_key_scope ADD VALUE IF NOT EXISTS 'workspace:*';
+ALTER TYPE api_key_scope ADD VALUE IF NOT EXISTS 'workspace_agent_devcontainers:*';
+ALTER TYPE api_key_scope ADD VALUE IF NOT EXISTS 'workspace_agent_resource_monitor:*';
+ALTER TYPE api_key_scope ADD VALUE IF NOT EXISTS 'workspace_dormant:*';
+ALTER TYPE api_key_scope ADD VALUE IF NOT EXISTS 'workspace_proxy:*';
diff --git a/coderd/database/models.go b/coderd/database/models.go
index eecb657edb15d..06c0e98fe4f64 100644
--- a/coderd/database/models.go
+++ b/coderd/database/models.go
@@ -166,6 +166,46 @@ const (
ApiKeyScopeCoderTemplatesbuild APIKeyScope = "coder:templates.build"
ApiKeyScopeCoderTemplatesauthor APIKeyScope = "coder:templates.author"
ApiKeyScopeCoderApikeysmanageSelf APIKeyScope = "coder:apikeys.manage_self"
+ ApiKeyScopeAibridgeInterception APIKeyScope = "aibridge_interception:*"
+ ApiKeyScopeApiKey APIKeyScope = "api_key:*"
+ ApiKeyScopeAssignOrgRole APIKeyScope = "assign_org_role:*"
+ ApiKeyScopeAssignRole APIKeyScope = "assign_role:*"
+ ApiKeyScopeAuditLog APIKeyScope = "audit_log:*"
+ ApiKeyScopeConnectionLog APIKeyScope = "connection_log:*"
+ ApiKeyScopeCryptoKey APIKeyScope = "crypto_key:*"
+ ApiKeyScopeDebugInfo APIKeyScope = "debug_info:*"
+ ApiKeyScopeDeploymentConfig APIKeyScope = "deployment_config:*"
+ ApiKeyScopeDeploymentStats APIKeyScope = "deployment_stats:*"
+ ApiKeyScopeFile APIKeyScope = "file:*"
+ ApiKeyScopeGroup APIKeyScope = "group:*"
+ ApiKeyScopeGroupMember APIKeyScope = "group_member:*"
+ ApiKeyScopeIdpsyncSettings APIKeyScope = "idpsync_settings:*"
+ ApiKeyScopeInboxNotification APIKeyScope = "inbox_notification:*"
+ ApiKeyScopeLicense APIKeyScope = "license:*"
+ ApiKeyScopeNotificationMessage APIKeyScope = "notification_message:*"
+ ApiKeyScopeNotificationPreference APIKeyScope = "notification_preference:*"
+ ApiKeyScopeNotificationTemplate APIKeyScope = "notification_template:*"
+ ApiKeyScopeOauth2App APIKeyScope = "oauth2_app:*"
+ ApiKeyScopeOauth2AppCodeToken APIKeyScope = "oauth2_app_code_token:*"
+ ApiKeyScopeOauth2AppSecret APIKeyScope = "oauth2_app_secret:*"
+ ApiKeyScopeOrganization APIKeyScope = "organization:*"
+ ApiKeyScopeOrganizationMember APIKeyScope = "organization_member:*"
+ ApiKeyScopePrebuiltWorkspace APIKeyScope = "prebuilt_workspace:*"
+ ApiKeyScopeProvisionerDaemon APIKeyScope = "provisioner_daemon:*"
+ ApiKeyScopeProvisionerJobs APIKeyScope = "provisioner_jobs:*"
+ ApiKeyScopeReplicas APIKeyScope = "replicas:*"
+ ApiKeyScopeSystem APIKeyScope = "system:*"
+ ApiKeyScopeTailnetCoordinator APIKeyScope = "tailnet_coordinator:*"
+ ApiKeyScopeTemplate APIKeyScope = "template:*"
+ ApiKeyScopeUsageEvent APIKeyScope = "usage_event:*"
+ ApiKeyScopeUser APIKeyScope = "user:*"
+ ApiKeyScopeUserSecret APIKeyScope = "user_secret:*"
+ ApiKeyScopeWebpushSubscription APIKeyScope = "webpush_subscription:*"
+ ApiKeyScopeWorkspace APIKeyScope = "workspace:*"
+ ApiKeyScopeWorkspaceAgentDevcontainers APIKeyScope = "workspace_agent_devcontainers:*"
+ ApiKeyScopeWorkspaceAgentResourceMonitor APIKeyScope = "workspace_agent_resource_monitor:*"
+ ApiKeyScopeWorkspaceDormant APIKeyScope = "workspace_dormant:*"
+ ApiKeyScopeWorkspaceProxy APIKeyScope = "workspace_proxy:*"
)
func (e *APIKeyScope) Scan(src interface{}) error {
@@ -351,7 +391,47 @@ func (e APIKeyScope) Valid() bool {
ApiKeyScopeCoderWorkspacesaccess,
ApiKeyScopeCoderTemplatesbuild,
ApiKeyScopeCoderTemplatesauthor,
- ApiKeyScopeCoderApikeysmanageSelf:
+ ApiKeyScopeCoderApikeysmanageSelf,
+ ApiKeyScopeAibridgeInterception,
+ ApiKeyScopeApiKey,
+ ApiKeyScopeAssignOrgRole,
+ ApiKeyScopeAssignRole,
+ ApiKeyScopeAuditLog,
+ ApiKeyScopeConnectionLog,
+ ApiKeyScopeCryptoKey,
+ ApiKeyScopeDebugInfo,
+ ApiKeyScopeDeploymentConfig,
+ ApiKeyScopeDeploymentStats,
+ ApiKeyScopeFile,
+ ApiKeyScopeGroup,
+ ApiKeyScopeGroupMember,
+ ApiKeyScopeIdpsyncSettings,
+ ApiKeyScopeInboxNotification,
+ ApiKeyScopeLicense,
+ ApiKeyScopeNotificationMessage,
+ ApiKeyScopeNotificationPreference,
+ ApiKeyScopeNotificationTemplate,
+ ApiKeyScopeOauth2App,
+ ApiKeyScopeOauth2AppCodeToken,
+ ApiKeyScopeOauth2AppSecret,
+ ApiKeyScopeOrganization,
+ ApiKeyScopeOrganizationMember,
+ ApiKeyScopePrebuiltWorkspace,
+ ApiKeyScopeProvisionerDaemon,
+ ApiKeyScopeProvisionerJobs,
+ ApiKeyScopeReplicas,
+ ApiKeyScopeSystem,
+ ApiKeyScopeTailnetCoordinator,
+ ApiKeyScopeTemplate,
+ ApiKeyScopeUsageEvent,
+ ApiKeyScopeUser,
+ ApiKeyScopeUserSecret,
+ ApiKeyScopeWebpushSubscription,
+ ApiKeyScopeWorkspace,
+ ApiKeyScopeWorkspaceAgentDevcontainers,
+ ApiKeyScopeWorkspaceAgentResourceMonitor,
+ ApiKeyScopeWorkspaceDormant,
+ ApiKeyScopeWorkspaceProxy:
return true
}
return false
@@ -506,6 +586,46 @@ func AllAPIKeyScopeValues() []APIKeyScope {
ApiKeyScopeCoderTemplatesbuild,
ApiKeyScopeCoderTemplatesauthor,
ApiKeyScopeCoderApikeysmanageSelf,
+ ApiKeyScopeAibridgeInterception,
+ ApiKeyScopeApiKey,
+ ApiKeyScopeAssignOrgRole,
+ ApiKeyScopeAssignRole,
+ ApiKeyScopeAuditLog,
+ ApiKeyScopeConnectionLog,
+ ApiKeyScopeCryptoKey,
+ ApiKeyScopeDebugInfo,
+ ApiKeyScopeDeploymentConfig,
+ ApiKeyScopeDeploymentStats,
+ ApiKeyScopeFile,
+ ApiKeyScopeGroup,
+ ApiKeyScopeGroupMember,
+ ApiKeyScopeIdpsyncSettings,
+ ApiKeyScopeInboxNotification,
+ ApiKeyScopeLicense,
+ ApiKeyScopeNotificationMessage,
+ ApiKeyScopeNotificationPreference,
+ ApiKeyScopeNotificationTemplate,
+ ApiKeyScopeOauth2App,
+ ApiKeyScopeOauth2AppCodeToken,
+ ApiKeyScopeOauth2AppSecret,
+ ApiKeyScopeOrganization,
+ ApiKeyScopeOrganizationMember,
+ ApiKeyScopePrebuiltWorkspace,
+ ApiKeyScopeProvisionerDaemon,
+ ApiKeyScopeProvisionerJobs,
+ ApiKeyScopeReplicas,
+ ApiKeyScopeSystem,
+ ApiKeyScopeTailnetCoordinator,
+ ApiKeyScopeTemplate,
+ ApiKeyScopeUsageEvent,
+ ApiKeyScopeUser,
+ ApiKeyScopeUserSecret,
+ ApiKeyScopeWebpushSubscription,
+ ApiKeyScopeWorkspace,
+ ApiKeyScopeWorkspaceAgentDevcontainers,
+ ApiKeyScopeWorkspaceAgentResourceMonitor,
+ ApiKeyScopeWorkspaceDormant,
+ ApiKeyScopeWorkspaceProxy,
}
}
diff --git a/codersdk/apikey_scopes_gen.go b/codersdk/apikey_scopes_gen.go
index a399a014b42d5..606a704ae4bdc 100644
--- a/codersdk/apikey_scopes_gen.go
+++ b/codersdk/apikey_scopes_gen.go
@@ -5,46 +5,194 @@ const (
// Deprecated: use codersdk.APIKeyScopeCoderAll instead.
APIKeyScopeAll APIKeyScope = "all"
// Deprecated: use codersdk.APIKeyScopeCoderApplicationConnect instead.
- APIKeyScopeApplicationConnect APIKeyScope = "application_connect"
- APIKeyScopeApiKeyAll APIKeyScope = "api_key:*"
- APIKeyScopeApiKeyCreate APIKeyScope = "api_key:create"
- APIKeyScopeApiKeyDelete APIKeyScope = "api_key:delete"
- APIKeyScopeApiKeyRead APIKeyScope = "api_key:read"
- APIKeyScopeApiKeyUpdate APIKeyScope = "api_key:update"
- APIKeyScopeCoderAll APIKeyScope = "coder:all"
- APIKeyScopeCoderApikeysManageSelf APIKeyScope = "coder:apikeys.manage_self"
- APIKeyScopeCoderApplicationConnect APIKeyScope = "coder:application_connect"
- APIKeyScopeCoderTemplatesAuthor APIKeyScope = "coder:templates.author"
- APIKeyScopeCoderTemplatesBuild APIKeyScope = "coder:templates.build"
- APIKeyScopeCoderWorkspacesAccess APIKeyScope = "coder:workspaces.access"
- APIKeyScopeCoderWorkspacesCreate APIKeyScope = "coder:workspaces.create"
- APIKeyScopeCoderWorkspacesDelete APIKeyScope = "coder:workspaces.delete"
- APIKeyScopeCoderWorkspacesOperate APIKeyScope = "coder:workspaces.operate"
- APIKeyScopeFileAll APIKeyScope = "file:*"
- APIKeyScopeFileCreate APIKeyScope = "file:create"
- APIKeyScopeFileRead APIKeyScope = "file:read"
- APIKeyScopeTemplateAll APIKeyScope = "template:*"
- APIKeyScopeTemplateCreate APIKeyScope = "template:create"
- APIKeyScopeTemplateDelete APIKeyScope = "template:delete"
- APIKeyScopeTemplateRead APIKeyScope = "template:read"
- APIKeyScopeTemplateUpdate APIKeyScope = "template:update"
- APIKeyScopeTemplateUse APIKeyScope = "template:use"
- APIKeyScopeUserReadPersonal APIKeyScope = "user:read_personal"
- APIKeyScopeUserUpdatePersonal APIKeyScope = "user:update_personal"
- APIKeyScopeUserSecretAll APIKeyScope = "user_secret:*"
- APIKeyScopeUserSecretCreate APIKeyScope = "user_secret:create"
- APIKeyScopeUserSecretDelete APIKeyScope = "user_secret:delete"
- APIKeyScopeUserSecretRead APIKeyScope = "user_secret:read"
- APIKeyScopeUserSecretUpdate APIKeyScope = "user_secret:update"
- APIKeyScopeWorkspaceAll APIKeyScope = "workspace:*"
- APIKeyScopeWorkspaceApplicationConnect APIKeyScope = "workspace:application_connect"
- APIKeyScopeWorkspaceCreate APIKeyScope = "workspace:create"
- APIKeyScopeWorkspaceDelete APIKeyScope = "workspace:delete"
- APIKeyScopeWorkspaceRead APIKeyScope = "workspace:read"
- APIKeyScopeWorkspaceSsh APIKeyScope = "workspace:ssh"
- APIKeyScopeWorkspaceStart APIKeyScope = "workspace:start"
- APIKeyScopeWorkspaceStop APIKeyScope = "workspace:stop"
- APIKeyScopeWorkspaceUpdate APIKeyScope = "workspace:update"
+ APIKeyScopeApplicationConnect APIKeyScope = "application_connect"
+ APIKeyScopeAibridgeInterceptionAll APIKeyScope = "aibridge_interception:*"
+ APIKeyScopeAibridgeInterceptionCreate APIKeyScope = "aibridge_interception:create"
+ APIKeyScopeAibridgeInterceptionRead APIKeyScope = "aibridge_interception:read"
+ APIKeyScopeAibridgeInterceptionUpdate APIKeyScope = "aibridge_interception:update"
+ APIKeyScopeApiKeyAll APIKeyScope = "api_key:*"
+ APIKeyScopeApiKeyCreate APIKeyScope = "api_key:create"
+ APIKeyScopeApiKeyDelete APIKeyScope = "api_key:delete"
+ APIKeyScopeApiKeyRead APIKeyScope = "api_key:read"
+ APIKeyScopeApiKeyUpdate APIKeyScope = "api_key:update"
+ APIKeyScopeAssignOrgRoleAll APIKeyScope = "assign_org_role:*"
+ APIKeyScopeAssignOrgRoleAssign APIKeyScope = "assign_org_role:assign"
+ APIKeyScopeAssignOrgRoleCreate APIKeyScope = "assign_org_role:create"
+ APIKeyScopeAssignOrgRoleDelete APIKeyScope = "assign_org_role:delete"
+ APIKeyScopeAssignOrgRoleRead APIKeyScope = "assign_org_role:read"
+ APIKeyScopeAssignOrgRoleUnassign APIKeyScope = "assign_org_role:unassign"
+ APIKeyScopeAssignOrgRoleUpdate APIKeyScope = "assign_org_role:update"
+ APIKeyScopeAssignRoleAll APIKeyScope = "assign_role:*"
+ APIKeyScopeAssignRoleAssign APIKeyScope = "assign_role:assign"
+ APIKeyScopeAssignRoleRead APIKeyScope = "assign_role:read"
+ APIKeyScopeAssignRoleUnassign APIKeyScope = "assign_role:unassign"
+ APIKeyScopeAuditLogAll APIKeyScope = "audit_log:*"
+ APIKeyScopeAuditLogCreate APIKeyScope = "audit_log:create"
+ APIKeyScopeAuditLogRead APIKeyScope = "audit_log:read"
+ APIKeyScopeCoderAll APIKeyScope = "coder:all"
+ APIKeyScopeCoderApikeysManageSelf APIKeyScope = "coder:apikeys.manage_self"
+ APIKeyScopeCoderApplicationConnect APIKeyScope = "coder:application_connect"
+ APIKeyScopeCoderTemplatesAuthor APIKeyScope = "coder:templates.author"
+ APIKeyScopeCoderTemplatesBuild APIKeyScope = "coder:templates.build"
+ APIKeyScopeCoderWorkspacesAccess APIKeyScope = "coder:workspaces.access"
+ APIKeyScopeCoderWorkspacesCreate APIKeyScope = "coder:workspaces.create"
+ APIKeyScopeCoderWorkspacesDelete APIKeyScope = "coder:workspaces.delete"
+ APIKeyScopeCoderWorkspacesOperate APIKeyScope = "coder:workspaces.operate"
+ APIKeyScopeConnectionLogAll APIKeyScope = "connection_log:*"
+ APIKeyScopeConnectionLogRead APIKeyScope = "connection_log:read"
+ APIKeyScopeConnectionLogUpdate APIKeyScope = "connection_log:update"
+ APIKeyScopeCryptoKeyAll APIKeyScope = "crypto_key:*"
+ APIKeyScopeCryptoKeyCreate APIKeyScope = "crypto_key:create"
+ APIKeyScopeCryptoKeyDelete APIKeyScope = "crypto_key:delete"
+ APIKeyScopeCryptoKeyRead APIKeyScope = "crypto_key:read"
+ APIKeyScopeCryptoKeyUpdate APIKeyScope = "crypto_key:update"
+ APIKeyScopeDebugInfoAll APIKeyScope = "debug_info:*"
+ APIKeyScopeDebugInfoRead APIKeyScope = "debug_info:read"
+ APIKeyScopeDeploymentConfigAll APIKeyScope = "deployment_config:*"
+ APIKeyScopeDeploymentConfigRead APIKeyScope = "deployment_config:read"
+ APIKeyScopeDeploymentConfigUpdate APIKeyScope = "deployment_config:update"
+ APIKeyScopeDeploymentStatsAll APIKeyScope = "deployment_stats:*"
+ APIKeyScopeDeploymentStatsRead APIKeyScope = "deployment_stats:read"
+ APIKeyScopeFileAll APIKeyScope = "file:*"
+ APIKeyScopeFileCreate APIKeyScope = "file:create"
+ APIKeyScopeFileRead APIKeyScope = "file:read"
+ APIKeyScopeGroupAll APIKeyScope = "group:*"
+ APIKeyScopeGroupCreate APIKeyScope = "group:create"
+ APIKeyScopeGroupDelete APIKeyScope = "group:delete"
+ APIKeyScopeGroupRead APIKeyScope = "group:read"
+ APIKeyScopeGroupUpdate APIKeyScope = "group:update"
+ APIKeyScopeGroupMemberAll APIKeyScope = "group_member:*"
+ APIKeyScopeGroupMemberRead APIKeyScope = "group_member:read"
+ APIKeyScopeIdpsyncSettingsAll APIKeyScope = "idpsync_settings:*"
+ APIKeyScopeIdpsyncSettingsRead APIKeyScope = "idpsync_settings:read"
+ APIKeyScopeIdpsyncSettingsUpdate APIKeyScope = "idpsync_settings:update"
+ APIKeyScopeInboxNotificationAll APIKeyScope = "inbox_notification:*"
+ APIKeyScopeInboxNotificationCreate APIKeyScope = "inbox_notification:create"
+ APIKeyScopeInboxNotificationRead APIKeyScope = "inbox_notification:read"
+ APIKeyScopeInboxNotificationUpdate APIKeyScope = "inbox_notification:update"
+ APIKeyScopeLicenseAll APIKeyScope = "license:*"
+ APIKeyScopeLicenseCreate APIKeyScope = "license:create"
+ APIKeyScopeLicenseDelete APIKeyScope = "license:delete"
+ APIKeyScopeLicenseRead APIKeyScope = "license:read"
+ APIKeyScopeNotificationMessageAll APIKeyScope = "notification_message:*"
+ APIKeyScopeNotificationMessageCreate APIKeyScope = "notification_message:create"
+ APIKeyScopeNotificationMessageDelete APIKeyScope = "notification_message:delete"
+ APIKeyScopeNotificationMessageRead APIKeyScope = "notification_message:read"
+ APIKeyScopeNotificationMessageUpdate APIKeyScope = "notification_message:update"
+ APIKeyScopeNotificationPreferenceAll APIKeyScope = "notification_preference:*"
+ APIKeyScopeNotificationPreferenceRead APIKeyScope = "notification_preference:read"
+ APIKeyScopeNotificationPreferenceUpdate APIKeyScope = "notification_preference:update"
+ APIKeyScopeNotificationTemplateAll APIKeyScope = "notification_template:*"
+ APIKeyScopeNotificationTemplateRead APIKeyScope = "notification_template:read"
+ APIKeyScopeNotificationTemplateUpdate APIKeyScope = "notification_template:update"
+ APIKeyScopeOauth2AppAll APIKeyScope = "oauth2_app:*"
+ APIKeyScopeOauth2AppCreate APIKeyScope = "oauth2_app:create"
+ APIKeyScopeOauth2AppDelete APIKeyScope = "oauth2_app:delete"
+ APIKeyScopeOauth2AppRead APIKeyScope = "oauth2_app:read"
+ APIKeyScopeOauth2AppUpdate APIKeyScope = "oauth2_app:update"
+ APIKeyScopeOauth2AppCodeTokenAll APIKeyScope = "oauth2_app_code_token:*"
+ APIKeyScopeOauth2AppCodeTokenCreate APIKeyScope = "oauth2_app_code_token:create"
+ APIKeyScopeOauth2AppCodeTokenDelete APIKeyScope = "oauth2_app_code_token:delete"
+ APIKeyScopeOauth2AppCodeTokenRead APIKeyScope = "oauth2_app_code_token:read"
+ APIKeyScopeOauth2AppSecretAll APIKeyScope = "oauth2_app_secret:*"
+ APIKeyScopeOauth2AppSecretCreate APIKeyScope = "oauth2_app_secret:create"
+ APIKeyScopeOauth2AppSecretDelete APIKeyScope = "oauth2_app_secret:delete"
+ APIKeyScopeOauth2AppSecretRead APIKeyScope = "oauth2_app_secret:read"
+ APIKeyScopeOauth2AppSecretUpdate APIKeyScope = "oauth2_app_secret:update"
+ APIKeyScopeOrganizationAll APIKeyScope = "organization:*"
+ APIKeyScopeOrganizationCreate APIKeyScope = "organization:create"
+ APIKeyScopeOrganizationDelete APIKeyScope = "organization:delete"
+ APIKeyScopeOrganizationRead APIKeyScope = "organization:read"
+ APIKeyScopeOrganizationUpdate APIKeyScope = "organization:update"
+ APIKeyScopeOrganizationMemberAll APIKeyScope = "organization_member:*"
+ APIKeyScopeOrganizationMemberCreate APIKeyScope = "organization_member:create"
+ APIKeyScopeOrganizationMemberDelete APIKeyScope = "organization_member:delete"
+ APIKeyScopeOrganizationMemberRead APIKeyScope = "organization_member:read"
+ APIKeyScopeOrganizationMemberUpdate APIKeyScope = "organization_member:update"
+ APIKeyScopePrebuiltWorkspaceAll APIKeyScope = "prebuilt_workspace:*"
+ APIKeyScopePrebuiltWorkspaceDelete APIKeyScope = "prebuilt_workspace:delete"
+ APIKeyScopePrebuiltWorkspaceUpdate APIKeyScope = "prebuilt_workspace:update"
+ APIKeyScopeProvisionerDaemonAll APIKeyScope = "provisioner_daemon:*"
+ APIKeyScopeProvisionerDaemonCreate APIKeyScope = "provisioner_daemon:create"
+ APIKeyScopeProvisionerDaemonDelete APIKeyScope = "provisioner_daemon:delete"
+ APIKeyScopeProvisionerDaemonRead APIKeyScope = "provisioner_daemon:read"
+ APIKeyScopeProvisionerDaemonUpdate APIKeyScope = "provisioner_daemon:update"
+ APIKeyScopeProvisionerJobsAll APIKeyScope = "provisioner_jobs:*"
+ APIKeyScopeProvisionerJobsCreate APIKeyScope = "provisioner_jobs:create"
+ APIKeyScopeProvisionerJobsRead APIKeyScope = "provisioner_jobs:read"
+ APIKeyScopeProvisionerJobsUpdate APIKeyScope = "provisioner_jobs:update"
+ APIKeyScopeReplicasAll APIKeyScope = "replicas:*"
+ APIKeyScopeReplicasRead APIKeyScope = "replicas:read"
+ APIKeyScopeSystemAll APIKeyScope = "system:*"
+ APIKeyScopeSystemCreate APIKeyScope = "system:create"
+ APIKeyScopeSystemDelete APIKeyScope = "system:delete"
+ APIKeyScopeSystemRead APIKeyScope = "system:read"
+ APIKeyScopeSystemUpdate APIKeyScope = "system:update"
+ APIKeyScopeTailnetCoordinatorAll APIKeyScope = "tailnet_coordinator:*"
+ APIKeyScopeTailnetCoordinatorCreate APIKeyScope = "tailnet_coordinator:create"
+ APIKeyScopeTailnetCoordinatorDelete APIKeyScope = "tailnet_coordinator:delete"
+ APIKeyScopeTailnetCoordinatorRead APIKeyScope = "tailnet_coordinator:read"
+ APIKeyScopeTailnetCoordinatorUpdate APIKeyScope = "tailnet_coordinator:update"
+ APIKeyScopeTemplateAll APIKeyScope = "template:*"
+ APIKeyScopeTemplateCreate APIKeyScope = "template:create"
+ APIKeyScopeTemplateDelete APIKeyScope = "template:delete"
+ APIKeyScopeTemplateRead APIKeyScope = "template:read"
+ APIKeyScopeTemplateUpdate APIKeyScope = "template:update"
+ APIKeyScopeTemplateUse APIKeyScope = "template:use"
+ APIKeyScopeTemplateViewInsights APIKeyScope = "template:view_insights"
+ APIKeyScopeUsageEventAll APIKeyScope = "usage_event:*"
+ APIKeyScopeUsageEventCreate APIKeyScope = "usage_event:create"
+ APIKeyScopeUsageEventRead APIKeyScope = "usage_event:read"
+ APIKeyScopeUsageEventUpdate APIKeyScope = "usage_event:update"
+ APIKeyScopeUserAll APIKeyScope = "user:*"
+ APIKeyScopeUserCreate APIKeyScope = "user:create"
+ APIKeyScopeUserDelete APIKeyScope = "user:delete"
+ APIKeyScopeUserRead APIKeyScope = "user:read"
+ APIKeyScopeUserReadPersonal APIKeyScope = "user:read_personal"
+ APIKeyScopeUserUpdate APIKeyScope = "user:update"
+ APIKeyScopeUserUpdatePersonal APIKeyScope = "user:update_personal"
+ APIKeyScopeUserSecretAll APIKeyScope = "user_secret:*"
+ APIKeyScopeUserSecretCreate APIKeyScope = "user_secret:create"
+ APIKeyScopeUserSecretDelete APIKeyScope = "user_secret:delete"
+ APIKeyScopeUserSecretRead APIKeyScope = "user_secret:read"
+ APIKeyScopeUserSecretUpdate APIKeyScope = "user_secret:update"
+ APIKeyScopeWebpushSubscriptionAll APIKeyScope = "webpush_subscription:*"
+ APIKeyScopeWebpushSubscriptionCreate APIKeyScope = "webpush_subscription:create"
+ APIKeyScopeWebpushSubscriptionDelete APIKeyScope = "webpush_subscription:delete"
+ APIKeyScopeWebpushSubscriptionRead APIKeyScope = "webpush_subscription:read"
+ APIKeyScopeWorkspaceAll APIKeyScope = "workspace:*"
+ APIKeyScopeWorkspaceApplicationConnect APIKeyScope = "workspace:application_connect"
+ APIKeyScopeWorkspaceCreate APIKeyScope = "workspace:create"
+ APIKeyScopeWorkspaceCreateAgent APIKeyScope = "workspace:create_agent"
+ APIKeyScopeWorkspaceDelete APIKeyScope = "workspace:delete"
+ APIKeyScopeWorkspaceDeleteAgent APIKeyScope = "workspace:delete_agent"
+ APIKeyScopeWorkspaceRead APIKeyScope = "workspace:read"
+ APIKeyScopeWorkspaceSsh APIKeyScope = "workspace:ssh"
+ APIKeyScopeWorkspaceStart APIKeyScope = "workspace:start"
+ APIKeyScopeWorkspaceStop APIKeyScope = "workspace:stop"
+ APIKeyScopeWorkspaceUpdate APIKeyScope = "workspace:update"
+ APIKeyScopeWorkspaceAgentDevcontainersAll APIKeyScope = "workspace_agent_devcontainers:*"
+ APIKeyScopeWorkspaceAgentDevcontainersCreate APIKeyScope = "workspace_agent_devcontainers:create"
+ APIKeyScopeWorkspaceAgentResourceMonitorAll APIKeyScope = "workspace_agent_resource_monitor:*"
+ APIKeyScopeWorkspaceAgentResourceMonitorCreate APIKeyScope = "workspace_agent_resource_monitor:create"
+ APIKeyScopeWorkspaceAgentResourceMonitorRead APIKeyScope = "workspace_agent_resource_monitor:read"
+ APIKeyScopeWorkspaceAgentResourceMonitorUpdate APIKeyScope = "workspace_agent_resource_monitor:update"
+ APIKeyScopeWorkspaceDormantAll APIKeyScope = "workspace_dormant:*"
+ APIKeyScopeWorkspaceDormantApplicationConnect APIKeyScope = "workspace_dormant:application_connect"
+ APIKeyScopeWorkspaceDormantCreate APIKeyScope = "workspace_dormant:create"
+ APIKeyScopeWorkspaceDormantCreateAgent APIKeyScope = "workspace_dormant:create_agent"
+ APIKeyScopeWorkspaceDormantDelete APIKeyScope = "workspace_dormant:delete"
+ APIKeyScopeWorkspaceDormantDeleteAgent APIKeyScope = "workspace_dormant:delete_agent"
+ APIKeyScopeWorkspaceDormantRead APIKeyScope = "workspace_dormant:read"
+ APIKeyScopeWorkspaceDormantSsh APIKeyScope = "workspace_dormant:ssh"
+ APIKeyScopeWorkspaceDormantStart APIKeyScope = "workspace_dormant:start"
+ APIKeyScopeWorkspaceDormantStop APIKeyScope = "workspace_dormant:stop"
+ APIKeyScopeWorkspaceDormantUpdate APIKeyScope = "workspace_dormant:update"
+ APIKeyScopeWorkspaceProxyAll APIKeyScope = "workspace_proxy:*"
+ APIKeyScopeWorkspaceProxyCreate APIKeyScope = "workspace_proxy:create"
+ APIKeyScopeWorkspaceProxyDelete APIKeyScope = "workspace_proxy:delete"
+ APIKeyScopeWorkspaceProxyRead APIKeyScope = "workspace_proxy:read"
+ APIKeyScopeWorkspaceProxyUpdate APIKeyScope = "workspace_proxy:update"
)
// PublicAPIKeyScopes lists all public low-level API key scopes.
diff --git a/docs/reference/api/schemas.md b/docs/reference/api/schemas.md
index 33cb280ae15c0..c121096b094d6 100644
--- a/docs/reference/api/schemas.md
+++ b/docs/reference/api/schemas.md
@@ -711,49 +711,197 @@
#### Enumerated Values
-| Value |
-|---------------------------------|
-| `all` |
-| `application_connect` |
-| `api_key:*` |
-| `api_key:create` |
-| `api_key:delete` |
-| `api_key:read` |
-| `api_key:update` |
-| `coder:all` |
-| `coder:apikeys.manage_self` |
-| `coder:application_connect` |
-| `coder:templates.author` |
-| `coder:templates.build` |
-| `coder:workspaces.access` |
-| `coder:workspaces.create` |
-| `coder:workspaces.delete` |
-| `coder:workspaces.operate` |
-| `file:*` |
-| `file:create` |
-| `file:read` |
-| `template:*` |
-| `template:create` |
-| `template:delete` |
-| `template:read` |
-| `template:update` |
-| `template:use` |
-| `user:read_personal` |
-| `user:update_personal` |
-| `user_secret:*` |
-| `user_secret:create` |
-| `user_secret:delete` |
-| `user_secret:read` |
-| `user_secret:update` |
-| `workspace:*` |
-| `workspace:application_connect` |
-| `workspace:create` |
-| `workspace:delete` |
-| `workspace:read` |
-| `workspace:ssh` |
-| `workspace:start` |
-| `workspace:stop` |
-| `workspace:update` |
+| Value |
+|-------------------------------------------|
+| `all` |
+| `application_connect` |
+| `aibridge_interception:*` |
+| `aibridge_interception:create` |
+| `aibridge_interception:read` |
+| `aibridge_interception:update` |
+| `api_key:*` |
+| `api_key:create` |
+| `api_key:delete` |
+| `api_key:read` |
+| `api_key:update` |
+| `assign_org_role:*` |
+| `assign_org_role:assign` |
+| `assign_org_role:create` |
+| `assign_org_role:delete` |
+| `assign_org_role:read` |
+| `assign_org_role:unassign` |
+| `assign_org_role:update` |
+| `assign_role:*` |
+| `assign_role:assign` |
+| `assign_role:read` |
+| `assign_role:unassign` |
+| `audit_log:*` |
+| `audit_log:create` |
+| `audit_log:read` |
+| `coder:all` |
+| `coder:apikeys.manage_self` |
+| `coder:application_connect` |
+| `coder:templates.author` |
+| `coder:templates.build` |
+| `coder:workspaces.access` |
+| `coder:workspaces.create` |
+| `coder:workspaces.delete` |
+| `coder:workspaces.operate` |
+| `connection_log:*` |
+| `connection_log:read` |
+| `connection_log:update` |
+| `crypto_key:*` |
+| `crypto_key:create` |
+| `crypto_key:delete` |
+| `crypto_key:read` |
+| `crypto_key:update` |
+| `debug_info:*` |
+| `debug_info:read` |
+| `deployment_config:*` |
+| `deployment_config:read` |
+| `deployment_config:update` |
+| `deployment_stats:*` |
+| `deployment_stats:read` |
+| `file:*` |
+| `file:create` |
+| `file:read` |
+| `group:*` |
+| `group:create` |
+| `group:delete` |
+| `group:read` |
+| `group:update` |
+| `group_member:*` |
+| `group_member:read` |
+| `idpsync_settings:*` |
+| `idpsync_settings:read` |
+| `idpsync_settings:update` |
+| `inbox_notification:*` |
+| `inbox_notification:create` |
+| `inbox_notification:read` |
+| `inbox_notification:update` |
+| `license:*` |
+| `license:create` |
+| `license:delete` |
+| `license:read` |
+| `notification_message:*` |
+| `notification_message:create` |
+| `notification_message:delete` |
+| `notification_message:read` |
+| `notification_message:update` |
+| `notification_preference:*` |
+| `notification_preference:read` |
+| `notification_preference:update` |
+| `notification_template:*` |
+| `notification_template:read` |
+| `notification_template:update` |
+| `oauth2_app:*` |
+| `oauth2_app:create` |
+| `oauth2_app:delete` |
+| `oauth2_app:read` |
+| `oauth2_app:update` |
+| `oauth2_app_code_token:*` |
+| `oauth2_app_code_token:create` |
+| `oauth2_app_code_token:delete` |
+| `oauth2_app_code_token:read` |
+| `oauth2_app_secret:*` |
+| `oauth2_app_secret:create` |
+| `oauth2_app_secret:delete` |
+| `oauth2_app_secret:read` |
+| `oauth2_app_secret:update` |
+| `organization:*` |
+| `organization:create` |
+| `organization:delete` |
+| `organization:read` |
+| `organization:update` |
+| `organization_member:*` |
+| `organization_member:create` |
+| `organization_member:delete` |
+| `organization_member:read` |
+| `organization_member:update` |
+| `prebuilt_workspace:*` |
+| `prebuilt_workspace:delete` |
+| `prebuilt_workspace:update` |
+| `provisioner_daemon:*` |
+| `provisioner_daemon:create` |
+| `provisioner_daemon:delete` |
+| `provisioner_daemon:read` |
+| `provisioner_daemon:update` |
+| `provisioner_jobs:*` |
+| `provisioner_jobs:create` |
+| `provisioner_jobs:read` |
+| `provisioner_jobs:update` |
+| `replicas:*` |
+| `replicas:read` |
+| `system:*` |
+| `system:create` |
+| `system:delete` |
+| `system:read` |
+| `system:update` |
+| `tailnet_coordinator:*` |
+| `tailnet_coordinator:create` |
+| `tailnet_coordinator:delete` |
+| `tailnet_coordinator:read` |
+| `tailnet_coordinator:update` |
+| `template:*` |
+| `template:create` |
+| `template:delete` |
+| `template:read` |
+| `template:update` |
+| `template:use` |
+| `template:view_insights` |
+| `usage_event:*` |
+| `usage_event:create` |
+| `usage_event:read` |
+| `usage_event:update` |
+| `user:*` |
+| `user:create` |
+| `user:delete` |
+| `user:read` |
+| `user:read_personal` |
+| `user:update` |
+| `user:update_personal` |
+| `user_secret:*` |
+| `user_secret:create` |
+| `user_secret:delete` |
+| `user_secret:read` |
+| `user_secret:update` |
+| `webpush_subscription:*` |
+| `webpush_subscription:create` |
+| `webpush_subscription:delete` |
+| `webpush_subscription:read` |
+| `workspace:*` |
+| `workspace:application_connect` |
+| `workspace:create` |
+| `workspace:create_agent` |
+| `workspace:delete` |
+| `workspace:delete_agent` |
+| `workspace:read` |
+| `workspace:ssh` |
+| `workspace:start` |
+| `workspace:stop` |
+| `workspace:update` |
+| `workspace_agent_devcontainers:*` |
+| `workspace_agent_devcontainers:create` |
+| `workspace_agent_resource_monitor:*` |
+| `workspace_agent_resource_monitor:create` |
+| `workspace_agent_resource_monitor:read` |
+| `workspace_agent_resource_monitor:update` |
+| `workspace_dormant:*` |
+| `workspace_dormant:application_connect` |
+| `workspace_dormant:create` |
+| `workspace_dormant:create_agent` |
+| `workspace_dormant:delete` |
+| `workspace_dormant:delete_agent` |
+| `workspace_dormant:read` |
+| `workspace_dormant:ssh` |
+| `workspace_dormant:start` |
+| `workspace_dormant:stop` |
+| `workspace_dormant:update` |
+| `workspace_proxy:*` |
+| `workspace_proxy:create` |
+| `workspace_proxy:delete` |
+| `workspace_proxy:read` |
+| `workspace_proxy:update` |
## codersdk.AddLicenseRequest
diff --git a/scripts/apikeyscopesgen/main.go b/scripts/apikeyscopesgen/main.go
index 988c4cb2f0e10..b2c74c72c0adf 100644
--- a/scripts/apikeyscopesgen/main.go
+++ b/scripts/apikeyscopesgen/main.go
@@ -25,8 +25,8 @@ func main() {
}
func generate() ([]byte, error) {
- names := rbac.ExternalScopeNames()
- slices.Sort(names)
+ allNames := collectAllScopeNames()
+ publicNames := rbac.ExternalScopeNames()
var b bytes.Buffer
if _, err := b.WriteString("// Code generated by scripts/apikeyscopesgen. DO NOT EDIT.\n"); err != nil {
@@ -61,13 +61,9 @@ func generate() ([]byte, error) {
if _, err := b.WriteString("\tAPIKeyScopeApplicationConnect APIKeyScope = \"application_connect\"\n"); err != nil {
return nil, err
}
- for _, n := range names {
- res, act := splitRA(n)
- if act == policy.WildcardSymbol {
- act = "All"
- }
- constName := fmt.Sprintf("APIKeyScope%s%s", pascal(res), pascal(act))
- if _, err := fmt.Fprintf(&b, "\t%s APIKeyScope = \"%s\"\n", constName, n); err != nil {
+ for _, name := range allNames {
+ constName := constNameForScope(name)
+ if _, err := fmt.Fprintf(&b, "\t%s APIKeyScope = \"%s\"\n", constName, name); err != nil {
return nil, err
}
}
@@ -82,12 +78,8 @@ func generate() ([]byte, error) {
if _, err := b.WriteString("var PublicAPIKeyScopes = []APIKeyScope{\n"); err != nil {
return nil, err
}
- for _, n := range names {
- res, act := splitRA(n)
- if act == policy.WildcardSymbol {
- act = "All"
- }
- constName := fmt.Sprintf("APIKeyScope%s%s", pascal(res), pascal(act))
+ for _, name := range publicNames {
+ constName := constNameForScope(name)
if _, err := fmt.Fprintf(&b, "\t%s,\n", constName); err != nil {
return nil, err
}
@@ -99,6 +91,54 @@ func generate() ([]byte, error) {
return format.Source(b.Bytes())
}
+func collectAllScopeNames() []string {
+ seen := make(map[string]struct{})
+ var names []string
+ add := func(name string) {
+ if name == "" {
+ return
+ }
+ if _, ok := seen[name]; ok {
+ return
+ }
+ seen[name] = struct{}{}
+ names = append(names, name)
+ }
+
+ for resource, def := range policy.RBACPermissions {
+ if resource == policy.WildcardSymbol {
+ continue
+ }
+ add(resource + ":" + policy.WildcardSymbol)
+ for action := range def.Actions {
+ add(resource + ":" + string(action))
+ }
+ }
+
+ for _, name := range rbac.CompositeScopeNames() {
+ add(name)
+ }
+
+ for _, name := range rbac.BuiltinScopeNames() {
+ s := string(name)
+ if !strings.Contains(s, ":") {
+ continue
+ }
+ add(s)
+ }
+
+ slices.Sort(names)
+ return names
+}
+
+func constNameForScope(name string) string {
+ resource, action := splitRA(name)
+ if action == policy.WildcardSymbol {
+ action = "All"
+ }
+ return fmt.Sprintf("APIKeyScope%s%s", pascal(resource), pascal(action))
+}
+
func splitRA(name string) (resource string, action string) {
parts := strings.SplitN(name, ":", 2)
if len(parts) != 2 {
diff --git a/scripts/check-scopes/main.go b/scripts/check-scopes/main.go
index e79be506ae804..56ba0d4657e31 100644
--- a/scripts/check-scopes/main.go
+++ b/scripts/check-scopes/main.go
@@ -58,23 +58,37 @@ func main() {
os.Exit(1)
}
-// expectedFromRBAC returns the set of : pairs derived from RBACPermissions.
+// expectedFromRBAC returns the set of scope names the DB enum must support.
func expectedFromRBAC() map[string]struct{} {
want := make(map[string]struct{})
- // Low-level :
+ add := func(name string) {
+ if name == "" {
+ return
+ }
+ want[name] = struct{}{}
+ }
+ // Low-level : and synthesized :* wildcards
for resource, def := range policy.RBACPermissions {
if resource == policy.WildcardSymbol {
// Ignore wildcard entry; it has no concrete : pairs.
continue
}
+ add(resource + ":" + policy.WildcardSymbol)
for action := range def.Actions {
- key := resource + ":" + string(action)
- want[key] = struct{}{}
+ add(resource + ":" + string(action))
}
}
// Composite coder:* names
for _, n := range rbac.CompositeScopeNames() {
- want[n] = struct{}{}
+ add(n)
+ }
+ // Built-in coder-prefixed scopes such as coder:all
+ for _, n := range rbac.BuiltinScopeNames() {
+ s := string(n)
+ if !strings.Contains(s, ":") {
+ continue
+ }
+ add(s)
}
return want
}
diff --git a/scripts/generate_api_key_scope_enum/main.go b/scripts/generate_api_key_scope_enum/main.go
deleted file mode 100644
index 130dd865334b8..0000000000000
--- a/scripts/generate_api_key_scope_enum/main.go
+++ /dev/null
@@ -1,32 +0,0 @@
-package main
-
-import (
- "fmt"
- "sort"
-
- "github.com/coder/coder/v2/coderd/rbac"
- "github.com/coder/coder/v2/coderd/rbac/policy"
-)
-
-func main() {
- seen := map[string]struct{}{}
- var vals []string
- for resource, def := range policy.RBACPermissions {
- if resource == policy.WildcardSymbol {
- continue
- }
- for action := range def.Actions {
- vals = append(vals, fmt.Sprintf("%s:%s", resource, action))
- }
- }
- // Include composite coder:* scopes as first-class enum values
- vals = append(vals, rbac.CompositeScopeNames()...)
- sort.Strings(vals)
- for _, v := range vals {
- if _, ok := seen[v]; ok {
- continue
- }
- seen[v] = struct{}{}
- _, _ = fmt.Printf("ALTER TYPE api_key_scope ADD VALUE IF NOT EXISTS '%s';\n", v)
- }
-}
diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts
index e7c612078b6f3..0352ce1c97d9a 100644
--- a/site/src/api/typesGenerated.ts
+++ b/site/src/api/typesGenerated.ts
@@ -112,6 +112,10 @@ export interface APIKey {
// From codersdk/apikey.go
export type APIKeyScope =
+ | "aibridge_interception:*"
+ | "aibridge_interception:create"
+ | "aibridge_interception:read"
+ | "aibridge_interception:update"
| "all"
| "api_key:*"
| "api_key:create"
@@ -119,6 +123,20 @@ export type APIKeyScope =
| "api_key:read"
| "api_key:update"
| "application_connect"
+ | "assign_org_role:*"
+ | "assign_org_role:assign"
+ | "assign_org_role:create"
+ | "assign_org_role:delete"
+ | "assign_org_role:read"
+ | "assign_org_role:unassign"
+ | "assign_org_role:update"
+ | "assign_role:*"
+ | "assign_role:assign"
+ | "assign_role:read"
+ | "assign_role:unassign"
+ | "audit_log:*"
+ | "audit_log:create"
+ | "audit_log:read"
| "coder:all"
| "coder:apikeys.manage_self"
| "coder:application_connect"
@@ -128,26 +146,156 @@ export type APIKeyScope =
| "coder:workspaces.create"
| "coder:workspaces.delete"
| "coder:workspaces.operate"
+ | "connection_log:*"
+ | "connection_log:read"
+ | "connection_log:update"
+ | "crypto_key:*"
+ | "crypto_key:create"
+ | "crypto_key:delete"
+ | "crypto_key:read"
+ | "crypto_key:update"
+ | "debug_info:*"
+ | "debug_info:read"
+ | "deployment_config:*"
+ | "deployment_config:read"
+ | "deployment_config:update"
+ | "deployment_stats:*"
+ | "deployment_stats:read"
| "file:*"
| "file:create"
| "file:read"
+ | "group:*"
+ | "group:create"
+ | "group:delete"
+ | "group_member:*"
+ | "group_member:read"
+ | "group:read"
+ | "group:update"
+ | "idpsync_settings:*"
+ | "idpsync_settings:read"
+ | "idpsync_settings:update"
+ | "inbox_notification:*"
+ | "inbox_notification:create"
+ | "inbox_notification:read"
+ | "inbox_notification:update"
+ | "license:*"
+ | "license:create"
+ | "license:delete"
+ | "license:read"
+ | "notification_message:*"
+ | "notification_message:create"
+ | "notification_message:delete"
+ | "notification_message:read"
+ | "notification_message:update"
+ | "notification_preference:*"
+ | "notification_preference:read"
+ | "notification_preference:update"
+ | "notification_template:*"
+ | "notification_template:read"
+ | "notification_template:update"
+ | "oauth2_app:*"
+ | "oauth2_app_code_token:*"
+ | "oauth2_app_code_token:create"
+ | "oauth2_app_code_token:delete"
+ | "oauth2_app_code_token:read"
+ | "oauth2_app:create"
+ | "oauth2_app:delete"
+ | "oauth2_app:read"
+ | "oauth2_app_secret:*"
+ | "oauth2_app_secret:create"
+ | "oauth2_app_secret:delete"
+ | "oauth2_app_secret:read"
+ | "oauth2_app_secret:update"
+ | "oauth2_app:update"
+ | "organization:*"
+ | "organization:create"
+ | "organization:delete"
+ | "organization_member:*"
+ | "organization_member:create"
+ | "organization_member:delete"
+ | "organization_member:read"
+ | "organization_member:update"
+ | "organization:read"
+ | "organization:update"
+ | "prebuilt_workspace:*"
+ | "prebuilt_workspace:delete"
+ | "prebuilt_workspace:update"
+ | "provisioner_daemon:*"
+ | "provisioner_daemon:create"
+ | "provisioner_daemon:delete"
+ | "provisioner_daemon:read"
+ | "provisioner_daemon:update"
+ | "provisioner_jobs:*"
+ | "provisioner_jobs:create"
+ | "provisioner_jobs:read"
+ | "provisioner_jobs:update"
+ | "replicas:*"
+ | "replicas:read"
+ | "system:*"
+ | "system:create"
+ | "system:delete"
+ | "system:read"
+ | "system:update"
+ | "tailnet_coordinator:*"
+ | "tailnet_coordinator:create"
+ | "tailnet_coordinator:delete"
+ | "tailnet_coordinator:read"
+ | "tailnet_coordinator:update"
| "template:*"
| "template:create"
| "template:delete"
| "template:read"
| "template:update"
| "template:use"
+ | "template:view_insights"
+ | "usage_event:*"
+ | "usage_event:create"
+ | "usage_event:read"
+ | "usage_event:update"
+ | "user:*"
+ | "user:create"
+ | "user:delete"
+ | "user:read"
| "user:read_personal"
| "user_secret:*"
| "user_secret:create"
| "user_secret:delete"
| "user_secret:read"
| "user_secret:update"
+ | "user:update"
| "user:update_personal"
+ | "webpush_subscription:*"
+ | "webpush_subscription:create"
+ | "webpush_subscription:delete"
+ | "webpush_subscription:read"
+ | "workspace_agent_devcontainers:*"
+ | "workspace_agent_devcontainers:create"
+ | "workspace_agent_resource_monitor:*"
+ | "workspace_agent_resource_monitor:create"
+ | "workspace_agent_resource_monitor:read"
+ | "workspace_agent_resource_monitor:update"
| "workspace:*"
| "workspace:application_connect"
| "workspace:create"
+ | "workspace:create_agent"
| "workspace:delete"
+ | "workspace:delete_agent"
+ | "workspace_dormant:*"
+ | "workspace_dormant:application_connect"
+ | "workspace_dormant:create"
+ | "workspace_dormant:create_agent"
+ | "workspace_dormant:delete"
+ | "workspace_dormant:delete_agent"
+ | "workspace_dormant:read"
+ | "workspace_dormant:ssh"
+ | "workspace_dormant:start"
+ | "workspace_dormant:stop"
+ | "workspace_dormant:update"
+ | "workspace_proxy:*"
+ | "workspace_proxy:create"
+ | "workspace_proxy:delete"
+ | "workspace_proxy:read"
+ | "workspace_proxy:update"
| "workspace:read"
| "workspace:ssh"
| "workspace:start"
@@ -155,6 +303,10 @@ export type APIKeyScope =
| "workspace:update";
export const APIKeyScopes: APIKeyScope[] = [
+ "aibridge_interception:*",
+ "aibridge_interception:create",
+ "aibridge_interception:read",
+ "aibridge_interception:update",
"all",
"api_key:*",
"api_key:create",
@@ -162,6 +314,20 @@ export const APIKeyScopes: APIKeyScope[] = [
"api_key:read",
"api_key:update",
"application_connect",
+ "assign_org_role:*",
+ "assign_org_role:assign",
+ "assign_org_role:create",
+ "assign_org_role:delete",
+ "assign_org_role:read",
+ "assign_org_role:unassign",
+ "assign_org_role:update",
+ "assign_role:*",
+ "assign_role:assign",
+ "assign_role:read",
+ "assign_role:unassign",
+ "audit_log:*",
+ "audit_log:create",
+ "audit_log:read",
"coder:all",
"coder:apikeys.manage_self",
"coder:application_connect",
@@ -171,26 +337,156 @@ export const APIKeyScopes: APIKeyScope[] = [
"coder:workspaces.create",
"coder:workspaces.delete",
"coder:workspaces.operate",
+ "connection_log:*",
+ "connection_log:read",
+ "connection_log:update",
+ "crypto_key:*",
+ "crypto_key:create",
+ "crypto_key:delete",
+ "crypto_key:read",
+ "crypto_key:update",
+ "debug_info:*",
+ "debug_info:read",
+ "deployment_config:*",
+ "deployment_config:read",
+ "deployment_config:update",
+ "deployment_stats:*",
+ "deployment_stats:read",
"file:*",
"file:create",
"file:read",
+ "group:*",
+ "group:create",
+ "group:delete",
+ "group_member:*",
+ "group_member:read",
+ "group:read",
+ "group:update",
+ "idpsync_settings:*",
+ "idpsync_settings:read",
+ "idpsync_settings:update",
+ "inbox_notification:*",
+ "inbox_notification:create",
+ "inbox_notification:read",
+ "inbox_notification:update",
+ "license:*",
+ "license:create",
+ "license:delete",
+ "license:read",
+ "notification_message:*",
+ "notification_message:create",
+ "notification_message:delete",
+ "notification_message:read",
+ "notification_message:update",
+ "notification_preference:*",
+ "notification_preference:read",
+ "notification_preference:update",
+ "notification_template:*",
+ "notification_template:read",
+ "notification_template:update",
+ "oauth2_app:*",
+ "oauth2_app_code_token:*",
+ "oauth2_app_code_token:create",
+ "oauth2_app_code_token:delete",
+ "oauth2_app_code_token:read",
+ "oauth2_app:create",
+ "oauth2_app:delete",
+ "oauth2_app:read",
+ "oauth2_app_secret:*",
+ "oauth2_app_secret:create",
+ "oauth2_app_secret:delete",
+ "oauth2_app_secret:read",
+ "oauth2_app_secret:update",
+ "oauth2_app:update",
+ "organization:*",
+ "organization:create",
+ "organization:delete",
+ "organization_member:*",
+ "organization_member:create",
+ "organization_member:delete",
+ "organization_member:read",
+ "organization_member:update",
+ "organization:read",
+ "organization:update",
+ "prebuilt_workspace:*",
+ "prebuilt_workspace:delete",
+ "prebuilt_workspace:update",
+ "provisioner_daemon:*",
+ "provisioner_daemon:create",
+ "provisioner_daemon:delete",
+ "provisioner_daemon:read",
+ "provisioner_daemon:update",
+ "provisioner_jobs:*",
+ "provisioner_jobs:create",
+ "provisioner_jobs:read",
+ "provisioner_jobs:update",
+ "replicas:*",
+ "replicas:read",
+ "system:*",
+ "system:create",
+ "system:delete",
+ "system:read",
+ "system:update",
+ "tailnet_coordinator:*",
+ "tailnet_coordinator:create",
+ "tailnet_coordinator:delete",
+ "tailnet_coordinator:read",
+ "tailnet_coordinator:update",
"template:*",
"template:create",
"template:delete",
"template:read",
"template:update",
"template:use",
+ "template:view_insights",
+ "usage_event:*",
+ "usage_event:create",
+ "usage_event:read",
+ "usage_event:update",
+ "user:*",
+ "user:create",
+ "user:delete",
+ "user:read",
"user:read_personal",
"user_secret:*",
"user_secret:create",
"user_secret:delete",
"user_secret:read",
"user_secret:update",
+ "user:update",
"user:update_personal",
+ "webpush_subscription:*",
+ "webpush_subscription:create",
+ "webpush_subscription:delete",
+ "webpush_subscription:read",
+ "workspace_agent_devcontainers:*",
+ "workspace_agent_devcontainers:create",
+ "workspace_agent_resource_monitor:*",
+ "workspace_agent_resource_monitor:create",
+ "workspace_agent_resource_monitor:read",
+ "workspace_agent_resource_monitor:update",
"workspace:*",
"workspace:application_connect",
"workspace:create",
+ "workspace:create_agent",
"workspace:delete",
+ "workspace:delete_agent",
+ "workspace_dormant:*",
+ "workspace_dormant:application_connect",
+ "workspace_dormant:create",
+ "workspace_dormant:create_agent",
+ "workspace_dormant:delete",
+ "workspace_dormant:delete_agent",
+ "workspace_dormant:read",
+ "workspace_dormant:ssh",
+ "workspace_dormant:start",
+ "workspace_dormant:stop",
+ "workspace_dormant:update",
+ "workspace_proxy:*",
+ "workspace_proxy:create",
+ "workspace_proxy:delete",
+ "workspace_proxy:read",
+ "workspace_proxy:update",
"workspace:read",
"workspace:ssh",
"workspace:start",
From 815e58e872d936616b9110fba86a021f6290cd71 Mon Sep 17 00:00:00 2001
From: Danielle Maywood
Date: Mon, 6 Oct 2025 12:21:21 +0100
Subject: [PATCH 058/298] chore: upgrade clistat to v1.0.2 (#20173)
clistat@v1.0.2 contains a bug fix for when `cpu.max` cgroup file is
missing
---
go.mod | 2 +-
go.sum | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/go.mod b/go.mod
index c375c113f143b..17addc97e8524 100644
--- a/go.mod
+++ b/go.mod
@@ -462,7 +462,7 @@ require (
sigs.k8s.io/yaml v1.5.0 // indirect
)
-require github.com/coder/clistat v1.0.1
+require github.com/coder/clistat v1.0.2
require github.com/SherClockHolmes/webpush-go v1.4.0
diff --git a/go.sum b/go.sum
index 03c0c1bc96e8b..2c18dc1f5adf6 100644
--- a/go.sum
+++ b/go.sum
@@ -919,8 +919,8 @@ github.com/coder/boundary v1.0.1-0.20250925154134-55a44f2a7945 h1:hDUf02kTX8EGR3
github.com/coder/boundary v1.0.1-0.20250925154134-55a44f2a7945/go.mod h1:d1AMFw81rUgrGHuZzWdPNhkY0G8w7pvLNLYF0e3ceC4=
github.com/coder/bubbletea v1.2.2-0.20241212190825-007a1cdb2c41 h1:SBN/DA63+ZHwuWwPHPYoCZ/KLAjHv5g4h2MS4f2/MTI=
github.com/coder/bubbletea v1.2.2-0.20241212190825-007a1cdb2c41/go.mod h1:I9ULxr64UaOSUv7hcb3nX4kowodJCVS7vt7VVJk/kW4=
-github.com/coder/clistat v1.0.1 h1:0ZgnKr1C4Z0ukG1z1+RUa8Z4OoIgWIH2hdxWSXQTubE=
-github.com/coder/clistat v1.0.1/go.mod h1:F+gLef+F9chVrleq808RBxdaoq52R4VLopuLdAsh8Y4=
+github.com/coder/clistat v1.0.2 h1:9SjtcTVMGfM5LbdhjnkyxO3RCngrLvVu1+NXBs9QUy0=
+github.com/coder/clistat v1.0.2/go.mod h1:F+gLef+F9chVrleq808RBxdaoq52R4VLopuLdAsh8Y4=
github.com/coder/flog v1.1.0 h1:kbAes1ai8fIS5OeV+QAnKBQE22ty1jRF/mcAwHpLBa4=
github.com/coder/flog v1.1.0/go.mod h1:UQlQvrkJBvnRGo69Le8E24Tcl5SJleAAR7gYEHzAmdQ=
github.com/coder/glog v1.0.1-0.20220322161911-7365fe7f2cd1/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4=
From dd99d40ad69df231a1ff241c72c3a3110c7c76cc Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 6 Oct 2025 11:57:20 +0000
Subject: [PATCH 059/298] chore: bump github.com/go-playground/validator/v10
from 10.27.0 to 10.28.0 (#20176)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Bumps
[github.com/go-playground/validator/v10](https://github.com/go-playground/validator)
from 10.27.0 to 10.28.0.
Release notes
Sourced from github.com/go-playground/validator/v10's
releases .
Release 10.28.0
What's Changed
New Contributors
Full Changelog : https://github.com/go-playground/validator/compare/v10.27.0...v10.28.0
Commits
bdc3a7d
Add alphaspace validator (#1343 )
63594a0
docs: add description for 'port' validator (#1435 )
45f3a8e
Added https_url tag (#1461 )
7a23bca
Remove Go version 1.23 from CI workflow
13130d2
Fixed missing keys from returned errors in map validation (#1284 )
94e89f0
fix: should panic when define duplicate field param in
required_if (#1468 )
6905468
Bump golang.org/x/crypto from 0.33.0 to 0.42.0 (#1467 )
77ef70e
Bump actions/setup-go from 5 to 6 (#1465 )
78d05ae
Bump golang.org/x/text from 0.22.0 to 0.29.0 (#1464 )
34aea1f
Bump github.com/gabriel-vasile/mimetype from 1.4.8 to 1.4.10 (#1463 )
Additional commits viewable in compare
view
[](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
go.mod | 4 ++--
go.sum | 8 ++++----
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/go.mod b/go.mod
index 17addc97e8524..655dde3efe426 100644
--- a/go.mod
+++ b/go.mod
@@ -125,7 +125,7 @@ require (
github.com/go-chi/httprate v0.15.0
github.com/go-jose/go-jose/v4 v4.1.1
github.com/go-logr/logr v1.4.3
- github.com/go-playground/validator/v10 v10.27.0
+ github.com/go-playground/validator/v10 v10.28.0
github.com/gofrs/flock v0.12.1
github.com/gohugoio/hugo v0.150.0
github.com/golang-jwt/jwt/v4 v4.5.2
@@ -296,7 +296,7 @@ require (
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
- github.com/gabriel-vasile/mimetype v1.4.8 // indirect
+ github.com/gabriel-vasile/mimetype v1.4.10 // indirect
github.com/go-chi/hostrouter v0.3.0 // indirect
github.com/go-ini/ini v1.67.0 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
diff --git a/go.sum b/go.sum
index 2c18dc1f5adf6..d441935a07652 100644
--- a/go.sum
+++ b/go.sum
@@ -1094,8 +1094,8 @@ github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa h1:RDBNVkRviHZtvD
github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA=
github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
-github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM=
-github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8=
+github.com/gabriel-vasile/mimetype v1.4.10 h1:zyueNbySn/z8mJZHLt6IPw0KoZsiQNszIpU+bX4+ZK0=
+github.com/gabriel-vasile/mimetype v1.4.10/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
github.com/gen2brain/beeep v0.11.1 h1:EbSIhrQZFDj1K2fzlMpAYlFOzV8YuNe721A58XcCTYI=
github.com/gen2brain/beeep v0.11.1/go.mod h1:jQVvuwnLuwOcdctHn/uyh8horSBNJ8uGb9Cn2W4tvoc=
github.com/getkin/kin-openapi v0.133.0 h1:pJdmNohVIJ97r4AUFtEXRXwESr8b0bD721u/Tz6k8PQ=
@@ -1163,8 +1163,8 @@ github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/o
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
-github.com/go-playground/validator/v10 v10.27.0 h1:w8+XrWVMhGkxOaaowyKH35gFydVHOvC0/uWoy2Fzwn4=
-github.com/go-playground/validator/v10 v10.27.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo=
+github.com/go-playground/validator/v10 v10.28.0 h1:Q7ibns33JjyW48gHkuFT91qX48KG0ktULL6FgHdG688=
+github.com/go-playground/validator/v10 v10.28.0/go.mod h1:GoI6I1SjPBh9p7ykNE/yj3fFYbyDOpwMn5KXd+m2hUU=
github.com/go-sourcemap/sourcemap v2.1.3+incompatible h1:W1iEw64niKVGogNgBN3ePyLFfuisuzeidWPMPWmECqU=
github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg=
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
From a7c9e623fe7b57145498efd512dfdc809c4ef0b6 Mon Sep 17 00:00:00 2001
From: Sas Swart
Date: Mon, 6 Oct 2025 13:58:37 +0200
Subject: [PATCH 060/298] chore: fix api param name (#20172)
In https://github.com/coder/coder/pull/20137, we added a new flag to
`coder provisioner jobs list`, namely `--initiator`.
To make some follow-up worth it, I need to rename an API param used in
the process before it becomes part of our released and tagged API.
Instead of only accepting UUIDs, we accept an arbitrary string.
We still validate it as a UUID now, but we will expand its validation to
allow any string and then resolve that string the same way that we
resolve the user parameter elsewhere in the API.
---
cli/provisionerjobs.go | 10 ++++------
coderd/provisionerjobs.go | 2 +-
coderd/provisionerjobs_test.go | 20 ++++++++++----------
codersdk/organizations.go | 14 +++++++-------
site/src/api/typesGenerated.ts | 2 +-
5 files changed, 23 insertions(+), 25 deletions(-)
diff --git a/cli/provisionerjobs.go b/cli/provisionerjobs.go
index 3f441a1758045..ee29476ef09dd 100644
--- a/cli/provisionerjobs.go
+++ b/cli/provisionerjobs.go
@@ -66,20 +66,18 @@ func (r *RootCmd) provisionerJobsList() *serpent.Command {
return xerrors.Errorf("current organization: %w", err)
}
- var initiatorID *uuid.UUID
-
if initiator != "" {
user, err := client.User(ctx, initiator)
if err != nil {
return xerrors.Errorf("initiator not found: %s", initiator)
}
- initiatorID = &user.ID
+ initiator = user.ID.String()
}
jobs, err := client.OrganizationProvisionerJobs(ctx, org.ID, &codersdk.OrganizationProvisionerJobsOptions{
- Status: slice.StringEnums[codersdk.ProvisionerJobStatus](status),
- Limit: int(limit),
- InitiatorID: initiatorID,
+ Status: slice.StringEnums[codersdk.ProvisionerJobStatus](status),
+ Limit: int(limit),
+ Initiator: initiator,
})
if err != nil {
return xerrors.Errorf("list provisioner jobs: %w", err)
diff --git a/coderd/provisionerjobs.go b/coderd/provisionerjobs.go
index 4ba923dae2477..68f2207f2f90c 100644
--- a/coderd/provisionerjobs.go
+++ b/coderd/provisionerjobs.go
@@ -111,7 +111,7 @@ func (api *API) handleAuthAndFetchProvisionerJobs(rw http.ResponseWriter, r *htt
ids = p.UUIDs(qp, nil, "ids")
}
tags := p.JSONStringMap(qp, database.StringMap{}, "tags")
- initiatorID := p.UUID(qp, uuid.Nil, "initiator_id")
+ initiatorID := p.UUID(qp, uuid.Nil, "initiator")
p.ErrorExcessParams(qp)
if len(p.Errors) > 0 {
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
diff --git a/coderd/provisionerjobs_test.go b/coderd/provisionerjobs_test.go
index 829c72aa4dbd0..91096e3b64905 100644
--- a/coderd/provisionerjobs_test.go
+++ b/coderd/provisionerjobs_test.go
@@ -173,7 +173,7 @@ func TestProvisionerJobs(t *testing.T) {
ctx := testutil.Context(t, testutil.WaitMedium)
jobs, err := templateAdminClient.OrganizationProvisionerJobs(ctx, owner.OrganizationID, &codersdk.OrganizationProvisionerJobsOptions{
- InitiatorID: &member.ID,
+ Initiator: member.ID.String(),
})
require.NoError(t, err)
require.GreaterOrEqual(t, len(jobs), 1)
@@ -186,8 +186,8 @@ func TestProvisionerJobs(t *testing.T) {
// Test filtering by initiator ID combined with status filter
jobs, err := templateAdminClient.OrganizationProvisionerJobs(ctx, owner.OrganizationID, &codersdk.OrganizationProvisionerJobsOptions{
- InitiatorID: &owner.UserID,
- Status: []codersdk.ProvisionerJobStatus{codersdk.ProvisionerJobSucceeded},
+ Initiator: owner.UserID.String(),
+ Status: []codersdk.ProvisionerJobStatus{codersdk.ProvisionerJobSucceeded},
})
require.NoError(t, err)
@@ -204,8 +204,8 @@ func TestProvisionerJobs(t *testing.T) {
// Test filtering by initiator ID with limit
jobs, err := templateAdminClient.OrganizationProvisionerJobs(ctx, owner.OrganizationID, &codersdk.OrganizationProvisionerJobsOptions{
- InitiatorID: &owner.UserID,
- Limit: 1,
+ Initiator: owner.UserID.String(),
+ Limit: 1,
})
require.NoError(t, err)
require.Len(t, jobs, 1)
@@ -220,8 +220,8 @@ func TestProvisionerJobs(t *testing.T) {
// Test filtering by initiator ID combined with tags
jobs, err := templateAdminClient.OrganizationProvisionerJobs(ctx, owner.OrganizationID, &codersdk.OrganizationProvisionerJobsOptions{
- InitiatorID: &member.ID,
- Tags: map[string]string{"initiatorTest": "true"},
+ Initiator: member.ID.String(),
+ Tags: map[string]string{"initiatorTest": "true"},
})
require.NoError(t, err)
require.Len(t, jobs, 1)
@@ -238,7 +238,7 @@ func TestProvisionerJobs(t *testing.T) {
// Test with non-existent initiator ID
nonExistentID := uuid.New()
jobs, err := templateAdminClient.OrganizationProvisionerJobs(ctx, owner.OrganizationID, &codersdk.OrganizationProvisionerJobsOptions{
- InitiatorID: &nonExistentID,
+ Initiator: nonExistentID.String(),
})
require.NoError(t, err)
require.Len(t, jobs, 0)
@@ -250,7 +250,7 @@ func TestProvisionerJobs(t *testing.T) {
// Test with nil initiator ID (should return all jobs)
jobs, err := templateAdminClient.OrganizationProvisionerJobs(ctx, owner.OrganizationID, &codersdk.OrganizationProvisionerJobsOptions{
- InitiatorID: nil,
+ Initiator: "",
})
require.NoError(t, err)
require.GreaterOrEqual(t, len(jobs), 50) // Should return all jobs (up to default limit)
@@ -282,7 +282,7 @@ func TestProvisionerJobs(t *testing.T) {
ctx := testutil.Context(t, testutil.WaitMedium)
// Member should not be able to access jobs even with initiator filter
jobs, err := memberClient.OrganizationProvisionerJobs(ctx, owner.OrganizationID, &codersdk.OrganizationProvisionerJobsOptions{
- InitiatorID: &member.ID,
+ Initiator: member.ID.String(),
})
require.Error(t, err)
require.Len(t, jobs, 0)
diff --git a/codersdk/organizations.go b/codersdk/organizations.go
index 291bb9ac1baf7..823169d385b22 100644
--- a/codersdk/organizations.go
+++ b/codersdk/organizations.go
@@ -397,11 +397,11 @@ func (c *Client) OrganizationProvisionerDaemons(ctx context.Context, organizatio
}
type OrganizationProvisionerJobsOptions struct {
- Limit int
- IDs []uuid.UUID
- Status []ProvisionerJobStatus
- Tags map[string]string
- InitiatorID *uuid.UUID
+ Limit int
+ IDs []uuid.UUID
+ Status []ProvisionerJobStatus
+ Tags map[string]string
+ Initiator string
}
func (c *Client) OrganizationProvisionerJobs(ctx context.Context, organizationID uuid.UUID, opts *OrganizationProvisionerJobsOptions) ([]ProvisionerJob, error) {
@@ -423,8 +423,8 @@ func (c *Client) OrganizationProvisionerJobs(ctx context.Context, organizationID
}
qp.Add("tags", string(tagsRaw))
}
- if opts.InitiatorID != nil {
- qp.Add("initiator_id", opts.InitiatorID.String())
+ if opts.Initiator != "" {
+ qp.Add("initiator", opts.Initiator)
}
}
diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts
index 0352ce1c97d9a..1e07cf1aa2895 100644
--- a/site/src/api/typesGenerated.ts
+++ b/site/src/api/typesGenerated.ts
@@ -2356,7 +2356,7 @@ export interface OrganizationProvisionerJobsOptions {
readonly IDs: readonly string[];
readonly Status: readonly ProvisionerJobStatus[];
readonly Tags: Record;
- readonly InitiatorID: string | null;
+ readonly Initiator: string;
}
// From codersdk/idpsync.go
From 5fdc4185c75affca050851fb7ce42201d49a4e28 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 6 Oct 2025 11:58:57 +0000
Subject: [PATCH 061/298] chore: bump github.com/moby/moby from
28.4.0+incompatible to 28.5.0+incompatible (#20177)
Bumps [github.com/moby/moby](https://github.com/moby/moby) from
28.4.0+incompatible to 28.5.0+incompatible.
Release notes
Sourced from github.com/moby/moby's
releases .
v28.5.0
28.5.0
For a full list of pull requests and changes in this release, refer
to the relevant GitHub milestones:
Bug fixes and enhancements
Don't print warnings in docker info for broken symlinks
in CLI-plugin directories. docker/cli#6476
Fix a panic during stats on empty event
Actor.ID. docker/cli#6471
Packaging updates
Networking
Eliminated harmless warning about deletion of
endpoint_count from the data store. moby/moby#51064
Fix a bug causing IPAM plugins to not be loaded on Windows. moby/moby#51035
API
Deprecate support for kernel memory TCP accounting
(KernelMemoryTCP). moby/moby#51067
Fix GET containers/{name}/checkpoints returning
null instead of empty JSON array when there are no
checkpoints. moby/moby#51052
Go SDK
Deprecations
Go-SDK: cli/command: deprecate DockerCli.Apply. This
method is no longer used and will be removed in the next release if
there are no remaining uses. docker/cli#6497
Go-SDK: cli/command: deprecate
DockerCli.ContentTrustEnabled. This method is no longer
used and will be removed in the next release. docker/cli#6495
Go-SDK: cli/command: deprecate
DockerCli.DefaultVersion. This method is no longer used and
will be removed in the next release. docker/cli#6491
Go-SDK: cli/command: deprecate ResolveDefaultContext
utility. docker/cli#6529
Go-SDK: cli/command: deprecate WithContentTrustFromEnv,
WithContentTrust options. These options were used
internally, and will be removed in the next release.. docker/cli#6489
Go-SDK: cli/manifest/store: deprecate IsNotFound(). docker/cli#6514
Go-SDK: templates: deprecate NewParse() function. docker/cli#6469
v28.5.0-rc.1
28.5.0-rc.1
For a full list of pull requests and changes in this release, refer
to the relevant GitHub milestones:
... (truncated)
Commits
cd04830
Merge pull request #51075
from vvoland/51074-28.x
e29d6be
vendor: github.com/moby/buildkit v0.25.0
9b43690
Merge pull request #51069
from thaJeztah/28.x_backport_docs_rm_deprecated_vir...
4f35725
api: swagger: remove VirtualSize fields for API > v1.43
79f310d
Merge pull request #51067
from austinvazquez/cherry-pick-deprecate-kernel-mem...
deb4bbb
api: deprecate KernelMemoryTCP support
423a7fd
Merge pull request #51064
from thaJeztah/28.x_backport_fix_epcnt_warning
fbf2fe8
Eliminate warning about endpoint count store delete
252a1eb
Merge pull request #51061
from thaJeztah/28.x_backport_rm_email_example
2c15eb6
api/docs: remove email field from example auth
Additional commits viewable in compare
view
[](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
go.mod | 2 +-
go.sum | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/go.mod b/go.mod
index 655dde3efe426..584cc4595e339 100644
--- a/go.mod
+++ b/go.mod
@@ -154,7 +154,7 @@ require (
github.com/mattn/go-isatty v0.0.20
github.com/mitchellh/go-wordwrap v1.0.1
github.com/mitchellh/mapstructure v1.5.1-0.20231216201459-8508981c8b6c
- github.com/moby/moby v28.4.0+incompatible
+ github.com/moby/moby v28.5.0+incompatible
github.com/mocktools/go-smtp-mock/v2 v2.5.0
github.com/muesli/termenv v0.16.0
github.com/natefinch/atomic v1.0.1
diff --git a/go.sum b/go.sum
index d441935a07652..cdd3ae49e5e69 100644
--- a/go.sum
+++ b/go.sum
@@ -1586,8 +1586,8 @@ github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3N
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
github.com/moby/go-archive v0.1.0 h1:Kk/5rdW/g+H8NHdJW2gsXyZ7UnzvJNOy6VKJqueWdcQ=
github.com/moby/go-archive v0.1.0/go.mod h1:G9B+YoujNohJmrIYFBpSd54GTUB4lt9S+xVQvsJyFuo=
-github.com/moby/moby v28.4.0+incompatible h1:Rhu/o+7EaHGx0MV3KOouThtr3hY33m3aKyA6GDR2QmQ=
-github.com/moby/moby v28.4.0+incompatible/go.mod h1:fDXVQ6+S340veQPv35CzDahGBmHsiclFwfEygB/TWMc=
+github.com/moby/moby v28.5.0+incompatible h1:eN6ksRE7BojoGW18USJGfyqhx/FWJPLs0jqaTNlfSsM=
+github.com/moby/moby v28.5.0+incompatible/go.mod h1:fDXVQ6+S340veQPv35CzDahGBmHsiclFwfEygB/TWMc=
github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk=
github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU=
From 3f49e283086ae17cecc6d9b0d917e0bc50882ebd Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 6 Oct 2025 11:59:26 +0000
Subject: [PATCH 062/298] chore: bump github.com/coreos/go-oidc/v3 from 3.15.0
to 3.16.0 (#20178)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Bumps [github.com/coreos/go-oidc/v3](https://github.com/coreos/go-oidc)
from 3.15.0 to 3.16.0.
Release notes
Sourced from github.com/coreos/go-oidc/v3's
releases .
v3.16.0
What's Changed
New Contributors
Full Changelog : https://github.com/coreos/go-oidc/compare/v3.15.0...v3.16.0
Commits
e958473
bump go to 1.24, remove 1.23 support, bump go-jose dependency, remove
x/net d...
69b1670
refactor: Remove unused time injection from RemoteKeySet
See full diff in compare
view
[](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
go.mod | 4 ++--
go.sum | 8 ++++----
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/go.mod b/go.mod
index 584cc4595e339..f5d8227f9a9c1 100644
--- a/go.mod
+++ b/go.mod
@@ -104,7 +104,7 @@ require (
github.com/coder/terraform-provider-coder/v2 v2.11.0
github.com/coder/websocket v1.8.13
github.com/coder/wgtunnel v0.1.13-0.20240522110300-ade90dfb2da0
- github.com/coreos/go-oidc/v3 v3.15.0
+ github.com/coreos/go-oidc/v3 v3.16.0
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf
github.com/creack/pty v1.1.21
github.com/dave/dst v0.27.2
@@ -123,7 +123,7 @@ require (
github.com/go-chi/chi/v5 v5.2.2
github.com/go-chi/cors v1.2.1
github.com/go-chi/httprate v0.15.0
- github.com/go-jose/go-jose/v4 v4.1.1
+ github.com/go-jose/go-jose/v4 v4.1.3
github.com/go-logr/logr v1.4.3
github.com/go-playground/validator/v10 v10.28.0
github.com/gofrs/flock v0.12.1
diff --git a/go.sum b/go.sum
index cdd3ae49e5e69..193bb9536325b 100644
--- a/go.sum
+++ b/go.sum
@@ -970,8 +970,8 @@ github.com/containerd/platforms v1.0.0-rc.1 h1:83KIq4yy1erSRgOVHNk1HYdPvzdJ5CnsW
github.com/containerd/platforms v1.0.0-rc.1/go.mod h1:J71L7B+aiM5SdIEqmd9wp6THLVRzJGXfNuWCZCllLA4=
github.com/coreos/go-iptables v0.6.0 h1:is9qnZMPYjLd8LYqmm/qlE+wwEgJIkTYdhV3rfZo4jk=
github.com/coreos/go-iptables v0.6.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q=
-github.com/coreos/go-oidc/v3 v3.15.0 h1:R6Oz8Z4bqWR7VFQ+sPSvZPQv4x8M+sJkDO5ojgwlyAg=
-github.com/coreos/go-oidc/v3 v3.15.0/go.mod h1:HaZ3szPaZ0e4r6ebqvsLWlk2Tn+aejfmrfah6hnSYEU=
+github.com/coreos/go-oidc/v3 v3.16.0 h1:qRQUCFstKpXwmEjDQTIbyY/5jF00+asXzSkmkoa/mow=
+github.com/coreos/go-oidc/v3 v3.16.0/go.mod h1:wqPbKFrVnE90vty060SB40FCJ8fTHTxSwyXJqZH+sI8=
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf h1:iW4rZ826su+pqaw19uhpSCzhj44qo35pNgKFGqzDKkU=
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/cpuguy83/dockercfg v0.3.2 h1:DlJTyZGBDlXqUZ2Dk2Q3xHs/FtnooJJVaad2S9GKorA=
@@ -1130,8 +1130,8 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A=
github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
-github.com/go-jose/go-jose/v4 v4.1.1 h1:JYhSgy4mXXzAdF3nUx3ygx347LRXJRrpgyU3adRmkAI=
-github.com/go-jose/go-jose/v4 v4.1.1/go.mod h1:BdsZGqgdO3b6tTc6LSE56wcDbMMLuPsw5d4ZD5f94kA=
+github.com/go-jose/go-jose/v4 v4.1.3 h1:CVLmWDhDVRa6Mi/IgCgaopNosCaHz7zrMeF9MlZRkrs=
+github.com/go-jose/go-jose/v4 v4.1.3/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08=
github.com/go-json-experiment/json v0.0.0-20250725192818-e39067aee2d2 h1:iizUGZ9pEquQS5jTGkh4AqeeHCMbfbjeb0zMt0aEFzs=
github.com/go-json-experiment/json v0.0.0-20250725192818-e39067aee2d2/go.mod h1:TiCD2a1pcmjd7YnhGH0f/zKNcCD06B029pHhzV23c2M=
github.com/go-latex/latex v0.0.0-20210118124228-b3d85cf34e07/go.mod h1:CO1AlKB2CSIqUrmQPqA0gdRIlnLEY0gK5JGjh37zN5U=
From 840afb225b8050eae32a1eca8910f356e203a8e9 Mon Sep 17 00:00:00 2001
From: Bruno Quaresma
Date: Mon, 6 Oct 2025 10:23:53 -0300
Subject: [PATCH 063/298] feat: select template version for tasks (#20146)
Allows users with `updateTemplates` permission to select a specific
template version when creating a task.
One of the biggest changes was moving `TaskPrompt` into `modules/task`
and adding a Storybook entry for it. I also moved some stories from
`TasksPage` to simplify its story.
Closes https://github.com/coder/coder/issues/19986
---
.../tasks/TaskPrompt/TaskPrompt.stories.tsx | 296 ++++++++++++++++++
.../tasks/TaskPrompt}/TaskPrompt.tsx | 112 +++++--
.../src/pages/TasksPage/TasksPage.stories.tsx | 256 +--------------
site/src/pages/TasksPage/TasksPage.tsx | 2 +-
4 files changed, 386 insertions(+), 280 deletions(-)
create mode 100644 site/src/modules/tasks/TaskPrompt/TaskPrompt.stories.tsx
rename site/src/{pages/TasksPage => modules/tasks/TaskPrompt}/TaskPrompt.tsx (82%)
diff --git a/site/src/modules/tasks/TaskPrompt/TaskPrompt.stories.tsx b/site/src/modules/tasks/TaskPrompt/TaskPrompt.stories.tsx
new file mode 100644
index 0000000000000..1710bb3c347f4
--- /dev/null
+++ b/site/src/modules/tasks/TaskPrompt/TaskPrompt.stories.tsx
@@ -0,0 +1,296 @@
+import {
+ MockAIPromptPresets,
+ MockNewTaskData,
+ MockPresets,
+ MockTask,
+ MockTasks,
+ MockTemplate,
+ MockTemplateVersion,
+ MockTemplateVersionExternalAuthGithub,
+ MockTemplateVersionExternalAuthGithubAuthenticated,
+ MockUserOwner,
+ mockApiError,
+} from "testHelpers/entities";
+import { withAuthProvider, withGlobalSnackbar } from "testHelpers/storybook";
+import type { Meta, StoryObj } from "@storybook/react-vite";
+import { API } from "api/api";
+import { expect, spyOn, userEvent, waitFor, within } from "storybook/test";
+import type TasksPage from "../../../pages/TasksPage/TasksPage";
+import { TaskPrompt } from "./TaskPrompt";
+
+const meta: Meta = {
+ title: "modules/tasks/TaskPrompt",
+ component: TaskPrompt,
+ decorators: [withAuthProvider],
+ parameters: {
+ user: MockUserOwner,
+ permissions: {
+ updateTemplates: true,
+ },
+ },
+ beforeEach: () => {
+ spyOn(API, "getTemplateVersionExternalAuth").mockResolvedValue([]);
+ spyOn(API, "getTemplates").mockResolvedValue([
+ MockTemplate,
+ {
+ ...MockTemplate,
+ id: "test-template-2",
+ name: "template 2",
+ display_name: "Template 2",
+ },
+ ]);
+ spyOn(API, "getTemplateVersions").mockResolvedValue([
+ {
+ ...MockTemplateVersion,
+ name: "v1.0.0",
+ },
+ ]);
+ spyOn(API, "getTemplateVersionPresets").mockResolvedValue(null);
+ },
+ args: {
+ templates: [MockTemplate],
+ },
+};
+
+export default meta;
+type Story = StoryObj;
+
+export const LoadingTemplates: Story = {
+ args: {
+ templates: undefined,
+ },
+};
+
+export const EmptyTemplates: Story = {
+ args: {
+ templates: [],
+ },
+};
+
+export const WithPresets: Story = {
+ beforeEach: () => {
+ spyOn(API, "getTemplateVersionPresets").mockResolvedValue(MockPresets);
+ },
+};
+
+export const ReadOnlyPresetPrompt: Story = {
+ beforeEach: () => {
+ spyOn(API, "getTemplateVersionPresets").mockResolvedValue(
+ MockAIPromptPresets,
+ );
+ },
+};
+
+export const OnSuccess: Story = {
+ decorators: [withGlobalSnackbar],
+ parameters: {
+ permissions: {
+ updateTemplates: false,
+ },
+ },
+ beforeEach: () => {
+ const activeVersionId = `${MockTemplate.active_version_id}-latest`;
+ spyOn(API, "getTemplate").mockResolvedValue({
+ ...MockTemplate,
+ active_version_id: activeVersionId,
+ });
+ spyOn(API.experimental, "createTask").mockResolvedValue(MockTask);
+ },
+ play: async ({ canvasElement, step }) => {
+ const canvas = within(canvasElement);
+
+ await step("Run task", async () => {
+ const prompt = await canvas.findByLabelText(/prompt/i);
+ await userEvent.type(prompt, MockNewTaskData.prompt);
+ const submitButton = canvas.getByRole("button", { name: /run task/i });
+ await waitFor(() => expect(submitButton).toBeEnabled());
+ await userEvent.click(submitButton);
+ });
+
+ await step("Uses latest template version", () => {
+ expect(API.experimental.createTask).toHaveBeenCalledWith(
+ MockUserOwner.id,
+ {
+ input: MockNewTaskData.prompt,
+ template_version_id: `${MockTemplate.active_version_id}-latest`,
+ template_version_preset_id: undefined,
+ },
+ );
+ });
+
+ await step("Displays success message", async () => {
+ const body = within(canvasElement.ownerDocument.body);
+ const successMessage = await body.findByText(/task created/i);
+ expect(successMessage).toBeInTheDocument();
+ });
+ },
+};
+
+export const SelectTemplateVersion: Story = {
+ decorators: [withGlobalSnackbar],
+ beforeEach: () => {
+ spyOn(API, "getTemplateVersions").mockResolvedValue([
+ {
+ ...MockTemplateVersion,
+ id: "test-template-version-2",
+ name: "v2.0.0",
+ },
+ {
+ ...MockTemplateVersion,
+ name: "v1.0.0",
+ },
+ ]);
+ spyOn(API.experimental, "createTask").mockResolvedValue(MockTask);
+ },
+ play: async ({ canvasElement, step }) => {
+ const canvas = within(canvasElement);
+
+ await step("Fill prompt", async () => {
+ const prompt = await canvas.findByLabelText(/prompt/i);
+ await userEvent.type(prompt, MockNewTaskData.prompt);
+ });
+
+ await step("Select version", async () => {
+ const body = within(canvasElement.ownerDocument.body);
+ const versionSelect = await canvas.findByLabelText(/template version/i);
+ await userEvent.click(versionSelect);
+ const versionOption = await body.findByRole("option", {
+ name: /v2.0.0/i,
+ });
+ await userEvent.click(versionOption);
+ });
+
+ await step("Submit form", async () => {
+ const submitButton = canvas.getByRole("button", { name: /run task/i });
+ await waitFor(() => expect(submitButton).toBeEnabled());
+ await userEvent.click(submitButton);
+ });
+
+ await step("Uses selected version", () => {
+ expect(API.experimental.createTask).toHaveBeenCalledWith(
+ MockUserOwner.id,
+ {
+ input: MockNewTaskData.prompt,
+ template_version_id: "test-template-version-2",
+ template_version_preset_id: undefined,
+ },
+ );
+ });
+
+ await step("Displays success message", async () => {
+ const body = within(canvasElement.ownerDocument.body);
+ const successMessage = await body.findByText(/task created/i);
+ expect(successMessage).toBeInTheDocument();
+ });
+ },
+};
+
+export const OnError: Story = {
+ decorators: [withGlobalSnackbar],
+ beforeEach: () => {
+ spyOn(API, "getTemplates").mockResolvedValue([MockTemplate]);
+ spyOn(API, "getTemplate").mockResolvedValue(MockTemplate);
+ spyOn(API.experimental, "getTasks").mockResolvedValue(MockTasks);
+ spyOn(API.experimental, "createTask").mockRejectedValue(
+ mockApiError({
+ message: "Failed to create task",
+ detail: "You don't have permission to create tasks.",
+ }),
+ );
+ },
+ play: async ({ canvasElement, step }) => {
+ const canvas = within(canvasElement);
+
+ await step("Run task", async () => {
+ const prompt = await canvas.findByLabelText(/prompt/i);
+ await userEvent.type(prompt, "Create a new task");
+ const submitButton = canvas.getByRole("button", { name: /run task/i });
+ await waitFor(() => expect(submitButton).toBeEnabled());
+ await userEvent.click(submitButton);
+ });
+
+ await step("Verify error", async () => {
+ await canvas.findByText(/failed to create task/i);
+ });
+ },
+};
+
+export const AuthenticatedExternalAuth: Story = {
+ beforeEach: () => {
+ spyOn(API.experimental, "getTasks")
+ .mockResolvedValueOnce(MockTasks)
+ .mockResolvedValue([MockNewTaskData, ...MockTasks]);
+ spyOn(API.experimental, "createTask").mockResolvedValue(MockTask);
+ spyOn(API, "getTemplateVersionExternalAuth").mockResolvedValue([
+ MockTemplateVersionExternalAuthGithubAuthenticated,
+ ]);
+ },
+ play: async ({ canvasElement, step }) => {
+ const canvas = within(canvasElement);
+
+ await step("Does not render external auth", async () => {
+ expect(
+ canvas.queryByText(/external authentication/),
+ ).not.toBeInTheDocument();
+ });
+ },
+ parameters: {
+ chromatic: {
+ disableSnapshot: true,
+ },
+ },
+};
+
+export const MissingExternalAuth: Story = {
+ beforeEach: () => {
+ spyOn(API.experimental, "getTasks")
+ .mockResolvedValueOnce(MockTasks)
+ .mockResolvedValue([MockNewTaskData, ...MockTasks]);
+ spyOn(API.experimental, "createTask").mockResolvedValue(MockTask);
+ spyOn(API, "getTemplateVersionExternalAuth").mockResolvedValue([
+ MockTemplateVersionExternalAuthGithub,
+ ]);
+ },
+ play: async ({ canvasElement, step }) => {
+ const canvas = within(canvasElement);
+
+ await step("Submit is disabled", async () => {
+ const prompt = await canvas.findByLabelText(/prompt/i);
+ await userEvent.type(prompt, MockNewTaskData.prompt);
+ const submitButton = canvas.getByRole("button", { name: /run task/i });
+ expect(submitButton).toBeDisabled();
+ });
+
+ await step("Renders external authentication", async () => {
+ await canvas.findByRole("button", { name: /connect to github/i });
+ });
+ },
+};
+
+export const ExternalAuthError: Story = {
+ beforeEach: () => {
+ spyOn(API.experimental, "getTasks")
+ .mockResolvedValueOnce(MockTasks)
+ .mockResolvedValue([MockNewTaskData, ...MockTasks]);
+ spyOn(API.experimental, "createTask").mockResolvedValue(MockTask);
+ spyOn(API, "getTemplateVersionExternalAuth").mockRejectedValue(
+ mockApiError({
+ message: "Failed to load external auth",
+ }),
+ );
+ },
+ play: async ({ canvasElement, step }) => {
+ const canvas = within(canvasElement);
+
+ await step("Submit is disabled", async () => {
+ const prompt = await canvas.findByLabelText(/prompt/i);
+ await userEvent.type(prompt, MockNewTaskData.prompt);
+ const submitButton = canvas.getByRole("button", { name: /run task/i });
+ expect(submitButton).toBeDisabled();
+ });
+
+ await step("Renders error", async () => {
+ await canvas.findByText(/failed to load external auth/i);
+ });
+ },
+};
diff --git a/site/src/pages/TasksPage/TaskPrompt.tsx b/site/src/modules/tasks/TaskPrompt/TaskPrompt.tsx
similarity index 82%
rename from site/src/pages/TasksPage/TaskPrompt.tsx
rename to site/src/modules/tasks/TaskPrompt/TaskPrompt.tsx
index c08f0ee8a7775..2f399ac3e4d87 100644
--- a/site/src/pages/TasksPage/TaskPrompt.tsx
+++ b/site/src/modules/tasks/TaskPrompt/TaskPrompt.tsx
@@ -1,7 +1,10 @@
import type { SelectTriggerProps } from "@radix-ui/react-select";
import { API } from "api/api";
import { getErrorDetail, getErrorMessage } from "api/errors";
-import { templateVersionPresets } from "api/queries/templates";
+import {
+ templateVersionPresets,
+ templateVersions,
+} from "api/queries/templates";
import type {
Preset,
Task,
@@ -135,12 +138,14 @@ type CreateTaskFormProps = {
};
const CreateTaskForm: FC = ({ templates, onSuccess }) => {
- const { user } = useAuthenticated();
+ const { user, permissions } = useAuthenticated();
const queryClient = useQueryClient();
+ const [prompt, setPrompt] = useState("");
+
+ // Template
const [selectedTemplateId, setSelectedTemplateId] = useState(
templates[0].id,
);
- const [selectedPresetId, setSelectedPresetId] = useState();
const selectedTemplate = templates.find(
(t) => t.id === selectedTemplateId,
) as Template;
@@ -152,24 +157,38 @@ const CreateTaskForm: FC = ({ templates, onSuccess }) => {
isLoadingExternalAuth,
} = useExternalAuth(selectedTemplate.active_version_id);
- // Fetch presets when template changes
- const { data: presets, isLoading: isLoadingPresets } = useQuery(
- templateVersionPresets(selectedTemplate.active_version_id),
+ // Template versions
+ const [selectedVersionId, setSelectedVersionId] = useState(
+ selectedTemplate.active_version_id,
);
- const defaultPreset = presets?.find((p) => p.Default);
+ const versionsQuery = useQuery({
+ ...templateVersions(selectedTemplate.id),
+ enabled: permissions.updateTemplates,
+ });
- // Handle preset selection when data changes
+ // Presets
+ const { data: presets, isLoading: isLoadingPresets } = useQuery(
+ templateVersionPresets(selectedVersionId),
+ );
+ const [selectedPresetId, setSelectedPresetId] = useState();
useEffect(() => {
- setSelectedPresetId(defaultPreset?.ID);
- }, [defaultPreset?.ID]);
-
- // Extract AI prompt from selected preset
+ const defaultPreset = presets?.find((p) => p.Default);
+ setSelectedPresetId(defaultPreset?.ID ?? presets?.[0]?.ID);
+ }, [presets]);
const selectedPreset = presets?.find((p) => p.ID === selectedPresetId);
- const presetAIPrompt = selectedPreset?.Parameters?.find(
+
+ // Read-only prompt if defined in preset
+ const presetPrompt = selectedPreset?.Parameters?.find(
(param) => param.Name === AI_PROMPT_PARAMETER_NAME,
)?.Value;
- const isPromptReadOnly = !!presetAIPrompt;
+ const isPromptReadOnly = !!presetPrompt;
+ useEffect(() => {
+ if (presetPrompt) {
+ setPrompt(presetPrompt);
+ }
+ }, [presetPrompt]);
+ // External Auth
const missedExternalAuth = externalAuth?.filter(
(auth) => !auth.optional && !auth.authenticated,
);
@@ -178,13 +197,26 @@ const CreateTaskForm: FC = ({ templates, onSuccess }) => {
: true;
const createTaskMutation = useMutation({
- mutationFn: async ({ prompt }: CreateTaskMutationFnProps) =>
- createTaskWithLatestTemplateVersion(
+ mutationFn: async ({ prompt }: CreateTaskMutationFnProps) => {
+ // Users with updateTemplates permission can select the version to use.
+ if (permissions.updateTemplates) {
+ return API.experimental.createTask(user.id, {
+ input: prompt,
+ template_version_id: selectedVersionId,
+ template_version_preset_id: selectedPresetId,
+ });
+ }
+
+ // For regular users we want to enforce task creation to always use the latest
+ // active template version, to avoid issues when the active version changes
+ // between template load and user action.
+ return createTaskWithLatestTemplateVersion(
prompt,
user.id,
selectedTemplate.id,
selectedPresetId,
- ),
+ );
+ },
onSuccess: async (task) => {
await queryClient.invalidateQueries({ queryKey: ["tasks"] });
onSuccess(task);
@@ -194,10 +226,6 @@ const CreateTaskForm: FC = ({ templates, onSuccess }) => {
const onSubmit = async (e: React.FormEvent) => {
e.preventDefault();
- const form = e.currentTarget;
- const formData = new FormData(form);
- const prompt = presetAIPrompt || (formData.get("prompt") as string);
-
try {
await createTaskMutation.mutateAsync({
prompt,
@@ -225,7 +253,7 @@ const CreateTaskForm: FC = ({ templates, onSuccess }) => {
htmlFor="prompt"
className={
isPromptReadOnly
- ? "text-xs font-medium text-content-primary mb-2 block"
+ ? "text-xs font-medium text-content-primary block px-3 pt-2"
: "sr-only"
}
>
@@ -233,12 +261,13 @@ const CreateTaskForm: FC = ({ templates, onSuccess }) => {
setPrompt(e.target.value)}
readOnly={isPromptReadOnly}
/>
-
+
Template
@@ -265,7 +294,34 @@ const CreateTaskForm: FC = ({ templates, onSuccess }) => {
-
+ {versionsQuery.data && (
+
+
+ Template version
+
+
setSelectedVersionId(value)}
+ value={selectedVersionId}
+ required
+ >
+
+
+
+
+ {versionsQuery.data.map((version) => {
+ return (
+
+ {version.name}
+
+ );
+ })}
+
+
+
+ )}
+
+
Preset
@@ -273,11 +329,12 @@ const CreateTaskForm: FC
= ({ templates, onSuccess }) => {
) : (
presets &&
- presets.length > 0 && (
+ presets.length > 0 &&
+ selectedPresetId && (
@@ -438,6 +495,7 @@ async function createTaskWithLatestTemplateVersion(
const PromptTextarea: FC = (props) => {
return (
= {
@@ -54,7 +43,7 @@ const meta: Meta = {
export default meta;
type Story = StoryObj;
-export const LoadingAITemplates: Story = {
+export const LoadingTemplates: Story = {
beforeEach: () => {
spyOn(API, "getTemplates").mockImplementation(
() => new Promise(() => 1000 * 60 * 60),
@@ -62,7 +51,7 @@ export const LoadingAITemplates: Story = {
},
};
-export const LoadingAITemplatesError: Story = {
+export const LoadingTemplatesError: Story = {
beforeEach: () => {
spyOn(API, "getTemplates").mockRejectedValue(
mockApiError({
@@ -73,13 +62,6 @@ export const LoadingAITemplatesError: Story = {
},
};
-export const EmptyAITemplates: Story = {
- beforeEach: () => {
- spyOn(API, "getTemplates").mockResolvedValue([]);
- spyOn(API.experimental, "getTasks").mockResolvedValue([]);
- },
-};
-
export const LoadingTasks: Story = {
beforeEach: () => {
spyOn(API, "getTemplates").mockResolvedValue([MockTemplate]);
@@ -123,58 +105,6 @@ export const LoadedTasks: Story = {
},
};
-export const LoadedTasksWithPresets: Story = {
- beforeEach: () => {
- const mockTemplateWithPresets = {
- ...MockTemplate,
- id: "test-template-2",
- name: "template-with-presets",
- display_name: "Template with Presets",
- };
-
- spyOn(API, "getTemplates").mockResolvedValue([
- MockTemplate,
- mockTemplateWithPresets,
- ]);
- spyOn(API.experimental, "getTasks").mockResolvedValue(MockTasks);
- spyOn(API, "getTemplateVersionPresets").mockImplementation(
- async (versionId) => {
- // Return presets only for the second template
- if (versionId === mockTemplateWithPresets.active_version_id) {
- return MockPresets;
- }
- return null;
- },
- );
- },
-};
-
-export const LoadedTasksWithAIPromptPresets: Story = {
- beforeEach: () => {
- const mockTemplateWithPresets = {
- ...MockTemplate,
- id: "test-template-2",
- name: "template-with-presets",
- display_name: "Template with AI Prompt Presets",
- };
-
- spyOn(API, "getTemplates").mockResolvedValue([
- MockTemplate,
- mockTemplateWithPresets,
- ]);
- spyOn(API.experimental, "getTasks").mockResolvedValue(MockTasks);
- spyOn(API, "getTemplateVersionPresets").mockImplementation(
- async (versionId) => {
- // Return presets only for the second template
- if (versionId === mockTemplateWithPresets.active_version_id) {
- return MockAIPromptPresets;
- }
- return null;
- },
- );
- },
-};
-
export const LoadedTasksWaitingForInput: Story = {
beforeEach: () => {
const [firstTask, ...otherTasks] = MockTasks;
@@ -225,184 +155,6 @@ export const LoadedTasksWaitingForInputTab: Story = {
},
};
-export const CreateTaskSuccessfully: Story = {
- decorators: [withGlobalSnackbar],
- parameters: {
- reactRouter: reactRouterParameters({
- location: {
- path: "/tasks",
- },
- routing: [
- {
- path: "/tasks",
- useStoryElement: true,
- },
- {
- path: "/tasks/:ownerName/:workspaceName",
- element: Task page ,
- },
- ],
- }),
- },
- beforeEach: () => {
- const activeVersionId = `${MockTemplate.active_version_id}-latest`;
- spyOn(API, "getTemplates").mockResolvedValue([MockTemplate]);
- spyOn(API, "getTemplate").mockResolvedValue({
- ...MockTemplate,
- active_version_id: activeVersionId,
- });
- spyOn(API.experimental, "getTasks")
- .mockResolvedValueOnce(MockTasks)
- .mockResolvedValue([MockNewTaskData, ...MockTasks]);
- spyOn(API.experimental, "createTask").mockResolvedValue(MockTask);
- },
- play: async ({ canvasElement, step }) => {
- const canvas = within(canvasElement);
-
- await step("Run task", async () => {
- const prompt = await canvas.findByLabelText(/prompt/i);
- await userEvent.type(prompt, MockNewTaskData.prompt);
- const submitButton = canvas.getByRole("button", { name: /run task/i });
- await waitFor(() => expect(submitButton).toBeEnabled());
- await userEvent.click(submitButton);
- });
-
- await step("Uses latest template version", () => {
- expect(API.experimental.createTask).toHaveBeenCalledWith(
- MockUserOwner.id,
- {
- input: MockNewTaskData.prompt,
- template_version_id: `${MockTemplate.active_version_id}-latest`,
- template_version_preset_id: undefined,
- },
- );
- });
-
- await step("Displays success message", async () => {
- const body = within(canvasElement.ownerDocument.body);
- const successMessage = await body.findByText(/task created/i);
- expect(successMessage).toBeInTheDocument();
- });
-
- await step("Find task in the table", async () => {
- const table = canvasElement.querySelector("table");
- await waitFor(() => {
- expect(table).toHaveTextContent(MockNewTaskData.prompt);
- });
- });
- },
-};
-
-export const CreateTaskError: Story = {
- decorators: [withGlobalSnackbar],
- beforeEach: () => {
- spyOn(API, "getTemplates").mockResolvedValue([MockTemplate]);
- spyOn(API, "getTemplate").mockResolvedValue(MockTemplate);
- spyOn(API.experimental, "getTasks").mockResolvedValue(MockTasks);
- spyOn(API.experimental, "createTask").mockRejectedValue(
- mockApiError({
- message: "Failed to create task",
- detail: "You don't have permission to create tasks.",
- }),
- );
- },
- play: async ({ canvasElement, step }) => {
- const canvas = within(canvasElement);
-
- await step("Run task", async () => {
- const prompt = await canvas.findByLabelText(/prompt/i);
- await userEvent.type(prompt, "Create a new task");
- const submitButton = canvas.getByRole("button", { name: /run task/i });
- await waitFor(() => expect(submitButton).toBeEnabled());
- await userEvent.click(submitButton);
- });
-
- await step("Verify error", async () => {
- await canvas.findByText(/failed to create task/i);
- });
- },
-};
-
-export const WithAuthenticatedExternalAuth: Story = {
- beforeEach: () => {
- spyOn(API.experimental, "getTasks")
- .mockResolvedValueOnce(MockTasks)
- .mockResolvedValue([MockNewTaskData, ...MockTasks]);
- spyOn(API.experimental, "createTask").mockResolvedValue(MockTask);
- spyOn(API, "getTemplateVersionExternalAuth").mockResolvedValue([
- MockTemplateVersionExternalAuthGithubAuthenticated,
- ]);
- },
- play: async ({ canvasElement, step }) => {
- const canvas = within(canvasElement);
-
- await step("Does not render external auth", async () => {
- expect(
- canvas.queryByText(/external authentication/),
- ).not.toBeInTheDocument();
- });
- },
- parameters: {
- chromatic: {
- disableSnapshot: true,
- },
- },
-};
-
-export const MissingExternalAuth: Story = {
- beforeEach: () => {
- spyOn(API.experimental, "getTasks")
- .mockResolvedValueOnce(MockTasks)
- .mockResolvedValue([MockNewTaskData, ...MockTasks]);
- spyOn(API.experimental, "createTask").mockResolvedValue(MockTask);
- spyOn(API, "getTemplateVersionExternalAuth").mockResolvedValue([
- MockTemplateVersionExternalAuthGithub,
- ]);
- },
- play: async ({ canvasElement, step }) => {
- const canvas = within(canvasElement);
-
- await step("Submit is disabled", async () => {
- const prompt = await canvas.findByLabelText(/prompt/i);
- await userEvent.type(prompt, MockNewTaskData.prompt);
- const submitButton = canvas.getByRole("button", { name: /run task/i });
- expect(submitButton).toBeDisabled();
- });
-
- await step("Renders external authentication", async () => {
- await canvas.findByRole("button", { name: /connect to github/i });
- });
- },
-};
-
-export const ExternalAuthError: Story = {
- beforeEach: () => {
- spyOn(API.experimental, "getTasks")
- .mockResolvedValueOnce(MockTasks)
- .mockResolvedValue([MockNewTaskData, ...MockTasks]);
- spyOn(API.experimental, "createTask").mockResolvedValue(MockTask);
- spyOn(API, "getTemplateVersionExternalAuth").mockRejectedValue(
- mockApiError({
- message: "Failed to load external auth",
- }),
- );
- },
- play: async ({ canvasElement, step }) => {
- const canvas = within(canvasElement);
-
- await step("Submit is disabled", async () => {
- const prompt = await canvas.findByLabelText(/prompt/i);
- await userEvent.type(prompt, MockNewTaskData.prompt);
- const submitButton = canvas.getByRole("button", { name: /run task/i });
- expect(submitButton).toBeDisabled();
- });
-
- await step("Renders error", async () => {
- await canvas.findByText(/failed to load external auth/i);
- });
- },
-};
-
export const NonAdmin: Story = {
parameters: {
permissions: {
diff --git a/site/src/pages/TasksPage/TasksPage.tsx b/site/src/pages/TasksPage/TasksPage.tsx
index 451a0f0709cc1..06da02a278953 100644
--- a/site/src/pages/TasksPage/TasksPage.tsx
+++ b/site/src/pages/TasksPage/TasksPage.tsx
@@ -11,11 +11,11 @@ import {
} from "components/PageHeader/PageHeader";
import { useAuthenticated } from "hooks";
import { useSearchParamsKey } from "hooks/useSearchParamsKey";
+import { TaskPrompt } from "modules/tasks/TaskPrompt/TaskPrompt";
import type { FC } from "react";
import { useQuery } from "react-query";
import { cn } from "utils/cn";
import { pageTitle } from "utils/page";
-import { TaskPrompt } from "./TaskPrompt";
import { TasksTable } from "./TasksTable";
import { UsersCombobox } from "./UsersCombobox";
From 33fbb174d536fa0254fb20eeb82bab840d1b542f Mon Sep 17 00:00:00 2001
From: Bruno Quaresma
Date: Mon, 6 Oct 2025 11:51:44 -0300
Subject: [PATCH 064/298] chore: set biome lsp bin path for vscode (#20180)
---
.vscode/settings.json | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 6057824039b6d..762ed91595ded 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -61,5 +61,6 @@
"typos.config": ".github/workflows/typos.toml",
"[markdown]": {
"editor.defaultFormatter": "DavidAnson.vscode-markdownlint"
- }
+ },
+ "biome.lsp.bin": "site/node_modules/.bin/biome"
}
From 1783ee13ab3d69b7f0cc5c0169f3e9b257c47b44 Mon Sep 17 00:00:00 2001
From: Bruno Quaresma
Date: Mon, 6 Oct 2025 11:51:56 -0300
Subject: [PATCH 065/298] chore: fix biome error when running make lint
(#20182)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Fixes a Biome lint error when running `make lint`.
```
> biome check --error-on-warnings --fix .
biome.jsonc:6:13 deserialize ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
ℹ The configuration schema version does not match the CLI version 2.2.4
4 │ "includes": ["!e2e/**/*Generated.ts"]
5 │ },
> 6 │ "$schema": "https://biomejs.dev/schemas/2.2.0/schema.json"
│ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
7 │ }
8 │
ℹ Expected: 2.2.4
Found: 2.2.0
ℹ Run the command biome migrate to migrate the configuration file.
Checked 1165 files in 796ms. No fixes applied.
```
---
biome.jsonc | 13 +++----------
site/biome.jsonc | 2 +-
2 files changed, 4 insertions(+), 11 deletions(-)
diff --git a/biome.jsonc b/biome.jsonc
index ae81184cdca0c..daa99a8b90ce4 100644
--- a/biome.jsonc
+++ b/biome.jsonc
@@ -6,10 +6,7 @@
"defaultBranch": "main"
},
"files": {
- "includes": [
- "**",
- "!**/pnpm-lock.yaml"
- ],
+ "includes": ["**", "!**/pnpm-lock.yaml"],
"ignoreUnknown": true
},
"linter": {
@@ -69,11 +66,7 @@
"noConsole": {
"level": "error",
"options": {
- "allow": [
- "error",
- "info",
- "warn"
- ]
+ "allow": ["error", "info", "warn"]
}
}
},
@@ -82,5 +75,5 @@
}
}
},
- "$schema": "https://biomejs.dev/schemas/2.2.0/schema.json"
+ "$schema": "./node_modules/@biomejs/biome/configuration_schema.json"
}
diff --git a/site/biome.jsonc b/site/biome.jsonc
index 4c9cb18aa482b..be24c66617a6e 100644
--- a/site/biome.jsonc
+++ b/site/biome.jsonc
@@ -3,5 +3,5 @@
"files": {
"includes": ["!e2e/**/*Generated.ts"]
},
- "$schema": "https://biomejs.dev/schemas/2.2.0/schema.json"
+ "$schema": "./node_modules/@biomejs/biome/configuration_schema.json"
}
From 23a44d10ac7d11c5ff0d54c3dca41aad5de1985c Mon Sep 17 00:00:00 2001
From: Bruno Quaresma
Date: Mon, 6 Oct 2025 13:12:56 -0300
Subject: [PATCH 066/298] feat: include latest build id in task responses
(#20181)
Adding the latest build ID is necessary to locate the logs associated
with the tasks in the UI.
---
cli/exp_task_status_test.go | 1 +
coderd/aitasks.go | 1 +
coderd/aitasks_test.go | 2 ++
codersdk/aitasks.go | 1 +
site/src/api/typesGenerated.ts | 1 +
site/src/testHelpers/entities.ts | 1 +
6 files changed, 7 insertions(+)
diff --git a/cli/exp_task_status_test.go b/cli/exp_task_status_test.go
index be62a76476d35..24a0c82b70a73 100644
--- a/cli/exp_task_status_test.go
+++ b/cli/exp_task_status_test.go
@@ -193,6 +193,7 @@ STATE CHANGED STATUS HEALTHY STATE MESSAGE
"workspace_agent_id": null,
"workspace_agent_lifecycle": null,
"workspace_agent_health": null,
+ "latest_build_id": null,
"initial_prompt": "",
"status": "running",
"current_state": {
diff --git a/coderd/aitasks.go b/coderd/aitasks.go
index 275cfe855621e..fa6bc1dbd5cf7 100644
--- a/coderd/aitasks.go
+++ b/coderd/aitasks.go
@@ -272,6 +272,7 @@ func taskFromWorkspace(ws codersdk.Workspace, initialPrompt string) codersdk.Tas
WorkspaceAgentID: taskAgentID,
WorkspaceAgentLifecycle: taskAgentLifecycle,
WorkspaceAgentHealth: taskAgentHealth,
+ LatestBuildID: uuid.NullUUID{Valid: true, UUID: ws.LatestBuild.ID},
CreatedAt: ws.CreatedAt,
UpdatedAt: ws.UpdatedAt,
InitialPrompt: initialPrompt,
diff --git a/coderd/aitasks_test.go b/coderd/aitasks_test.go
index 6425e06c771db..5ec6f49a5f34c 100644
--- a/coderd/aitasks_test.go
+++ b/coderd/aitasks_test.go
@@ -270,6 +270,7 @@ func TestTasks(t *testing.T) {
assert.Equal(t, wantPrompt, got.InitialPrompt, "task prompt should match the AI Prompt parameter")
assert.Equal(t, workspace.Name, got.Name, "task name should map from workspace name")
assert.Equal(t, workspace.ID, got.WorkspaceID.UUID, "workspace id should match")
+ assert.Equal(t, workspace.LatestBuild.ID, got.LatestBuildID.UUID, "latest build id should match")
// Status should be populated via app status or workspace status mapping.
assert.NotEmpty(t, got.Status, "task status should not be empty")
})
@@ -320,6 +321,7 @@ func TestTasks(t *testing.T) {
assert.Equal(t, workspace.Name, task.Name, "task name should map from workspace name")
assert.Equal(t, wantPrompt, task.InitialPrompt, "task prompt should match the AI Prompt parameter")
assert.Equal(t, workspace.ID, task.WorkspaceID.UUID, "workspace id should match")
+ assert.Equal(t, workspace.LatestBuild.ID, task.LatestBuildID.UUID, "latest build id should match")
assert.NotEmpty(t, task.Status, "task status should not be empty")
// Stop the workspace
diff --git a/codersdk/aitasks.go b/codersdk/aitasks.go
index 21efb15b5313e..e62f65ce95c49 100644
--- a/codersdk/aitasks.go
+++ b/codersdk/aitasks.go
@@ -119,6 +119,7 @@ type Task struct {
WorkspaceAgentID uuid.NullUUID `json:"workspace_agent_id" format:"uuid" table:"workspace agent id"`
WorkspaceAgentLifecycle *WorkspaceAgentLifecycle `json:"workspace_agent_lifecycle" table:"workspace agent lifecycle"`
WorkspaceAgentHealth *WorkspaceAgentHealth `json:"workspace_agent_health" table:"workspace agent health"`
+ LatestBuildID uuid.NullUUID `json:"latest_build_id" format:"uuid" table:"latest build id"`
InitialPrompt string `json:"initial_prompt" table:"initial prompt"`
Status WorkspaceStatus `json:"status" enums:"pending,starting,running,stopping,stopped,failed,canceling,canceled,deleting,deleted" table:"status"`
CurrentState *TaskStateEntry `json:"current_state" table:"cs,recursive_inline"`
diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts
index 1e07cf1aa2895..da2c6806a22ee 100644
--- a/site/src/api/typesGenerated.ts
+++ b/site/src/api/typesGenerated.ts
@@ -3330,6 +3330,7 @@ export interface Task {
readonly workspace_agent_id: string | null;
readonly workspace_agent_lifecycle: WorkspaceAgentLifecycle | null;
readonly workspace_agent_health: WorkspaceAgentHealth | null;
+ readonly latest_build_id: string | null;
readonly initial_prompt: string;
readonly status: WorkspaceStatus;
readonly current_state: TaskStateEntry | null;
diff --git a/site/src/testHelpers/entities.ts b/site/src/testHelpers/entities.ts
index 0b8d87f8111ef..d9a73bc16326d 100644
--- a/site/src/testHelpers/entities.ts
+++ b/site/src/testHelpers/entities.ts
@@ -5031,6 +5031,7 @@ export const MockTask: TypesGen.Task = {
workspace_agent_id: MockWorkspaceAgent.id,
workspace_agent_lifecycle: MockWorkspaceAgent.lifecycle_state,
workspace_agent_health: MockWorkspaceAgent.health,
+ latest_build_id: MockWorkspace.latest_build.id,
initial_prompt: "Perform some task",
status: "running",
current_state: {
From 83c4611293919035ff40e33b6b4d84c0dacfb6eb Mon Sep 17 00:00:00 2001
From: Bruno Quaresma
Date: Mon, 6 Oct 2025 14:44:11 -0300
Subject: [PATCH 067/298] chore: revert "feat: include latest build id in task
responses" (#20184)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Reverts coder/coder#20181
I realized we don’t need this in the task response. When loading a task,
we already need much more workspace information, so it makes more sense
to fetch the workspace data separately instead of trying to embed all
its details into the response.
I think we can keep the task response clean and focused on the essential
information needed to list tasks. For more specific details, we can
fetch the related resources as needed. So, I’m reverting this PR.
---
cli/exp_task_status_test.go | 1 -
coderd/aitasks.go | 1 -
coderd/aitasks_test.go | 2 --
codersdk/aitasks.go | 1 -
site/src/api/typesGenerated.ts | 1 -
site/src/testHelpers/entities.ts | 1 -
6 files changed, 7 deletions(-)
diff --git a/cli/exp_task_status_test.go b/cli/exp_task_status_test.go
index 24a0c82b70a73..be62a76476d35 100644
--- a/cli/exp_task_status_test.go
+++ b/cli/exp_task_status_test.go
@@ -193,7 +193,6 @@ STATE CHANGED STATUS HEALTHY STATE MESSAGE
"workspace_agent_id": null,
"workspace_agent_lifecycle": null,
"workspace_agent_health": null,
- "latest_build_id": null,
"initial_prompt": "",
"status": "running",
"current_state": {
diff --git a/coderd/aitasks.go b/coderd/aitasks.go
index fa6bc1dbd5cf7..275cfe855621e 100644
--- a/coderd/aitasks.go
+++ b/coderd/aitasks.go
@@ -272,7 +272,6 @@ func taskFromWorkspace(ws codersdk.Workspace, initialPrompt string) codersdk.Tas
WorkspaceAgentID: taskAgentID,
WorkspaceAgentLifecycle: taskAgentLifecycle,
WorkspaceAgentHealth: taskAgentHealth,
- LatestBuildID: uuid.NullUUID{Valid: true, UUID: ws.LatestBuild.ID},
CreatedAt: ws.CreatedAt,
UpdatedAt: ws.UpdatedAt,
InitialPrompt: initialPrompt,
diff --git a/coderd/aitasks_test.go b/coderd/aitasks_test.go
index 5ec6f49a5f34c..6425e06c771db 100644
--- a/coderd/aitasks_test.go
+++ b/coderd/aitasks_test.go
@@ -270,7 +270,6 @@ func TestTasks(t *testing.T) {
assert.Equal(t, wantPrompt, got.InitialPrompt, "task prompt should match the AI Prompt parameter")
assert.Equal(t, workspace.Name, got.Name, "task name should map from workspace name")
assert.Equal(t, workspace.ID, got.WorkspaceID.UUID, "workspace id should match")
- assert.Equal(t, workspace.LatestBuild.ID, got.LatestBuildID.UUID, "latest build id should match")
// Status should be populated via app status or workspace status mapping.
assert.NotEmpty(t, got.Status, "task status should not be empty")
})
@@ -321,7 +320,6 @@ func TestTasks(t *testing.T) {
assert.Equal(t, workspace.Name, task.Name, "task name should map from workspace name")
assert.Equal(t, wantPrompt, task.InitialPrompt, "task prompt should match the AI Prompt parameter")
assert.Equal(t, workspace.ID, task.WorkspaceID.UUID, "workspace id should match")
- assert.Equal(t, workspace.LatestBuild.ID, task.LatestBuildID.UUID, "latest build id should match")
assert.NotEmpty(t, task.Status, "task status should not be empty")
// Stop the workspace
diff --git a/codersdk/aitasks.go b/codersdk/aitasks.go
index e62f65ce95c49..21efb15b5313e 100644
--- a/codersdk/aitasks.go
+++ b/codersdk/aitasks.go
@@ -119,7 +119,6 @@ type Task struct {
WorkspaceAgentID uuid.NullUUID `json:"workspace_agent_id" format:"uuid" table:"workspace agent id"`
WorkspaceAgentLifecycle *WorkspaceAgentLifecycle `json:"workspace_agent_lifecycle" table:"workspace agent lifecycle"`
WorkspaceAgentHealth *WorkspaceAgentHealth `json:"workspace_agent_health" table:"workspace agent health"`
- LatestBuildID uuid.NullUUID `json:"latest_build_id" format:"uuid" table:"latest build id"`
InitialPrompt string `json:"initial_prompt" table:"initial prompt"`
Status WorkspaceStatus `json:"status" enums:"pending,starting,running,stopping,stopped,failed,canceling,canceled,deleting,deleted" table:"status"`
CurrentState *TaskStateEntry `json:"current_state" table:"cs,recursive_inline"`
diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts
index da2c6806a22ee..1e07cf1aa2895 100644
--- a/site/src/api/typesGenerated.ts
+++ b/site/src/api/typesGenerated.ts
@@ -3330,7 +3330,6 @@ export interface Task {
readonly workspace_agent_id: string | null;
readonly workspace_agent_lifecycle: WorkspaceAgentLifecycle | null;
readonly workspace_agent_health: WorkspaceAgentHealth | null;
- readonly latest_build_id: string | null;
readonly initial_prompt: string;
readonly status: WorkspaceStatus;
readonly current_state: TaskStateEntry | null;
diff --git a/site/src/testHelpers/entities.ts b/site/src/testHelpers/entities.ts
index d9a73bc16326d..0b8d87f8111ef 100644
--- a/site/src/testHelpers/entities.ts
+++ b/site/src/testHelpers/entities.ts
@@ -5031,7 +5031,6 @@ export const MockTask: TypesGen.Task = {
workspace_agent_id: MockWorkspaceAgent.id,
workspace_agent_lifecycle: MockWorkspaceAgent.lifecycle_state,
workspace_agent_health: MockWorkspaceAgent.health,
- latest_build_id: MockWorkspace.latest_build.id,
initial_prompt: "Perform some task",
status: "running",
current_state: {
From 09f69ef74f50f63308fb2366fdbb634143db5eb6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=82=B1=E3=82=A4=E3=83=A9?=
Date: Mon, 6 Oct 2025 12:14:35 -0600
Subject: [PATCH 068/298] chore: update logo on error page (#20185)
---
site/static/error.html | 44 +-----------------------------------
site/static/logo.svg | 4 ----
site/static/oauth2allow.html | 2 +-
3 files changed, 2 insertions(+), 48 deletions(-)
delete mode 100644 site/static/logo.svg
diff --git a/site/static/error.html b/site/static/error.html
index d0eee1bb4a402..d5ea5ab9dd790 100644
--- a/site/static/error.html
+++ b/site/static/error.html
@@ -119,49 +119,7 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
{{- if not .Error.HideStatus }}{{ .Error.Status }} - {{end}}{{
diff --git a/site/static/logo.svg b/site/static/logo.svg
deleted file mode 100644
index adf9f2e910090..0000000000000
--- a/site/static/logo.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-
- Coder logo
-
-
\ No newline at end of file
diff --git a/site/static/oauth2allow.html b/site/static/oauth2allow.html
index d1aa84ecd031d..313cac30dd05d 100644
--- a/site/static/oauth2allow.html
+++ b/site/static/oauth2allow.html
@@ -110,7 +110,7 @@
+
{{end}}
-
+
Authorize {{ .AppName }}
From 156f985fb0908f9e6d99ae5cc5f0c1d1360603e4 Mon Sep 17 00:00:00 2001
From: Michael Smith
Date: Mon, 6 Oct 2025 15:41:57 -0400
Subject: [PATCH 069/298] fix(site): update `useClipboard` to work better with
effect logic (#20183)
## Changes made
- Updated `useClipboard` API to require passing the text in via the
`copyToClipboard` function, rather than requiring that the text gets
specified in render logic
- Ensured that the `copyToClipboard` function always stays stable across
all React lifecycles
- Updated all existing uses to use the new function signatures
- Updated all tests and added new cases
---
site/src/components/CopyButton/CopyButton.tsx | 6 +-
.../CopyableValue/CopyableValue.tsx | 6 +-
site/src/hooks/useClickable.ts | 4 +-
site/src/hooks/useClipboard.test.tsx | 110 +++++++++++++++---
site/src/hooks/useClipboard.ts | 77 ++++++------
.../src/pages/CliAuthPage/CliAuthPageView.tsx | 15 +--
site/src/pages/TaskPage/TaskTopbar.tsx | 7 +-
.../TemplateEmbedPage/TemplateEmbedPage.tsx | 17 +--
.../TemplateEmbedPageExperimental.tsx | 18 +--
9 files changed, 173 insertions(+), 87 deletions(-)
diff --git a/site/src/components/CopyButton/CopyButton.tsx b/site/src/components/CopyButton/CopyButton.tsx
index 9110bb4cd68d0..c00b9360e4206 100644
--- a/site/src/components/CopyButton/CopyButton.tsx
+++ b/site/src/components/CopyButton/CopyButton.tsx
@@ -19,9 +19,7 @@ export const CopyButton: FC = ({
label,
...buttonProps
}) => {
- const { showCopiedSuccess, copyToClipboard } = useClipboard({
- textToCopy: text,
- });
+ const { showCopiedSuccess, copyToClipboard } = useClipboard();
return (
@@ -30,7 +28,7 @@ export const CopyButton: FC = ({
copyToClipboard(text)}
{...buttonProps}
>
{showCopiedSuccess ? : }
diff --git a/site/src/components/CopyableValue/CopyableValue.tsx b/site/src/components/CopyableValue/CopyableValue.tsx
index 1cd3ea4a15a49..92cb6ec3c4e42 100644
--- a/site/src/components/CopyableValue/CopyableValue.tsx
+++ b/site/src/components/CopyableValue/CopyableValue.tsx
@@ -16,10 +16,10 @@ export const CopyableValue: FC = ({
children,
...attrs
}) => {
- const { showCopiedSuccess, copyToClipboard } = useClipboard({
- textToCopy: value,
+ const { showCopiedSuccess, copyToClipboard } = useClipboard();
+ const clickableProps = useClickable(() => {
+ copyToClipboard(value);
});
- const clickableProps = useClickable(copyToClipboard);
return (
=> {
const ref = useRef(null);
+ const stableOnClick = useEffectEvent(onClick);
return {
ref,
- onClick,
+ onClick: stableOnClick,
tabIndex: 0,
role: (role ?? "button") as TRole,
diff --git a/site/src/hooks/useClipboard.test.tsx b/site/src/hooks/useClipboard.test.tsx
index 1d4d2eb702a81..156d70ab31593 100644
--- a/site/src/hooks/useClipboard.test.tsx
+++ b/site/src/hooks/useClipboard.test.tsx
@@ -9,9 +9,11 @@
* immediately pollutes the tests with false negatives. Even if something should
* fail, it won't.
*/
-import { act, renderHook, screen } from "@testing-library/react";
+
+import { renderHook, screen } from "@testing-library/react";
import { GlobalSnackbar } from "components/GlobalSnackbar/GlobalSnackbar";
import { ThemeOverride } from "contexts/ThemeProvider";
+import { act } from "react";
import themes, { DEFAULT_THEME } from "theme";
import {
COPY_FAILED_MESSAGE,
@@ -115,8 +117,8 @@ function setupMockClipboard(isSecure: boolean): SetupMockClipboardResult {
};
}
-function renderUseClipboard(inputs: TInput) {
- return renderHook(
+function renderUseClipboard(inputs?: UseClipboardInput) {
+ return renderHook(
(props) => useClipboard(props),
{
initialProps: inputs,
@@ -188,9 +190,9 @@ describe.each(secureContextValues)("useClipboard - secure: %j", (isSecure) => {
const assertClipboardUpdateLifecycle = async (
result: RenderResult,
- textToCheck: string,
+ textToCopy: string,
): Promise => {
- await act(() => result.current.copyToClipboard());
+ await act(() => result.current.copyToClipboard(textToCopy));
expect(result.current.showCopiedSuccess).toBe(true);
// Because of timing trickery, any timeouts for flipping the copy status
@@ -203,18 +205,18 @@ describe.each(secureContextValues)("useClipboard - secure: %j", (isSecure) => {
await act(() => jest.runAllTimersAsync());
const clipboardText = getClipboardText();
- expect(clipboardText).toEqual(textToCheck);
+ expect(clipboardText).toEqual(textToCopy);
};
it("Copies the current text to the user's clipboard", async () => {
const textToCopy = "dogs";
- const { result } = renderUseClipboard({ textToCopy });
+ const { result } = renderUseClipboard();
await assertClipboardUpdateLifecycle(result, textToCopy);
});
it("Should indicate to components not to show successful copy after a set period of time", async () => {
const textToCopy = "cats";
- const { result } = renderUseClipboard({ textToCopy });
+ const { result } = renderUseClipboard();
await assertClipboardUpdateLifecycle(result, textToCopy);
expect(result.current.showCopiedSuccess).toBe(false);
});
@@ -222,16 +224,16 @@ describe.each(secureContextValues)("useClipboard - secure: %j", (isSecure) => {
it("Should notify the user of an error using the provided callback", async () => {
const textToCopy = "birds";
const onError = jest.fn();
- const { result } = renderUseClipboard({ textToCopy, onError });
+ const { result } = renderUseClipboard({ onError });
setSimulateFailure(true);
- await act(() => result.current.copyToClipboard());
+ await act(() => result.current.copyToClipboard(textToCopy));
expect(onError).toBeCalled();
});
it("Should dispatch a new toast message to the global snackbar when errors happen while no error callback is provided to the hook", async () => {
const textToCopy = "crow";
- const { result } = renderUseClipboard({ textToCopy });
+ const { result } = renderUseClipboard();
/**
* @todo Look into why deferring error-based state updates to the global
@@ -241,7 +243,7 @@ describe.each(secureContextValues)("useClipboard - secure: %j", (isSecure) => {
* flushed through the GlobalSnackbar component afterwards
*/
setSimulateFailure(true);
- await act(() => result.current.copyToClipboard());
+ await act(() => result.current.copyToClipboard(textToCopy));
const errorMessageNode = screen.queryByText(COPY_FAILED_MESSAGE);
expect(errorMessageNode).not.toBeNull();
@@ -252,11 +254,91 @@ describe.each(secureContextValues)("useClipboard - secure: %j", (isSecure) => {
// Snackbar state transitions that you might get if the hook uses the
// default
const textToCopy = "hamster";
- const { result } = renderUseClipboard({ textToCopy, onError: jest.fn() });
+ const { result } = renderUseClipboard({ onError: jest.fn() });
+
+ setSimulateFailure(true);
+ await act(() => result.current.copyToClipboard(textToCopy));
+
+ expect(result.current.error).toBeInstanceOf(Error);
+ });
+ it("Clears out existing errors if a new copy operation succeeds", async () => {
+ const text = "dummy-text";
+ const { result } = renderUseClipboard();
setSimulateFailure(true);
- await act(() => result.current.copyToClipboard());
+ await act(() => result.current.copyToClipboard(text));
expect(result.current.error).toBeInstanceOf(Error);
+
+ setSimulateFailure(false);
+ await assertClipboardUpdateLifecycle(result, text);
+ expect(result.current.error).toBeUndefined();
+ });
+
+ // This test case is really important to ensure that it's easy to plop this
+ // inside of useEffect calls without having to think about dependencies too
+ // much
+ it("Ensures that the copyToClipboard function always maintains a stable reference across all re-renders", async () => {
+ const initialOnError = jest.fn();
+ const { result, rerender } = renderUseClipboard({
+ onError: initialOnError,
+ clearErrorOnSuccess: true,
+ });
+ const initialCopy = result.current.copyToClipboard;
+
+ // Re-render arbitrarily with no clipboard state transitions to make
+ // sure that a parent re-rendering doesn't break anything
+ rerender({ onError: initialOnError });
+ expect(result.current.copyToClipboard).toBe(initialCopy);
+
+ // Re-render with new onError prop and then swap back to simplify
+ // testing
+ rerender({ onError: jest.fn() });
+ expect(result.current.copyToClipboard).toBe(initialCopy);
+ rerender({ onError: initialOnError });
+
+ // Re-render with a new clear value then swap back to simplify testing
+ rerender({ onError: initialOnError, clearErrorOnSuccess: false });
+ expect(result.current.copyToClipboard).toBe(initialCopy);
+ rerender({ onError: initialOnError, clearErrorOnSuccess: true });
+
+ // Trigger a failed clipboard interaction
+ setSimulateFailure(true);
+ await act(() => result.current.copyToClipboard("dummy-text-2"));
+ expect(result.current.copyToClipboard).toBe(initialCopy);
+
+ /**
+ * Trigger a successful clipboard interaction
+ *
+ * @todo For some reason, using the assertClipboardUpdateLifecycle
+ * helper triggers Jest errors with it thinking that values are being
+ * accessed after teardown, even though the problem doesn't exist for
+ * any other test case.
+ *
+ * It's not a huge deal, because we only need to inspect React after the
+ * interaction, instead of the full DOM, but for correctness, it would
+ * be nice if we could get this issue figured out.
+ */
+ setSimulateFailure(false);
+ await act(() => result.current.copyToClipboard("dummy-text-2"));
+ expect(result.current.copyToClipboard).toBe(initialCopy);
+ });
+
+ it("Always uses the most up-to-date onError prop", async () => {
+ const initialOnError = jest.fn();
+ const { result, rerender } = renderUseClipboard({
+ onError: initialOnError,
+ });
+ setSimulateFailure(true);
+
+ const secondOnError = jest.fn();
+ rerender({ onError: secondOnError });
+ await act(() => result.current.copyToClipboard("dummy-text"));
+
+ expect(initialOnError).not.toHaveBeenCalled();
+ expect(secondOnError).toHaveBeenCalledTimes(1);
+ expect(secondOnError).toHaveBeenCalledWith(
+ "Failed to copy text to clipboard",
+ );
});
});
diff --git a/site/src/hooks/useClipboard.ts b/site/src/hooks/useClipboard.ts
index 1eb91cc356155..88a57a61fc05a 100644
--- a/site/src/hooks/useClipboard.ts
+++ b/site/src/hooks/useClipboard.ts
@@ -1,22 +1,18 @@
import { displayError } from "components/GlobalSnackbar/utils";
-import { useEffect, useRef, useState } from "react";
+import { useCallback, useEffect, useRef, useState } from "react";
+import { useEffectEvent } from "./hookPolyfills";
const CLIPBOARD_TIMEOUT_MS = 1_000;
export const COPY_FAILED_MESSAGE = "Failed to copy text to clipboard";
export const HTTP_FALLBACK_DATA_ID = "http-fallback";
export type UseClipboardInput = Readonly<{
- textToCopy: string;
-
- /**
- * Optional callback to call when an error happens. If not specified, the hook
- * will dispatch an error message to the GlobalSnackbar
- */
onError?: (errorMessage: string) => void;
+ clearErrorOnSuccess?: boolean;
}>;
export type UseClipboardResult = Readonly<{
- copyToClipboard: () => Promise;
+ copyToClipboard: (textToCopy: string) => Promise;
error: Error | undefined;
/**
@@ -40,47 +36,56 @@ export type UseClipboardResult = Readonly<{
showCopiedSuccess: boolean;
}>;
-export const useClipboard = (input: UseClipboardInput): UseClipboardResult => {
- const { textToCopy, onError: errorCallback } = input;
+export const useClipboard = (input?: UseClipboardInput): UseClipboardResult => {
+ const { onError = displayError, clearErrorOnSuccess = true } = input ?? {};
+
const [showCopiedSuccess, setShowCopiedSuccess] = useState(false);
const [error, setError] = useState();
const timeoutIdRef = useRef(undefined);
useEffect(() => {
- const clearIdOnUnmount = () => window.clearTimeout(timeoutIdRef.current);
- return clearIdOnUnmount;
+ const clearTimeoutOnUnmount = () => {
+ window.clearTimeout(timeoutIdRef.current);
+ };
+ return clearTimeoutOnUnmount;
}, []);
- const handleSuccessfulCopy = () => {
+ const stableOnError = useEffectEvent(() => onError(COPY_FAILED_MESSAGE));
+ const handleSuccessfulCopy = useEffectEvent(() => {
setShowCopiedSuccess(true);
+ if (clearErrorOnSuccess) {
+ setError(undefined);
+ }
+
timeoutIdRef.current = window.setTimeout(() => {
setShowCopiedSuccess(false);
}, CLIPBOARD_TIMEOUT_MS);
- };
-
- const copyToClipboard = async () => {
- try {
- await window.navigator.clipboard.writeText(textToCopy);
- handleSuccessfulCopy();
- } catch (err) {
- const fallbackCopySuccessful = simulateClipboardWrite(textToCopy);
- if (fallbackCopySuccessful) {
- handleSuccessfulCopy();
- return;
- }
+ });
- const wrappedErr = new Error(COPY_FAILED_MESSAGE);
- if (err instanceof Error) {
- wrappedErr.stack = err.stack;
+ const copyToClipboard = useCallback(
+ async (textToCopy: string) => {
+ try {
+ await window.navigator.clipboard.writeText(textToCopy);
+ handleSuccessfulCopy();
+ } catch (err) {
+ const fallbackCopySuccessful = simulateClipboardWrite(textToCopy);
+ if (fallbackCopySuccessful) {
+ handleSuccessfulCopy();
+ return;
+ }
+
+ const wrappedErr = new Error(COPY_FAILED_MESSAGE);
+ if (err instanceof Error) {
+ wrappedErr.stack = err.stack;
+ }
+
+ console.error(wrappedErr);
+ setError(wrappedErr);
+ stableOnError();
}
-
- console.error(wrappedErr);
- setError(wrappedErr);
-
- const notifyUser = errorCallback ?? displayError;
- notifyUser(COPY_FAILED_MESSAGE);
- }
- };
+ },
+ [stableOnError, handleSuccessfulCopy],
+ );
return { showCopiedSuccess, error, copyToClipboard };
};
diff --git a/site/src/pages/CliAuthPage/CliAuthPageView.tsx b/site/src/pages/CliAuthPage/CliAuthPageView.tsx
index e836127f61fc8..10df8b225ddbc 100644
--- a/site/src/pages/CliAuthPage/CliAuthPageView.tsx
+++ b/site/src/pages/CliAuthPage/CliAuthPageView.tsx
@@ -12,10 +12,7 @@ interface CliAuthPageViewProps {
}
export const CliAuthPageView: FC = ({ sessionToken }) => {
- const clipboard = useClipboard({
- textToCopy: sessionToken ?? "",
- });
-
+ const clipboardState = useClipboard();
return (
Session token
@@ -30,16 +27,20 @@ export const CliAuthPageView: FC = ({ sessionToken }) => {
className="w-full"
size="lg"
disabled={!sessionToken}
- onClick={clipboard.copyToClipboard}
+ onClick={() => {
+ if (sessionToken) {
+ clipboardState.copyToClipboard(sessionToken);
+ }
+ }}
>
- {clipboard.showCopiedSuccess ? (
+ {clipboardState.showCopiedSuccess ? (
) : (
)}
- {clipboard.showCopiedSuccess
+ {clipboardState.showCopiedSuccess
? "Session token copied!"
: "Copy session token"}
diff --git a/site/src/pages/TaskPage/TaskTopbar.tsx b/site/src/pages/TaskPage/TaskTopbar.tsx
index 1ad9ca5f0ff4c..989e1b6473416 100644
--- a/site/src/pages/TaskPage/TaskTopbar.tsx
+++ b/site/src/pages/TaskPage/TaskTopbar.tsx
@@ -81,14 +81,11 @@ export const TaskTopbar: FC = ({ task }) => {
type CopyPromptButtonProps = { prompt: string };
const CopyPromptButton: FC = ({ prompt }) => {
- const { copyToClipboard, showCopiedSuccess } = useClipboard({
- textToCopy: prompt,
- });
-
+ const { copyToClipboard, showCopiedSuccess } = useClipboard();
return (
copyToClipboard(prompt)}
size="sm"
variant="subtle"
className="p-0 min-w-0"
diff --git a/site/src/pages/TemplatePage/TemplateEmbedPage/TemplateEmbedPage.tsx b/site/src/pages/TemplatePage/TemplateEmbedPage/TemplateEmbedPage.tsx
index ee92303b5df23..8b50ef2447652 100644
--- a/site/src/pages/TemplatePage/TemplateEmbedPage/TemplateEmbedPage.tsx
+++ b/site/src/pages/TemplatePage/TemplateEmbedPage/TemplateEmbedPage.tsx
@@ -74,13 +74,7 @@ export const TemplateEmbedPageView: FC = ({
templateParameters,
}) => {
const [buttonValues, setButtonValues] = useState();
- const clipboard = useClipboard({
- textToCopy: getClipboardCopyContent(
- template.name,
- template.organization_name,
- buttonValues,
- ),
- });
+ const clipboard = useClipboard();
// template parameters is async so we need to initialize the values after it
// is loaded
@@ -237,8 +231,15 @@ export const TemplateEmbedPageView: FC = ({
>
{
+ const textToCopy = getClipboardCopyContent(
+ template.name,
+ template.organization_name,
+ buttonValues,
+ );
+ clipboard.copyToClipboard(textToCopy);
+ }}
>
{clipboard.showCopiedSuccess ? : }
Copy button code
diff --git a/site/src/pages/TemplatePage/TemplateEmbedPage/TemplateEmbedPageExperimental.tsx b/site/src/pages/TemplatePage/TemplateEmbedPage/TemplateEmbedPageExperimental.tsx
index a34d719f4c052..c9b63f1422478 100644
--- a/site/src/pages/TemplatePage/TemplateEmbedPage/TemplateEmbedPageExperimental.tsx
+++ b/site/src/pages/TemplatePage/TemplateEmbedPage/TemplateEmbedPageExperimental.tsx
@@ -289,14 +289,7 @@ interface ButtonPreviewProps {
}
const ButtonPreview: FC = ({ template, buttonValues }) => {
- const clipboard = useClipboard({
- textToCopy: getClipboardCopyContent(
- template.name,
- template.organization_name,
- buttonValues,
- ),
- });
-
+ const clipboard = useClipboard();
return (
{
+ const textToCopy = getClipboardCopyContent(
+ template.name,
+ template.organization_name,
+ buttonValues,
+ );
+ clipboard.copyToClipboard(textToCopy);
+ }}
>
{clipboard.showCopiedSuccess ? : }{" "}
Copy button code
From 05f8f67ced1468fed312757a9f3f8243511d609c Mon Sep 17 00:00:00 2001
From: Kacper Sawicki
Date: Tue, 7 Oct 2025 09:59:15 +0200
Subject: [PATCH 070/298] feat(scaletest): add runner for notifications
delivery (#20091)
Relates to https://github.com/coder/internal/issues/910
This PR adds a scaletest runner that simulates users receiving notifications through WebSocket connections.
An instance of this notification runner does the following:
1. Creates a user (optionally with specific roles like owner).
2. Connects to /api/v2/notifications/inbox/watch via WebSocket to receive notifications in real-time.
3. Waits for all other concurrently executing runners (per the DialBarrier WaitGroup) to also connect their websockets.
4. For receiving users: Watches the WebSocket for expected notifications and records delivery latency for each notification type.
5. For regular users: Maintains WebSocket connections to simulate concurrent load while receiving users wait for notifications.
6. Waits on the ReceivingWatchBarrier to coordinate between receiving and regular users.
7. Cleans up the created user after the test completes.
Exposes three prometheus metrics:
1. notification_delivery_latency_seconds - HistogramVec. Labels = {username, notification_type}
2. notification_delivery_errors_total - CounterVec. Labels = {username, action}
3. notification_delivery_missed_total - CounterVec. Labels = {username}
The runner measures end-to-end notification latency from when a notification-triggering event occurs (e.g., user creation/deletion) to when the notification is received by a WebSocket client.
---
scaletest/notifications/config.go | 71 ++++++++
scaletest/notifications/metrics.go | 58 ++++++
scaletest/notifications/run.go | 263 ++++++++++++++++++++++++++++
scaletest/notifications/run_test.go | 221 +++++++++++++++++++++++
4 files changed, 613 insertions(+)
create mode 100644 scaletest/notifications/config.go
create mode 100644 scaletest/notifications/metrics.go
create mode 100644 scaletest/notifications/run.go
create mode 100644 scaletest/notifications/run_test.go
diff --git a/scaletest/notifications/config.go b/scaletest/notifications/config.go
new file mode 100644
index 0000000000000..ac1c6da49a01b
--- /dev/null
+++ b/scaletest/notifications/config.go
@@ -0,0 +1,71 @@
+package notifications
+
+import (
+ "sync"
+ "time"
+
+ "golang.org/x/xerrors"
+
+ "github.com/google/uuid"
+
+ "github.com/coder/coder/v2/scaletest/createusers"
+)
+
+type Config struct {
+ // User is the configuration for the user to create.
+ User createusers.Config `json:"user"`
+
+ // Roles are the roles to assign to the user.
+ Roles []string `json:"roles"`
+
+ // NotificationTimeout is how long to wait for notifications after triggering.
+ NotificationTimeout time.Duration `json:"notification_timeout"`
+
+ // DialTimeout is how long to wait for websocket connection.
+ DialTimeout time.Duration `json:"dial_timeout"`
+
+ // ExpectedNotifications maps notification template IDs to channels
+ // that receive the trigger time for each notification.
+ ExpectedNotifications map[uuid.UUID]chan time.Time `json:"-"`
+
+ Metrics *Metrics `json:"-"`
+
+ // DialBarrier ensures all runners are connected before notifications are triggered.
+ DialBarrier *sync.WaitGroup `json:"-"`
+
+ // ReceivingWatchBarrier is the barrier for receiving users. Regular users wait on this to disconnect after receiving users complete.
+ ReceivingWatchBarrier *sync.WaitGroup `json:"-"`
+}
+
+func (c Config) Validate() error {
+ // The runner always needs an org; ensure we propagate it into the user config.
+ if c.User.OrganizationID == uuid.Nil {
+ return xerrors.New("user organization_id must be set")
+ }
+
+ if err := c.User.Validate(); err != nil {
+ return xerrors.Errorf("user config: %w", err)
+ }
+
+ if c.DialBarrier == nil {
+ return xerrors.New("dial barrier must be set")
+ }
+
+ if c.ReceivingWatchBarrier == nil {
+ return xerrors.New("receiving_watch_barrier must be set")
+ }
+
+ if c.NotificationTimeout <= 0 {
+ return xerrors.New("notification_timeout must be greater than 0")
+ }
+
+ if c.DialTimeout <= 0 {
+ return xerrors.New("dial_timeout must be greater than 0")
+ }
+
+ if c.Metrics == nil {
+ return xerrors.New("metrics must be set")
+ }
+
+ return nil
+}
diff --git a/scaletest/notifications/metrics.go b/scaletest/notifications/metrics.go
new file mode 100644
index 0000000000000..c9e7374250b24
--- /dev/null
+++ b/scaletest/notifications/metrics.go
@@ -0,0 +1,58 @@
+package notifications
+
+import (
+ "time"
+
+ "github.com/prometheus/client_golang/prometheus"
+)
+
+type Metrics struct {
+ notificationLatency *prometheus.HistogramVec
+ notificationErrors *prometheus.CounterVec
+ missedNotifications *prometheus.CounterVec
+}
+
+func NewMetrics(reg prometheus.Registerer) *Metrics {
+ if reg == nil {
+ reg = prometheus.DefaultRegisterer
+ }
+
+ latency := prometheus.NewHistogramVec(prometheus.HistogramOpts{
+ Namespace: "coderd",
+ Subsystem: "scaletest",
+ Name: "notification_delivery_latency_seconds",
+ Help: "Time between notification-creating action and receipt of notification by client",
+ }, []string{"username", "notification_type"})
+ errors := prometheus.NewCounterVec(prometheus.CounterOpts{
+ Namespace: "coderd",
+ Subsystem: "scaletest",
+ Name: "notification_delivery_errors_total",
+ Help: "Total number of notification delivery errors",
+ }, []string{"username", "action"})
+ missed := prometheus.NewCounterVec(prometheus.CounterOpts{
+ Namespace: "coderd",
+ Subsystem: "scaletest",
+ Name: "notification_delivery_missed_total",
+ Help: "Total number of missed notifications",
+ }, []string{"username"})
+
+ reg.MustRegister(latency, errors, missed)
+
+ return &Metrics{
+ notificationLatency: latency,
+ notificationErrors: errors,
+ missedNotifications: missed,
+ }
+}
+
+func (m *Metrics) RecordLatency(latency time.Duration, username, notificationType string) {
+ m.notificationLatency.WithLabelValues(username, notificationType).Observe(latency.Seconds())
+}
+
+func (m *Metrics) AddError(username, action string) {
+ m.notificationErrors.WithLabelValues(username, action).Inc()
+}
+
+func (m *Metrics) RecordMissed(username string) {
+ m.missedNotifications.WithLabelValues(username).Inc()
+}
diff --git a/scaletest/notifications/run.go b/scaletest/notifications/run.go
new file mode 100644
index 0000000000000..d3d68e78acb42
--- /dev/null
+++ b/scaletest/notifications/run.go
@@ -0,0 +1,263 @@
+package notifications
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "io"
+ "net/http"
+ "time"
+
+ "github.com/google/uuid"
+ "golang.org/x/xerrors"
+
+ "cdr.dev/slog"
+ "cdr.dev/slog/sloggers/sloghuman"
+
+ "github.com/coder/coder/v2/coderd/tracing"
+ "github.com/coder/coder/v2/codersdk"
+ "github.com/coder/coder/v2/scaletest/createusers"
+ "github.com/coder/coder/v2/scaletest/harness"
+ "github.com/coder/coder/v2/scaletest/loadtestutil"
+ "github.com/coder/websocket"
+)
+
+type Runner struct {
+ client *codersdk.Client
+ cfg Config
+
+ createUserRunner *createusers.Runner
+
+ // notificationLatencies stores the latency for each notification type
+ notificationLatencies map[uuid.UUID]time.Duration
+}
+
+func NewRunner(client *codersdk.Client, cfg Config) *Runner {
+ return &Runner{
+ client: client,
+ cfg: cfg,
+ notificationLatencies: make(map[uuid.UUID]time.Duration),
+ }
+}
+
+var (
+ _ harness.Runnable = &Runner{}
+ _ harness.Cleanable = &Runner{}
+ _ harness.Collectable = &Runner{}
+)
+
+func (r *Runner) Run(ctx context.Context, id string, logs io.Writer) error {
+ ctx, span := tracing.StartSpan(ctx)
+ defer span.End()
+
+ reachedBarrier := false
+ defer func() {
+ if !reachedBarrier {
+ r.cfg.DialBarrier.Done()
+ }
+ }()
+
+ reachedReceivingWatchBarrier := false
+ defer func() {
+ if len(r.cfg.ExpectedNotifications) > 0 && !reachedReceivingWatchBarrier {
+ r.cfg.ReceivingWatchBarrier.Done()
+ }
+ }()
+
+ logs = loadtestutil.NewSyncWriter(logs)
+ logger := slog.Make(sloghuman.Sink(logs)).Leveled(slog.LevelDebug)
+ r.client.SetLogger(logger)
+ r.client.SetLogBodies(true)
+
+ r.createUserRunner = createusers.NewRunner(r.client, r.cfg.User)
+ newUserAndToken, err := r.createUserRunner.RunReturningUser(ctx, id, logs)
+ if err != nil {
+ r.cfg.Metrics.AddError("", "create_user")
+ return xerrors.Errorf("create user: %w", err)
+ }
+ newUser := newUserAndToken.User
+ newUserClient := codersdk.New(r.client.URL,
+ codersdk.WithSessionToken(newUserAndToken.SessionToken),
+ codersdk.WithLogger(logger),
+ codersdk.WithLogBodies())
+
+ logger.Info(ctx, "runner user created", slog.F("username", newUser.Username), slog.F("user_id", newUser.ID.String()))
+
+ if len(r.cfg.Roles) > 0 {
+ logger.Info(ctx, "assigning roles to user", slog.F("roles", r.cfg.Roles))
+
+ _, err := r.client.UpdateUserRoles(ctx, newUser.ID.String(), codersdk.UpdateRoles{
+ Roles: r.cfg.Roles,
+ })
+ if err != nil {
+ r.cfg.Metrics.AddError(newUser.Username, "assign_roles")
+ return xerrors.Errorf("assign roles: %w", err)
+ }
+ }
+
+ logger.Info(ctx, "notification runner is ready")
+
+ dialCtx, cancel := context.WithTimeout(ctx, r.cfg.DialTimeout)
+ defer cancel()
+
+ logger.Info(ctx, "connecting to notification websocket")
+ conn, err := r.dialNotificationWebsocket(dialCtx, newUserClient, newUser, logger)
+ if err != nil {
+ return xerrors.Errorf("dial notification websocket: %w", err)
+ }
+ defer conn.Close(websocket.StatusNormalClosure, "done")
+ logger.Info(ctx, "connected to notification websocket")
+
+ reachedBarrier = true
+ r.cfg.DialBarrier.Done()
+ r.cfg.DialBarrier.Wait()
+
+ if len(r.cfg.ExpectedNotifications) == 0 {
+ logger.Info(ctx, "maintaining websocket connection, waiting for receiving users to complete")
+
+ // Wait for receiving users to complete
+ done := make(chan struct{})
+ go func() {
+ r.cfg.ReceivingWatchBarrier.Wait()
+ close(done)
+ }()
+
+ select {
+ case <-done:
+ logger.Info(ctx, "receiving users complete, closing connection")
+ case <-ctx.Done():
+ logger.Info(ctx, "context canceled, closing connection")
+ }
+ return nil
+ }
+
+ logger.Info(ctx, "waiting for notifications", slog.F("timeout", r.cfg.NotificationTimeout))
+
+ watchCtx, cancel := context.WithTimeout(ctx, r.cfg.NotificationTimeout)
+ defer cancel()
+
+ if err := r.watchNotifications(watchCtx, conn, newUser, logger, r.cfg.ExpectedNotifications); err != nil {
+ return xerrors.Errorf("notification watch failed: %w", err)
+ }
+
+ reachedReceivingWatchBarrier = true
+ r.cfg.ReceivingWatchBarrier.Done()
+
+ return nil
+}
+
+func (r *Runner) Cleanup(ctx context.Context, id string, logs io.Writer) error {
+ if r.createUserRunner != nil {
+ _, _ = fmt.Fprintln(logs, "Cleaning up user...")
+ if err := r.createUserRunner.Cleanup(ctx, id, logs); err != nil {
+ return xerrors.Errorf("cleanup user: %w", err)
+ }
+ }
+
+ return nil
+}
+
+const NotificationDeliveryLatencyMetric = "notification_delivery_latency_seconds"
+
+func (r *Runner) GetMetrics() map[string]any {
+ return map[string]any{
+ NotificationDeliveryLatencyMetric: r.notificationLatencies,
+ }
+}
+
+func (r *Runner) dialNotificationWebsocket(ctx context.Context, client *codersdk.Client, user codersdk.User, logger slog.Logger) (*websocket.Conn, error) {
+ u, err := client.URL.Parse("/api/v2/notifications/inbox/watch")
+ if err != nil {
+ logger.Error(ctx, "parse notification URL", slog.Error(err))
+ r.cfg.Metrics.AddError(user.Username, "parse_url")
+ return nil, xerrors.Errorf("parse notification URL: %w", err)
+ }
+
+ conn, resp, err := websocket.Dial(ctx, u.String(), &websocket.DialOptions{
+ HTTPHeader: http.Header{
+ "Coder-Session-Token": []string{client.SessionToken()},
+ },
+ })
+ if err != nil {
+ if resp != nil {
+ defer resp.Body.Close()
+ if resp.StatusCode != http.StatusSwitchingProtocols {
+ err = codersdk.ReadBodyAsError(resp)
+ }
+ }
+ logger.Error(ctx, "dial notification websocket", slog.Error(err))
+ r.cfg.Metrics.AddError(user.Username, "dial")
+ return nil, xerrors.Errorf("dial notification websocket: %w", err)
+ }
+
+ return conn, nil
+}
+
+// watchNotifications reads notifications from the websocket and returns error or nil
+// once all expected notifications are received.
+func (r *Runner) watchNotifications(ctx context.Context, conn *websocket.Conn, user codersdk.User, logger slog.Logger, expectedNotifications map[uuid.UUID]chan time.Time) error {
+ logger.Info(ctx, "waiting for notifications",
+ slog.F("username", user.Username),
+ slog.F("expected_count", len(expectedNotifications)))
+
+ receivedNotifications := make(map[uuid.UUID]struct{})
+
+ for {
+ select {
+ case <-ctx.Done():
+ return xerrors.Errorf("context canceled while waiting for notifications: %w", ctx.Err())
+ default:
+ }
+
+ if len(receivedNotifications) == len(expectedNotifications) {
+ logger.Info(ctx, "received all expected notifications")
+ return nil
+ }
+
+ notif, err := readNotification(ctx, conn)
+ if err != nil {
+ logger.Error(ctx, "read notification", slog.Error(err))
+ r.cfg.Metrics.AddError(user.Username, "read_notification")
+ return xerrors.Errorf("read notification: %w", err)
+ }
+
+ templateID := notif.Notification.TemplateID
+ if triggerTimeChan, exists := expectedNotifications[templateID]; exists {
+ if _, exists := receivedNotifications[templateID]; !exists {
+ receiptTime := time.Now()
+ select {
+ case triggerTime := <-triggerTimeChan:
+ latency := receiptTime.Sub(triggerTime)
+ r.notificationLatencies[templateID] = latency
+ r.cfg.Metrics.RecordLatency(latency, user.Username, templateID.String())
+ receivedNotifications[templateID] = struct{}{}
+
+ logger.Info(ctx, "received expected notification",
+ slog.F("template_id", templateID),
+ slog.F("title", notif.Notification.Title),
+ slog.F("latency", latency))
+ case <-ctx.Done():
+ return xerrors.Errorf("context canceled while waiting for trigger time: %w", ctx.Err())
+ }
+ }
+ } else {
+ logger.Debug(ctx, "received notification not being tested",
+ slog.F("template_id", templateID),
+ slog.F("title", notif.Notification.Title))
+ }
+ }
+}
+
+func readNotification(ctx context.Context, conn *websocket.Conn) (codersdk.GetInboxNotificationResponse, error) {
+ _, message, err := conn.Read(ctx)
+ if err != nil {
+ return codersdk.GetInboxNotificationResponse{}, err
+ }
+
+ var notif codersdk.GetInboxNotificationResponse
+ if err := json.Unmarshal(message, ¬if); err != nil {
+ return codersdk.GetInboxNotificationResponse{}, xerrors.Errorf("unmarshal notification: %w", err)
+ }
+
+ return notif, nil
+}
diff --git a/scaletest/notifications/run_test.go b/scaletest/notifications/run_test.go
new file mode 100644
index 0000000000000..e94e6d82eab56
--- /dev/null
+++ b/scaletest/notifications/run_test.go
@@ -0,0 +1,221 @@
+package notifications_test
+
+import (
+ "io"
+ "strconv"
+ "sync"
+ "testing"
+ "time"
+
+ "github.com/google/uuid"
+ "github.com/prometheus/client_golang/prometheus"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+ "golang.org/x/sync/errgroup"
+ "golang.org/x/xerrors"
+
+ "github.com/coder/serpent"
+
+ "github.com/coder/coder/v2/coderd/coderdtest"
+ "github.com/coder/coder/v2/coderd/database"
+ "github.com/coder/coder/v2/coderd/database/dbauthz"
+ "github.com/coder/coder/v2/coderd/database/dbtestutil"
+ notificationsLib "github.com/coder/coder/v2/coderd/notifications"
+ "github.com/coder/coder/v2/coderd/notifications/dispatch"
+ "github.com/coder/coder/v2/codersdk"
+ "github.com/coder/coder/v2/scaletest/createusers"
+ "github.com/coder/coder/v2/scaletest/notifications"
+ "github.com/coder/coder/v2/testutil"
+ "github.com/coder/quartz"
+)
+
+func TestRun(t *testing.T) {
+ t.Parallel()
+
+ ctx := testutil.Context(t, testutil.WaitLong)
+ logger := testutil.Logger(t)
+ db, ps := dbtestutil.NewDB(t)
+
+ // Setup notifications manager with inbox handler
+ cfg := defaultNotificationsConfig(database.NotificationMethodSmtp)
+ mgr, err := notificationsLib.NewManager(
+ cfg,
+ db,
+ ps,
+ defaultHelpers(),
+ notificationsLib.NewMetrics(prometheus.NewRegistry()),
+ logger.Named("manager"),
+ )
+ require.NoError(t, err)
+
+ mgr.WithHandlers(map[database.NotificationMethod]notificationsLib.Handler{
+ database.NotificationMethodInbox: dispatch.NewInboxHandler(logger.Named("inbox"), db, ps),
+ })
+ t.Cleanup(func() {
+ assert.NoError(t, mgr.Stop(dbauthz.AsNotifier(ctx)))
+ })
+ mgr.Run(dbauthz.AsNotifier(ctx))
+
+ enqueuer, err := notificationsLib.NewStoreEnqueuer(
+ cfg,
+ db,
+ defaultHelpers(),
+ logger.Named("enqueuer"),
+ quartz.NewReal(),
+ )
+ require.NoError(t, err)
+
+ client := coderdtest.New(t, &coderdtest.Options{
+ Database: db,
+ Pubsub: ps,
+ NotificationsEnqueuer: enqueuer,
+ })
+ firstUser := coderdtest.CreateFirstUser(t, client)
+
+ const numReceivingUsers = 2
+ const numRegularUsers = 2
+ dialBarrier := new(sync.WaitGroup)
+ receivingWatchBarrier := new(sync.WaitGroup)
+ dialBarrier.Add(numReceivingUsers + numRegularUsers)
+ receivingWatchBarrier.Add(numReceivingUsers)
+ metrics := notifications.NewMetrics(prometheus.NewRegistry())
+
+ eg, runCtx := errgroup.WithContext(ctx)
+
+ expectedNotifications := map[uuid.UUID]chan time.Time{
+ notificationsLib.TemplateUserAccountCreated: make(chan time.Time, 1),
+ notificationsLib.TemplateUserAccountDeleted: make(chan time.Time, 1),
+ }
+
+ // Start receiving runners who will receive notifications
+ receivingRunners := make([]*notifications.Runner, 0, numReceivingUsers)
+ for i := range numReceivingUsers {
+ runnerCfg := notifications.Config{
+ User: createusers.Config{
+ OrganizationID: firstUser.OrganizationID,
+ },
+ Roles: []string{codersdk.RoleOwner},
+ NotificationTimeout: testutil.WaitLong,
+ DialTimeout: testutil.WaitLong,
+ Metrics: metrics,
+ DialBarrier: dialBarrier,
+ ReceivingWatchBarrier: receivingWatchBarrier,
+ ExpectedNotifications: expectedNotifications,
+ }
+ err := runnerCfg.Validate()
+ require.NoError(t, err)
+
+ runner := notifications.NewRunner(client, runnerCfg)
+ receivingRunners = append(receivingRunners, runner)
+ eg.Go(func() error {
+ return runner.Run(runCtx, "receiving-"+strconv.Itoa(i), io.Discard)
+ })
+ }
+
+ // Start regular user runners who will maintain websocket connections
+ regularRunners := make([]*notifications.Runner, 0, numRegularUsers)
+ for i := range numRegularUsers {
+ runnerCfg := notifications.Config{
+ User: createusers.Config{
+ OrganizationID: firstUser.OrganizationID,
+ },
+ Roles: []string{},
+ NotificationTimeout: testutil.WaitLong,
+ DialTimeout: testutil.WaitLong,
+ Metrics: metrics,
+ DialBarrier: dialBarrier,
+ ReceivingWatchBarrier: receivingWatchBarrier,
+ }
+ err := runnerCfg.Validate()
+ require.NoError(t, err)
+
+ runner := notifications.NewRunner(client, runnerCfg)
+ regularRunners = append(regularRunners, runner)
+ eg.Go(func() error {
+ return runner.Run(runCtx, "regular-"+strconv.Itoa(i), io.Discard)
+ })
+ }
+
+ // Trigger notifications by creating and deleting a user
+ eg.Go(func() error {
+ // Wait for all runners to connect
+ dialBarrier.Wait()
+
+ createTime := time.Now()
+ newUser, err := client.CreateUserWithOrgs(runCtx, codersdk.CreateUserRequestWithOrgs{
+ OrganizationIDs: []uuid.UUID{firstUser.OrganizationID},
+ Email: "test-user@coder.com",
+ Username: "test-user",
+ Password: "SomeSecurePassword!",
+ })
+ if err != nil {
+ return xerrors.Errorf("create test user: %w", err)
+ }
+ expectedNotifications[notificationsLib.TemplateUserAccountCreated] <- createTime
+
+ deleteTime := time.Now()
+ if err := client.DeleteUser(runCtx, newUser.ID); err != nil {
+ return xerrors.Errorf("delete test user: %w", err)
+ }
+ expectedNotifications[notificationsLib.TemplateUserAccountDeleted] <- deleteTime
+
+ close(expectedNotifications[notificationsLib.TemplateUserAccountCreated])
+ close(expectedNotifications[notificationsLib.TemplateUserAccountDeleted])
+
+ return nil
+ })
+
+ err = eg.Wait()
+ require.NoError(t, err, "runner execution should complete successfully")
+
+ cleanupEg, cleanupCtx := errgroup.WithContext(ctx)
+ for i, runner := range receivingRunners {
+ cleanupEg.Go(func() error {
+ return runner.Cleanup(cleanupCtx, "receiving-"+strconv.Itoa(i), io.Discard)
+ })
+ }
+ for i, runner := range regularRunners {
+ cleanupEg.Go(func() error {
+ return runner.Cleanup(cleanupCtx, "regular-"+strconv.Itoa(i), io.Discard)
+ })
+ }
+ err = cleanupEg.Wait()
+ require.NoError(t, err)
+
+ users, err := client.Users(ctx, codersdk.UsersRequest{})
+ require.NoError(t, err)
+ require.Len(t, users.Users, 1)
+ require.Equal(t, firstUser.UserID, users.Users[0].ID)
+
+ for _, runner := range receivingRunners {
+ runnerMetrics := runner.GetMetrics()[notifications.NotificationDeliveryLatencyMetric].(map[uuid.UUID]time.Duration)
+ require.Contains(t, runnerMetrics, notificationsLib.TemplateUserAccountCreated)
+ require.Contains(t, runnerMetrics, notificationsLib.TemplateUserAccountDeleted)
+ }
+}
+
+func defaultNotificationsConfig(method database.NotificationMethod) codersdk.NotificationsConfig {
+ return codersdk.NotificationsConfig{
+ Method: serpent.String(method),
+ MaxSendAttempts: 5,
+ FetchInterval: serpent.Duration(time.Millisecond * 100),
+ StoreSyncInterval: serpent.Duration(time.Millisecond * 200),
+ LeasePeriod: serpent.Duration(time.Second * 10),
+ DispatchTimeout: serpent.Duration(time.Second * 5),
+ RetryInterval: serpent.Duration(time.Millisecond * 50),
+ LeaseCount: 10,
+ StoreSyncBufferSize: 50,
+ Inbox: codersdk.NotificationsInboxConfig{
+ Enabled: serpent.Bool(true),
+ },
+ }
+}
+
+func defaultHelpers() map[string]any {
+ return map[string]any{
+ "base_url": func() string { return "http://test.com" },
+ "current_year": func() string { return "2024" },
+ "logo_url": func() string { return "https://coder.com/coder-logo-horizontal.png" },
+ "app_name": func() string { return "Coder" },
+ }
+}
From 0c2eca94f5983b66eef9758775059c5c1fdaf829 Mon Sep 17 00:00:00 2001
From: Kacper Sawicki
Date: Tue, 7 Oct 2025 10:33:52 +0200
Subject: [PATCH 071/298] feat(cli): add `notifications` scaletest command
(#20092)
Closes https://github.com/coder/internal/issues/984
---
cli/exp_scaletest.go | 323 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 323 insertions(+)
diff --git a/cli/exp_scaletest.go b/cli/exp_scaletest.go
index e6a3993035512..126a0527dfa01 100644
--- a/cli/exp_scaletest.go
+++ b/cli/exp_scaletest.go
@@ -29,6 +29,7 @@ import (
"github.com/coder/coder/v2/cli/cliui"
"github.com/coder/coder/v2/coderd/httpapi"
+ notificationsLib "github.com/coder/coder/v2/coderd/notifications"
"github.com/coder/coder/v2/coderd/tracing"
"github.com/coder/coder/v2/codersdk"
"github.com/coder/coder/v2/codersdk/workspacesdk"
@@ -39,6 +40,7 @@ import (
"github.com/coder/coder/v2/scaletest/dashboard"
"github.com/coder/coder/v2/scaletest/harness"
"github.com/coder/coder/v2/scaletest/loadtestutil"
+ "github.com/coder/coder/v2/scaletest/notifications"
"github.com/coder/coder/v2/scaletest/reconnectingpty"
"github.com/coder/coder/v2/scaletest/workspacebuild"
"github.com/coder/coder/v2/scaletest/workspacetraffic"
@@ -62,6 +64,7 @@ func (r *RootCmd) scaletestCmd() *serpent.Command {
r.scaletestWorkspaceUpdates(),
r.scaletestWorkspaceTraffic(),
r.scaletestAutostart(),
+ r.scaletestNotifications(),
},
}
@@ -1917,6 +1920,259 @@ func (r *RootCmd) scaletestAutostart() *serpent.Command {
return cmd
}
+func (r *RootCmd) scaletestNotifications() *serpent.Command {
+ var (
+ userCount int64
+ ownerUserPercentage float64
+ notificationTimeout time.Duration
+ dialTimeout time.Duration
+ noCleanup bool
+
+ tracingFlags = &scaletestTracingFlags{}
+
+ // This test requires unlimited concurrency.
+ timeoutStrategy = &timeoutFlags{}
+ cleanupStrategy = newScaletestCleanupStrategy()
+ output = &scaletestOutputFlags{}
+ prometheusFlags = &scaletestPrometheusFlags{}
+ )
+
+ cmd := &serpent.Command{
+ Use: "notifications",
+ Short: "Simulate notification delivery by creating many users listening to notifications.",
+ Handler: func(inv *serpent.Invocation) error {
+ ctx := inv.Context()
+ client, err := r.InitClient(inv)
+ if err != nil {
+ return err
+ }
+
+ notifyCtx, stop := signal.NotifyContext(ctx, StopSignals...)
+ defer stop()
+ ctx = notifyCtx
+
+ me, err := requireAdmin(ctx, client)
+ if err != nil {
+ return err
+ }
+
+ client.HTTPClient = &http.Client{
+ Transport: &codersdk.HeaderTransport{
+ Transport: http.DefaultTransport,
+ Header: map[string][]string{
+ codersdk.BypassRatelimitHeader: {"true"},
+ },
+ },
+ }
+
+ if userCount <= 0 {
+ return xerrors.Errorf("--user-count must be greater than 0")
+ }
+
+ if ownerUserPercentage < 0 || ownerUserPercentage > 100 {
+ return xerrors.Errorf("--owner-user-percentage must be between 0 and 100")
+ }
+
+ ownerUserCount := int64(float64(userCount) * ownerUserPercentage / 100)
+ if ownerUserCount == 0 && ownerUserPercentage > 0 {
+ ownerUserCount = 1
+ }
+ regularUserCount := userCount - ownerUserCount
+
+ _, _ = fmt.Fprintf(inv.Stderr, "Distribution plan:\n")
+ _, _ = fmt.Fprintf(inv.Stderr, " Total users: %d\n", userCount)
+ _, _ = fmt.Fprintf(inv.Stderr, " Owner users: %d (%.1f%%)\n", ownerUserCount, ownerUserPercentage)
+ _, _ = fmt.Fprintf(inv.Stderr, " Regular users: %d (%.1f%%)\n", regularUserCount, 100.0-ownerUserPercentage)
+
+ outputs, err := output.parse()
+ if err != nil {
+ return xerrors.Errorf("could not parse --output flags")
+ }
+
+ tracerProvider, closeTracing, tracingEnabled, err := tracingFlags.provider(ctx)
+ if err != nil {
+ return xerrors.Errorf("create tracer provider: %w", err)
+ }
+ tracer := tracerProvider.Tracer(scaletestTracerName)
+
+ reg := prometheus.NewRegistry()
+ metrics := notifications.NewMetrics(reg)
+
+ logger := inv.Logger
+ prometheusSrvClose := ServeHandler(ctx, logger, promhttp.HandlerFor(reg, promhttp.HandlerOpts{}), prometheusFlags.Address, "prometheus")
+ defer prometheusSrvClose()
+
+ defer func() {
+ _, _ = fmt.Fprintln(inv.Stderr, "\nUploading traces...")
+ if err := closeTracing(ctx); err != nil {
+ _, _ = fmt.Fprintf(inv.Stderr, "\nError uploading traces: %+v\n", err)
+ }
+ // Wait for prometheus metrics to be scraped
+ _, _ = fmt.Fprintf(inv.Stderr, "Waiting %s for prometheus metrics to be scraped\n", prometheusFlags.Wait)
+ <-time.After(prometheusFlags.Wait)
+ }()
+
+ _, _ = fmt.Fprintln(inv.Stderr, "Creating users...")
+
+ dialBarrier := &sync.WaitGroup{}
+ ownerWatchBarrier := &sync.WaitGroup{}
+ dialBarrier.Add(int(userCount))
+ ownerWatchBarrier.Add(int(ownerUserCount))
+
+ expectedNotifications := map[uuid.UUID]chan time.Time{
+ notificationsLib.TemplateUserAccountCreated: make(chan time.Time, 1),
+ notificationsLib.TemplateUserAccountDeleted: make(chan time.Time, 1),
+ }
+
+ configs := make([]notifications.Config, 0, userCount)
+ for range ownerUserCount {
+ config := notifications.Config{
+ User: createusers.Config{
+ OrganizationID: me.OrganizationIDs[0],
+ },
+ Roles: []string{codersdk.RoleOwner},
+ NotificationTimeout: notificationTimeout,
+ DialTimeout: dialTimeout,
+ DialBarrier: dialBarrier,
+ ReceivingWatchBarrier: ownerWatchBarrier,
+ ExpectedNotifications: expectedNotifications,
+ Metrics: metrics,
+ }
+ if err := config.Validate(); err != nil {
+ return xerrors.Errorf("validate config: %w", err)
+ }
+ configs = append(configs, config)
+ }
+ for range regularUserCount {
+ config := notifications.Config{
+ User: createusers.Config{
+ OrganizationID: me.OrganizationIDs[0],
+ },
+ Roles: []string{},
+ NotificationTimeout: notificationTimeout,
+ DialTimeout: dialTimeout,
+ DialBarrier: dialBarrier,
+ ReceivingWatchBarrier: ownerWatchBarrier,
+ Metrics: metrics,
+ }
+ if err := config.Validate(); err != nil {
+ return xerrors.Errorf("validate config: %w", err)
+ }
+ configs = append(configs, config)
+ }
+
+ go triggerUserNotifications(
+ ctx,
+ logger,
+ client,
+ me.OrganizationIDs[0],
+ dialBarrier,
+ dialTimeout,
+ expectedNotifications,
+ )
+
+ th := harness.NewTestHarness(timeoutStrategy.wrapStrategy(harness.ConcurrentExecutionStrategy{}), cleanupStrategy.toStrategy())
+
+ for i, config := range configs {
+ id := strconv.Itoa(i)
+ name := fmt.Sprintf("notifications-%s", id)
+ var runner harness.Runnable = notifications.NewRunner(client, config)
+ if tracingEnabled {
+ runner = &runnableTraceWrapper{
+ tracer: tracer,
+ spanName: name,
+ runner: runner,
+ }
+ }
+
+ th.AddRun(name, id, runner)
+ }
+
+ _, _ = fmt.Fprintln(inv.Stderr, "Running notification delivery scaletest...")
+ testCtx, testCancel := timeoutStrategy.toContext(ctx)
+ defer testCancel()
+ err = th.Run(testCtx)
+ if err != nil {
+ return xerrors.Errorf("run test harness (harness failure, not a test failure): %w", err)
+ }
+
+ // If the command was interrupted, skip stats.
+ if notifyCtx.Err() != nil {
+ return notifyCtx.Err()
+ }
+
+ res := th.Results()
+ for _, o := range outputs {
+ err = o.write(res, inv.Stdout)
+ if err != nil {
+ return xerrors.Errorf("write output %q to %q: %w", o.format, o.path, err)
+ }
+ }
+
+ if !noCleanup {
+ _, _ = fmt.Fprintln(inv.Stderr, "\nCleaning up...")
+ cleanupCtx, cleanupCancel := cleanupStrategy.toContext(ctx)
+ defer cleanupCancel()
+ err = th.Cleanup(cleanupCtx)
+ if err != nil {
+ return xerrors.Errorf("cleanup tests: %w", err)
+ }
+ }
+
+ if res.TotalFail > 0 {
+ return xerrors.New("load test failed, see above for more details")
+ }
+
+ return nil
+ },
+ }
+
+ cmd.Options = serpent.OptionSet{
+ {
+ Flag: "user-count",
+ FlagShorthand: "c",
+ Env: "CODER_SCALETEST_NOTIFICATION_USER_COUNT",
+ Description: "Required: Total number of users to create.",
+ Value: serpent.Int64Of(&userCount),
+ Required: true,
+ },
+ {
+ Flag: "owner-user-percentage",
+ Env: "CODER_SCALETEST_NOTIFICATION_OWNER_USER_PERCENTAGE",
+ Default: "20.0",
+ Description: "Percentage of users to assign Owner role to (0-100).",
+ Value: serpent.Float64Of(&ownerUserPercentage),
+ },
+ {
+ Flag: "notification-timeout",
+ Env: "CODER_SCALETEST_NOTIFICATION_TIMEOUT",
+ Default: "5m",
+ Description: "How long to wait for notifications after triggering.",
+ Value: serpent.DurationOf(¬ificationTimeout),
+ },
+ {
+ Flag: "dial-timeout",
+ Env: "CODER_SCALETEST_DIAL_TIMEOUT",
+ Default: "2m",
+ Description: "Timeout for dialing the notification websocket endpoint.",
+ Value: serpent.DurationOf(&dialTimeout),
+ },
+ {
+ Flag: "no-cleanup",
+ Env: "CODER_SCALETEST_NO_CLEANUP",
+ Description: "Do not clean up resources after the test completes.",
+ Value: serpent.BoolOf(&noCleanup),
+ },
+ }
+
+ tracingFlags.attach(&cmd.Options)
+ timeoutStrategy.attach(&cmd.Options)
+ cleanupStrategy.attach(&cmd.Options)
+ output.attach(&cmd.Options)
+ prometheusFlags.attach(&cmd.Options)
+ return cmd
+}
+
type runnableTraceWrapper struct {
tracer trace.Tracer
spanName string
@@ -2117,6 +2373,73 @@ func parseTargetRange(name, targets string) (start, end int, err error) {
return start, end, nil
}
+// triggerUserNotifications waits for all test users to connect,
+// then creates and deletes a test user to trigger notification events for testing.
+func triggerUserNotifications(
+ ctx context.Context,
+ logger slog.Logger,
+ client *codersdk.Client,
+ orgID uuid.UUID,
+ dialBarrier *sync.WaitGroup,
+ dialTimeout time.Duration,
+ expectedNotifications map[uuid.UUID]chan time.Time,
+) {
+ logger.Info(ctx, "waiting for all users to connect")
+
+ // Wait for all users to connect
+ waitCtx, cancel := context.WithTimeout(ctx, dialTimeout+30*time.Second)
+ defer cancel()
+
+ done := make(chan struct{})
+ go func() {
+ dialBarrier.Wait()
+ close(done)
+ }()
+
+ select {
+ case <-done:
+ logger.Info(ctx, "all users connected")
+ case <-waitCtx.Done():
+ if waitCtx.Err() == context.DeadlineExceeded {
+ logger.Error(ctx, "timeout waiting for users to connect")
+ } else {
+ logger.Info(ctx, "context canceled while waiting for users")
+ }
+ return
+ }
+
+ const (
+ triggerUsername = "scaletest-trigger-user"
+ triggerEmail = "scaletest-trigger@example.com"
+ )
+
+ logger.Info(ctx, "creating test user to test notifications",
+ slog.F("username", triggerUsername),
+ slog.F("email", triggerEmail),
+ slog.F("org_id", orgID))
+
+ testUser, err := client.CreateUserWithOrgs(ctx, codersdk.CreateUserRequestWithOrgs{
+ OrganizationIDs: []uuid.UUID{orgID},
+ Username: triggerUsername,
+ Email: triggerEmail,
+ Password: "test-password-123",
+ })
+ if err != nil {
+ logger.Error(ctx, "create test user", slog.Error(err))
+ return
+ }
+ expectedNotifications[notificationsLib.TemplateUserAccountCreated] <- time.Now()
+
+ err = client.DeleteUser(ctx, testUser.ID)
+ if err != nil {
+ logger.Error(ctx, "delete test user", slog.Error(err))
+ return
+ }
+ expectedNotifications[notificationsLib.TemplateUserAccountDeleted] <- time.Now()
+ close(expectedNotifications[notificationsLib.TemplateUserAccountCreated])
+ close(expectedNotifications[notificationsLib.TemplateUserAccountDeleted])
+}
+
func createWorkspaceAppConfig(client *codersdk.Client, appHost, app string, workspace codersdk.Workspace, agent codersdk.WorkspaceAgent) (workspacetraffic.AppConfig, error) {
if app == "" {
return workspacetraffic.AppConfig{}, nil
From 6b72ef8b1806777db8768cba0b8e10b9119799fd Mon Sep 17 00:00:00 2001
From: Susana Ferreira
Date: Tue, 7 Oct 2025 11:32:44 +0100
Subject: [PATCH 072/298] chore(docs): update notifications documentation to
include task events (#20190)
## Description
Update notifications documentation to include Task Events introduced in
PR: https://github.com/coder/coder/pull/19965
---
docs/admin/monitoring/notifications/index.md | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/docs/admin/monitoring/notifications/index.md b/docs/admin/monitoring/notifications/index.md
index e87a4dd1ac27d..b1461cfec58a6 100644
--- a/docs/admin/monitoring/notifications/index.md
+++ b/docs/admin/monitoring/notifications/index.md
@@ -14,6 +14,13 @@ user(s) of the event.
Coder supports the following list of events:
+### Task Events
+
+These notifications are sent to the owner of the workspace where the task is running:
+
+- Task Idle
+- Task Working
+
### Template Events
These notifications are sent to users with **template admin** roles:
From 057d7dacdc36cede265865c0282bfaf80e83f755 Mon Sep 17 00:00:00 2001
From: Mathias Fredriksson
Date: Tue, 7 Oct 2025 16:10:38 +0300
Subject: [PATCH 073/298] chore(coderd/database/queries): remove trailing
whitespace (#20192)
---
coderd/database/queries.sql.go | 32 +++++++++----------
.../database/queries/provisionerdaemons.sql | 2 +-
.../database/queries/provisionerjoblogs.sql | 16 +++++-----
coderd/database/queries/provisionerkeys.sql | 6 ++--
coderd/database/queries/testadmin.sql | 10 +++---
.../database/queries/workspaceagentstats.sql | 2 +-
6 files changed, 34 insertions(+), 34 deletions(-)
diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go
index 3612375b8b26c..605db1cffe777 100644
--- a/coderd/database/queries.sql.go
+++ b/coderd/database/queries.sql.go
@@ -8966,7 +8966,7 @@ WHERE
-- Filter by max age if provided
AND (
$7::bigint IS NULL
- OR pd.last_seen_at IS NULL
+ OR pd.last_seen_at IS NULL
OR pd.last_seen_at >= (NOW() - ($7::bigint || ' ms')::interval)
)
AND (
@@ -9291,11 +9291,11 @@ func (q *sqlQuerier) InsertProvisionerJobLogs(ctx context.Context, arg InsertPro
}
const updateProvisionerJobLogsLength = `-- name: UpdateProvisionerJobLogsLength :exec
-UPDATE
+UPDATE
provisioner_jobs
-SET
+SET
logs_length = logs_length + $2
-WHERE
+WHERE
id = $1
`
@@ -9310,11 +9310,11 @@ func (q *sqlQuerier) UpdateProvisionerJobLogsLength(ctx context.Context, arg Upd
}
const updateProvisionerJobLogsOverflowed = `-- name: UpdateProvisionerJobLogsOverflowed :exec
-UPDATE
+UPDATE
provisioner_jobs
-SET
+SET
logs_overflowed = $2
-WHERE
+WHERE
id = $1
`
@@ -10376,7 +10376,7 @@ FROM
provisioner_keys
WHERE
organization_id = $1
-AND
+AND
lower(name) = lower($2)
`
@@ -10492,10 +10492,10 @@ WHERE
AND
-- exclude reserved built-in key
id != '00000000-0000-0000-0000-000000000001'::uuid
-AND
+AND
-- exclude reserved user-auth key
id != '00000000-0000-0000-0000-000000000002'::uuid
-AND
+AND
-- exclude reserved psk key
id != '00000000-0000-0000-0000-000000000003'::uuid
`
@@ -14289,14 +14289,14 @@ DO $$
DECLARE
table_record record;
BEGIN
- FOR table_record IN
- SELECT table_schema, table_name
- FROM information_schema.tables
+ FOR table_record IN
+ SELECT table_schema, table_name
+ FROM information_schema.tables
WHERE table_schema NOT IN ('pg_catalog', 'information_schema')
AND table_type = 'BASE TABLE'
LOOP
- EXECUTE format('ALTER TABLE %I.%I DISABLE TRIGGER ALL',
- table_record.table_schema,
+ EXECUTE format('ALTER TABLE %I.%I DISABLE TRIGGER ALL',
+ table_record.table_schema,
table_record.table_name);
END LOOP;
END;
@@ -18281,7 +18281,7 @@ WITH agent_stats AS (
coalesce((PERCENTILE_CONT(0.95) WITHIN GROUP (ORDER BY connection_median_latency_ms)), -1)::FLOAT AS workspace_connection_latency_95
FROM workspace_agent_stats
-- The greater than 0 is to support legacy agents that don't report connection_median_latency_ms.
- WHERE workspace_agent_stats.created_at > $1 AND connection_median_latency_ms > 0
+ WHERE workspace_agent_stats.created_at > $1 AND connection_median_latency_ms > 0
GROUP BY user_id, agent_id, workspace_id, template_id
), latest_agent_stats AS (
SELECT
diff --git a/coderd/database/queries/provisionerdaemons.sql b/coderd/database/queries/provisionerdaemons.sql
index ad6c0948eb448..03997c504cb1a 100644
--- a/coderd/database/queries/provisionerdaemons.sql
+++ b/coderd/database/queries/provisionerdaemons.sql
@@ -113,7 +113,7 @@ WHERE
-- Filter by max age if provided
AND (
sqlc.narg('max_age_ms')::bigint IS NULL
- OR pd.last_seen_at IS NULL
+ OR pd.last_seen_at IS NULL
OR pd.last_seen_at >= (NOW() - (sqlc.narg('max_age_ms')::bigint || ' ms')::interval)
)
AND (
diff --git a/coderd/database/queries/provisionerjoblogs.sql b/coderd/database/queries/provisionerjoblogs.sql
index c0ef188bdd382..14b9ccda9b1ff 100644
--- a/coderd/database/queries/provisionerjoblogs.sql
+++ b/coderd/database/queries/provisionerjoblogs.sql
@@ -19,19 +19,19 @@ SELECT
unnest(@level :: log_level [ ]) AS LEVEL,
unnest(@stage :: VARCHAR(128) [ ]) AS stage,
unnest(@output :: VARCHAR(1024) [ ]) AS output RETURNING *;
-
+
-- name: UpdateProvisionerJobLogsOverflowed :exec
-UPDATE
+UPDATE
provisioner_jobs
-SET
+SET
logs_overflowed = $2
-WHERE
+WHERE
id = $1;
-
+
-- name: UpdateProvisionerJobLogsLength :exec
-UPDATE
+UPDATE
provisioner_jobs
-SET
+SET
logs_length = logs_length + $2
-WHERE
+WHERE
id = $1;
diff --git a/coderd/database/queries/provisionerkeys.sql b/coderd/database/queries/provisionerkeys.sql
index 3fb05a8d0f613..0bf95069ddfe6 100644
--- a/coderd/database/queries/provisionerkeys.sql
+++ b/coderd/database/queries/provisionerkeys.sql
@@ -34,7 +34,7 @@ FROM
provisioner_keys
WHERE
organization_id = $1
-AND
+AND
lower(name) = lower(@name);
-- name: ListProvisionerKeysByOrganizationExcludeReserved :many
@@ -47,10 +47,10 @@ WHERE
AND
-- exclude reserved built-in key
id != '00000000-0000-0000-0000-000000000001'::uuid
-AND
+AND
-- exclude reserved user-auth key
id != '00000000-0000-0000-0000-000000000002'::uuid
-AND
+AND
-- exclude reserved psk key
id != '00000000-0000-0000-0000-000000000003'::uuid;
diff --git a/coderd/database/queries/testadmin.sql b/coderd/database/queries/testadmin.sql
index 77d39ce52768c..9cbaf67d2273c 100644
--- a/coderd/database/queries/testadmin.sql
+++ b/coderd/database/queries/testadmin.sql
@@ -6,14 +6,14 @@ DO $$
DECLARE
table_record record;
BEGIN
- FOR table_record IN
- SELECT table_schema, table_name
- FROM information_schema.tables
+ FOR table_record IN
+ SELECT table_schema, table_name
+ FROM information_schema.tables
WHERE table_schema NOT IN ('pg_catalog', 'information_schema')
AND table_type = 'BASE TABLE'
LOOP
- EXECUTE format('ALTER TABLE %I.%I DISABLE TRIGGER ALL',
- table_record.table_schema,
+ EXECUTE format('ALTER TABLE %I.%I DISABLE TRIGGER ALL',
+ table_record.table_schema,
table_record.table_name);
END LOOP;
END;
diff --git a/coderd/database/queries/workspaceagentstats.sql b/coderd/database/queries/workspaceagentstats.sql
index f2f2bdbe2824e..9c49b281f6e87 100644
--- a/coderd/database/queries/workspaceagentstats.sql
+++ b/coderd/database/queries/workspaceagentstats.sql
@@ -189,7 +189,7 @@ WITH agent_stats AS (
coalesce((PERCENTILE_CONT(0.95) WITHIN GROUP (ORDER BY connection_median_latency_ms)), -1)::FLOAT AS workspace_connection_latency_95
FROM workspace_agent_stats
-- The greater than 0 is to support legacy agents that don't report connection_median_latency_ms.
- WHERE workspace_agent_stats.created_at > $1 AND connection_median_latency_ms > 0
+ WHERE workspace_agent_stats.created_at > $1 AND connection_median_latency_ms > 0
GROUP BY user_id, agent_id, workspace_id, template_id
), latest_agent_stats AS (
SELECT
From 0e0f0925e410a4e700d5eb6f3aaeffda656569b3 Mon Sep 17 00:00:00 2001
From: Dean Sheather
Date: Wed, 8 Oct 2025 00:48:17 +1100
Subject: [PATCH 074/298] fix: use raw SVG for logo on static error page
(#20189)
Relates to #20185, #20029, #18878
---
site/static/error.html | 25 +++++++++++++++++++++----
1 file changed, 21 insertions(+), 4 deletions(-)
diff --git a/site/static/error.html b/site/static/error.html
index d5ea5ab9dd790..405ee59d48b60 100644
--- a/site/static/error.html
+++ b/site/static/error.html
@@ -1,6 +1,12 @@
-{{/* This template is used by application handlers to render friendly error
-pages when there is a proxy error (for example, when the target app isn't
-running). */}}
+{{/*
+ This template is used by application handlers to render friendly error pages
+ when there is a proxy error (for example, when the target app isn't running).
+
+ Since it is served from subdomains, both on proxies and the primary, it MUST
+ NOT access any external resources. It must be entirely self-contained. This
+ includes anything in `/static` or `/icon`, as these are not served from
+ subdomains.
+*/}}
@@ -119,7 +125,18 @@
-
+ {{/*
+ DO NOT LOAD AN EXTERNAL IMAGE HERE. See the comment at the top of
+ this file for more details.
+ */}}
+
+
+
{{- if not .Error.HideStatus }}{{ .Error.Status }} - {{end}}{{
From 65335bc7d437ba54bd1d48d71bdfd850eb9b470f Mon Sep 17 00:00:00 2001
From: Spike Curtis
Date: Tue, 7 Oct 2025 21:53:59 +0400
Subject: [PATCH 075/298] feat: add cli command scaletest dynamic-parameters
(#20034)
part of https://github.com/coder/internal/issues/912
Adds CLI command `coder exp scaletest dynamic-parameters`
I've left out the configuration of tracing and timeouts for now. I think I want to do some refactoring of the scaletest CLI to make handling those flags take up less boiler plate.
I will add tracing and timeout flags in a follow up PR.
---
cli/exp_scaletest.go | 1 +
cli/exp_scaletest_dynamicparameters.go | 110 +++++++
codersdk/client.go | 10 +
scaletest/dynamicparameters/config.go | 1 -
scaletest/dynamicparameters/run.go | 6 +-
scaletest/dynamicparameters/run_test.go | 1 -
scaletest/dynamicparameters/template.go | 285 +++++++++++++++++
.../template_internal_test.go | 293 ++++++++++++++++++
8 files changed, 700 insertions(+), 7 deletions(-)
create mode 100644 cli/exp_scaletest_dynamicparameters.go
create mode 100644 scaletest/dynamicparameters/template_internal_test.go
diff --git a/cli/exp_scaletest.go b/cli/exp_scaletest.go
index 126a0527dfa01..fc21d47fdb7c7 100644
--- a/cli/exp_scaletest.go
+++ b/cli/exp_scaletest.go
@@ -60,6 +60,7 @@ func (r *RootCmd) scaletestCmd() *serpent.Command {
Children: []*serpent.Command{
r.scaletestCleanup(),
r.scaletestDashboard(),
+ r.scaletestDynamicParameters(),
r.scaletestCreateWorkspaces(),
r.scaletestWorkspaceUpdates(),
r.scaletestWorkspaceTraffic(),
diff --git a/cli/exp_scaletest_dynamicparameters.go b/cli/exp_scaletest_dynamicparameters.go
new file mode 100644
index 0000000000000..fc0b949c9106e
--- /dev/null
+++ b/cli/exp_scaletest_dynamicparameters.go
@@ -0,0 +1,110 @@
+//go:build !slim
+
+package cli
+
+import (
+ "fmt"
+
+ "github.com/prometheus/client_golang/prometheus"
+ "golang.org/x/xerrors"
+
+ "cdr.dev/slog"
+ "cdr.dev/slog/sloggers/sloghuman"
+
+ "github.com/coder/coder/v2/scaletest/dynamicparameters"
+ "github.com/coder/coder/v2/scaletest/harness"
+ "github.com/coder/serpent"
+)
+
+const (
+ dynamicParametersTestName = "dynamic-parameters"
+)
+
+func (r *RootCmd) scaletestDynamicParameters() *serpent.Command {
+ var templateName string
+ var numEvals int64
+ orgContext := NewOrganizationContext()
+ output := &scaletestOutputFlags{}
+
+ cmd := &serpent.Command{
+ Use: "dynamic-parameters",
+ Short: "Generates load on the Coder server evaluating dynamic parameters",
+ Long: `It is recommended that all rate limits are disabled on the server before running this scaletest. This test generates many login events which will be rate limited against the (most likely single) IP.`,
+ Handler: func(inv *serpent.Invocation) error {
+ ctx := inv.Context()
+
+ outputs, err := output.parse()
+ if err != nil {
+ return xerrors.Errorf("could not parse --output flags")
+ }
+
+ client, err := r.InitClient(inv)
+ if err != nil {
+ return err
+ }
+ if templateName == "" {
+ return xerrors.Errorf("template cannot be empty")
+ }
+
+ org, err := orgContext.Selected(inv, client)
+ if err != nil {
+ return err
+ }
+
+ logger := slog.Make(sloghuman.Sink(inv.Stdout)).Leveled(slog.LevelDebug)
+ partitions, err := dynamicparameters.SetupPartitions(ctx, client, org.ID, templateName, numEvals, logger)
+ if err != nil {
+ return xerrors.Errorf("setup dynamic parameters partitions: %w", err)
+ }
+
+ th := harness.NewTestHarness(harness.ConcurrentExecutionStrategy{}, harness.ConcurrentExecutionStrategy{})
+ reg := prometheus.NewRegistry()
+ metrics := dynamicparameters.NewMetrics(reg, "concurrent_evaluations")
+
+ for i, part := range partitions {
+ for j := range part.ConcurrentEvaluations {
+ cfg := dynamicparameters.Config{
+ TemplateVersion: part.TemplateVersion.ID,
+ Metrics: metrics,
+ MetricLabelValues: []string{fmt.Sprintf("%d", part.ConcurrentEvaluations)},
+ }
+ runner := dynamicparameters.NewRunner(client, cfg)
+ th.AddRun(dynamicParametersTestName, fmt.Sprintf("%d/%d", j, i), runner)
+ }
+ }
+
+ err = th.Run(ctx)
+ if err != nil {
+ return xerrors.Errorf("run test harness: %w", err)
+ }
+
+ res := th.Results()
+ for _, o := range outputs {
+ err = o.write(res, inv.Stdout)
+ if err != nil {
+ return xerrors.Errorf("write output %q to %q: %w", o.format, o.path, err)
+ }
+ }
+
+ return nil
+ },
+ }
+
+ cmd.Options = serpent.OptionSet{
+ {
+ Flag: "template",
+ Description: "Name of the template to use. If it does not exist, it will be created.",
+ Default: "scaletest-dynamic-parameters",
+ Value: serpent.StringOf(&templateName),
+ },
+ {
+ Flag: "concurrent-evaluations",
+ Description: "Number of concurrent dynamic parameter evaluations to perform.",
+ Default: "100",
+ Value: serpent.Int64Of(&numEvals),
+ },
+ }
+ orgContext.AttachOptions(cmd)
+ output.attach(&cmd.Options)
+ return cmd
+}
diff --git a/codersdk/client.go b/codersdk/client.go
index e71703c751963..42ad51286f181 100644
--- a/codersdk/client.go
+++ b/codersdk/client.go
@@ -519,6 +519,16 @@ func (e *Error) Error() string {
return builder.String()
}
+// NewTestError is a helper function to create a Error, setting the internal fields. It's generally only useful for
+// testing.
+func NewTestError(statusCode int, method string, u string) *Error {
+ return &Error{
+ statusCode: statusCode,
+ method: method,
+ url: u,
+ }
+}
+
type closeFunc func() error
func (c closeFunc) Close() error {
diff --git a/scaletest/dynamicparameters/config.go b/scaletest/dynamicparameters/config.go
index 176b1245b23b1..5bd10f1b25a70 100644
--- a/scaletest/dynamicparameters/config.go
+++ b/scaletest/dynamicparameters/config.go
@@ -4,7 +4,6 @@ import "github.com/google/uuid"
type Config struct {
TemplateVersion uuid.UUID `json:"template_version"`
- SessionToken string `json:"session_token"`
Metrics *Metrics `json:"-"`
MetricLabelValues []string `json:"metric_label_values"`
}
diff --git a/scaletest/dynamicparameters/run.go b/scaletest/dynamicparameters/run.go
index cec482bb4129d..12dd4099817e6 100644
--- a/scaletest/dynamicparameters/run.go
+++ b/scaletest/dynamicparameters/run.go
@@ -22,12 +22,8 @@ type Runner struct {
var _ harness.Runnable = &Runner{}
func NewRunner(client *codersdk.Client, cfg Config) *Runner {
- clone := codersdk.New(client.URL)
- clone.HTTPClient = client.HTTPClient
- clone.SetLogger(client.Logger())
- clone.SetSessionToken(cfg.SessionToken)
return &Runner{
- client: clone,
+ client: client,
cfg: cfg,
}
}
diff --git a/scaletest/dynamicparameters/run_test.go b/scaletest/dynamicparameters/run_test.go
index 57577d27434d7..2c280e5f960e3 100644
--- a/scaletest/dynamicparameters/run_test.go
+++ b/scaletest/dynamicparameters/run_test.go
@@ -37,7 +37,6 @@ func TestRun(t *testing.T) {
reg := prometheus.NewRegistry()
cfg := dynamicparameters.Config{
TemplateVersion: version.ID,
- SessionToken: userClient.SessionToken(),
Metrics: dynamicparameters.NewMetrics(reg, "template", "test_label_name"),
MetricLabelValues: []string{template.Name, "test_label_value"},
}
diff --git a/scaletest/dynamicparameters/template.go b/scaletest/dynamicparameters/template.go
index 464fba2f7f7cd..9e7d8bc97f867 100644
--- a/scaletest/dynamicparameters/template.go
+++ b/scaletest/dynamicparameters/template.go
@@ -1,14 +1,30 @@
package dynamicparameters
import (
+ "archive/tar"
+ "bytes"
+ "context"
_ "embed"
"encoding/json"
+ "fmt"
+ "io"
+ "path/filepath"
+ "slices"
"strings"
"text/template"
+ "time"
+ "github.com/google/uuid"
+ "golang.org/x/xerrors"
+
+ "cdr.dev/slog"
+ "github.com/coder/coder/v2/codersdk"
"github.com/coder/coder/v2/cryptorand"
+ "github.com/coder/quartz"
)
+var ErrNoProvisionersMatched = xerrors.New("no provisioners matched")
+
//go:embed tf/main.tf
var templateContent string
@@ -72,3 +88,272 @@ func GetModuleFiles() map[string][]byte {
".terraform/modules/modules.json": modulesJSONBytes,
}
}
+
+func createTarFromFiles(files map[string][]byte) ([]byte, error) {
+ buf := new(bytes.Buffer)
+ writer := tar.NewWriter(buf)
+ dirs := []string{}
+ for name, content := range files {
+ // We need to add directories before any files that use them. But, we only need to do this
+ // once.
+ dir := filepath.Dir(name)
+ if dir != "." && !slices.Contains(dirs, dir) {
+ dirs = append(dirs, dir)
+ err := writer.WriteHeader(&tar.Header{
+ Name: dir,
+ Mode: 0o755,
+ Typeflag: tar.TypeDir,
+ })
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ err := writer.WriteHeader(&tar.Header{
+ Name: name,
+ Size: int64(len(content)),
+ Mode: 0o644,
+ })
+ if err != nil {
+ return nil, err
+ }
+
+ _, err = writer.Write(content)
+ if err != nil {
+ return nil, err
+ }
+ }
+ // `writer.Close()` function flushes the writer buffer, and adds extra padding to create a legal tarball.
+ err := writer.Close()
+ if err != nil {
+ return nil, err
+ }
+ return buf.Bytes(), nil
+}
+
+func TemplateTarData() ([]byte, error) {
+ mainTF, err := TemplateContent()
+ if err != nil {
+ return nil, xerrors.Errorf("failed to generate main.tf: %w", err)
+ }
+ moduleFiles := GetModuleFiles()
+
+ files := map[string][]byte{
+ "main.tf": []byte(mainTF),
+ }
+ for k, v := range moduleFiles {
+ files[k] = v
+ }
+ tarData, err := createTarFromFiles(files)
+ if err != nil {
+ return nil, xerrors.Errorf("failed to create tarball: %w", err)
+ }
+
+ return tarData, nil
+}
+
+type Partition struct {
+ TemplateVersion codersdk.TemplateVersion
+ ConcurrentEvaluations int
+}
+
+type SDKForDynamicParametersSetup interface {
+ TemplateByName(ctx context.Context, orgID uuid.UUID, templateName string) (codersdk.Template, error)
+ CreateTemplate(ctx context.Context, orgID uuid.UUID, createReq codersdk.CreateTemplateRequest) (codersdk.Template, error)
+ CreateTemplateVersion(ctx context.Context, orgID uuid.UUID, createReq codersdk.CreateTemplateVersionRequest) (codersdk.TemplateVersion, error)
+ Upload(ctx context.Context, contentType string, reader io.Reader) (codersdk.UploadResponse, error)
+ TemplateVersion(ctx context.Context, versionID uuid.UUID) (codersdk.TemplateVersion, error)
+}
+
+// partitioner is an internal struct to hold context and arguments for partition setup
+// and to provide methods for all sub-steps.
+type partitioner struct {
+ ctx context.Context
+ client SDKForDynamicParametersSetup
+ orgID uuid.UUID
+ templateName string
+ numEvals int64
+ logger slog.Logger
+
+ // for testing
+ clock quartz.Clock
+}
+
+func SetupPartitions(
+ ctx context.Context, client SDKForDynamicParametersSetup,
+ orgID uuid.UUID, templateName string, numEvals int64,
+ logger slog.Logger,
+) ([]Partition, error) {
+ p := &partitioner{
+ ctx: ctx,
+ client: client,
+ orgID: orgID,
+ templateName: templateName,
+ numEvals: numEvals,
+ logger: logger,
+ clock: quartz.NewReal(),
+ }
+ return p.run()
+}
+
+func (p *partitioner) run() ([]Partition, error) {
+ var (
+ err error
+ coderError *codersdk.Error
+ templ codersdk.Template
+ tempVersion codersdk.TemplateVersion
+ )
+ templ, err = p.client.TemplateByName(p.ctx, p.orgID, p.templateName)
+ if xerrors.As(err, &coderError) && coderError.StatusCode() == 404 {
+ tempVersion, err = p.createTemplateVersion(uuid.Nil)
+ if err != nil {
+ return nil, xerrors.Errorf("failed to create template version: %w", err)
+ }
+ p.logger.Info(p.ctx, "created template version", slog.F("version_id", tempVersion.ID))
+ createReq := codersdk.CreateTemplateRequest{
+ Name: p.templateName,
+ DisplayName: "Scaletest Dynamic Parameters",
+ Description: "`coder exp scaletest dynamic parameters test` template",
+ VersionID: tempVersion.ID,
+ }
+ templ, err = p.client.CreateTemplate(p.ctx, p.orgID, createReq)
+ if err != nil {
+ return nil, xerrors.Errorf("failed to create template: %w", err)
+ }
+ p.logger.Info(p.ctx, "created template", slog.F("template_id", templ.ID), slog.F("name", p.templateName))
+ } else if err != nil {
+ return nil, xerrors.Errorf("failed to get template: %w", err)
+ }
+
+ // Partition the number into a list decreasing by half each time
+ evalParts := partitionEvaluations(int(p.numEvals))
+ p.logger.Info(p.ctx, "partitioned evaluations", slog.F("num_evals", p.numEvals), slog.F("eval_parts", evalParts))
+
+ // If tempVersion is not empty (i.e. we created it above), use it as the first version.
+ partitions := make([]Partition, 0, len(evalParts))
+ if tempVersion.ID != uuid.Nil {
+ partitions = append(partitions, Partition{
+ TemplateVersion: tempVersion,
+ ConcurrentEvaluations: evalParts[0],
+ })
+ evalParts = evalParts[1:]
+ }
+
+ for _, num := range evalParts {
+ version, err := p.createTemplateVersion(templ.ID)
+ if err != nil {
+ return nil, xerrors.Errorf("failed to create template version: %w", err)
+ }
+ partitions = append(partitions, Partition{
+ TemplateVersion: version,
+ ConcurrentEvaluations: num,
+ })
+ p.logger.Info(p.ctx, "created template version", slog.F("version_id", version.ID))
+ }
+
+ err = p.waitForTemplateVersionJobs(partitions)
+ if err != nil {
+ return nil, xerrors.Errorf("one or more template version jobs did not succeed: %w", err)
+ }
+ return partitions, nil
+}
+
+func (p *partitioner) createTemplateVersion(templateID uuid.UUID) (codersdk.TemplateVersion, error) {
+ tarData, err := TemplateTarData()
+ if err != nil {
+ return codersdk.TemplateVersion{}, xerrors.Errorf("failed to create template tarball: %w", err)
+ }
+
+ // Upload tarball
+ uploadResp, err := p.client.Upload(p.ctx, codersdk.ContentTypeTar, bytes.NewReader(tarData))
+ if err != nil {
+ return codersdk.TemplateVersion{}, xerrors.Errorf("failed to upload template tar: %w", err)
+ }
+
+ // Create template version
+ versionReq := codersdk.CreateTemplateVersionRequest{
+ TemplateID: templateID,
+ FileID: uploadResp.ID,
+ Message: "Initial version for scaletest dynamic parameters",
+ StorageMethod: codersdk.ProvisionerStorageMethodFile,
+ Provisioner: codersdk.ProvisionerTypeTerraform,
+ }
+ version, err := p.client.CreateTemplateVersion(p.ctx, p.orgID, versionReq)
+ if err != nil {
+ return codersdk.TemplateVersion{}, xerrors.Errorf("failed to create template version: %w", err)
+ }
+ if version.MatchedProvisioners != nil && version.MatchedProvisioners.Count == 0 {
+ return codersdk.TemplateVersion{}, ErrNoProvisionersMatched
+ }
+ return version, nil
+}
+
+func (p *partitioner) waitForTemplateVersionJobs(partitions []Partition) error {
+ const pollInterval = 2 * time.Second
+ done := xerrors.New("done")
+
+ pending := make(map[uuid.UUID]int)
+ for i, part := range partitions {
+ pending[part.TemplateVersion.ID] = i
+ }
+
+ tkr := p.clock.TickerFunc(p.ctx, pollInterval, func() error {
+ for versionID := range pending {
+ version, err := p.client.TemplateVersion(p.ctx, versionID)
+ if err != nil {
+ return xerrors.Errorf("failed to fetch template version %s: %w", versionID, err)
+ }
+ status := version.Job.Status
+ p.logger.Info(p.ctx, "polled template version job", slog.F("version_id", versionID), slog.F("status", status))
+ switch status {
+ case codersdk.ProvisionerJobSucceeded:
+ delete(pending, versionID)
+ case codersdk.ProvisionerJobPending, codersdk.ProvisionerJobRunning:
+ continue
+ default:
+ return ProvisionerJobUnexpectedStatusError{
+ TemplateVersionID: versionID,
+ Status: status,
+ JobError: version.Job.Error,
+ }
+ }
+ }
+ if len(pending) == 0 {
+ return done
+ }
+ return nil
+ }, "waitForTemplateVersionJobs")
+ err := tkr.Wait()
+ if xerrors.Is(err, done) {
+ return nil
+ }
+ return err
+}
+
+func partitionEvaluations(total int) []int {
+ var parts []int
+ remaining := total
+ for remaining > 0 {
+ next := remaining / 2
+ // round up
+ if next*2 != remaining {
+ next++
+ }
+ if next > remaining {
+ next = remaining
+ }
+ parts = append(parts, next)
+ remaining -= next
+ }
+ return parts
+}
+
+type ProvisionerJobUnexpectedStatusError struct {
+ TemplateVersionID uuid.UUID
+ Status codersdk.ProvisionerJobStatus
+ JobError string
+}
+
+func (e ProvisionerJobUnexpectedStatusError) Error() string {
+ return fmt.Sprintf("template version %s job in unexpected status %q, error '%s'", e.TemplateVersionID, e.Status, e.JobError)
+}
diff --git a/scaletest/dynamicparameters/template_internal_test.go b/scaletest/dynamicparameters/template_internal_test.go
new file mode 100644
index 0000000000000..0b000a4c74981
--- /dev/null
+++ b/scaletest/dynamicparameters/template_internal_test.go
@@ -0,0 +1,293 @@
+package dynamicparameters
+
+import (
+ "context"
+ "io"
+ "net/http"
+ "testing"
+ "time"
+
+ "github.com/google/uuid"
+ "github.com/stretchr/testify/require"
+
+ "cdr.dev/slog"
+ "github.com/coder/coder/v2/codersdk"
+ "github.com/coder/coder/v2/testutil"
+ "github.com/coder/quartz"
+)
+
+func TestPartitionEvaluations(t *testing.T) {
+ t.Parallel()
+ tests := []struct {
+ name string
+ input int
+ expected []int
+ }{
+ {
+ name: "10",
+ input: 10,
+ expected: []int{5, 3, 1, 1},
+ },
+ {
+ name: "11",
+ input: 11,
+ expected: []int{6, 3, 1, 1},
+ },
+ {
+ name: "12",
+ input: 12,
+ expected: []int{6, 3, 2, 1},
+ },
+ {
+ name: "600",
+ input: 600,
+ expected: []int{300, 150, 75, 38, 19, 9, 5, 2, 1, 1},
+ },
+ }
+
+ for _, tc := range tests {
+ tc := tc
+ t.Run(tc.name, func(t *testing.T) {
+ t.Parallel()
+ got := partitionEvaluations(tc.input)
+ require.Equal(t, tc.expected, got)
+ total := 0
+ for _, v := range got {
+ total += v
+ }
+ require.Equal(t, tc.input, total)
+ })
+ }
+}
+
+func TestSetupPartitions_TemplateExists(t *testing.T) {
+ t.Parallel()
+ logger := testutil.Logger(t).Leveled(slog.LevelDebug)
+ ctx := testutil.Context(t, testutil.WaitShort)
+
+ orgID := uuid.New()
+ fClient := &fakeClient{
+ t: t,
+ expectedTemplateName: "test-template",
+ expectedOrgID: orgID,
+ matchedProvisioners: 1,
+ templateVersionJobStatus: codersdk.ProvisionerJobSucceeded,
+ }
+ mClock := quartz.NewMock(t)
+ trap := mClock.Trap().TickerFunc("waitForTemplateVersionJobs")
+ defer trap.Close()
+ uut := partitioner{
+ ctx: ctx,
+ client: fClient,
+ orgID: orgID,
+ templateName: "test-template",
+ numEvals: 600,
+ logger: logger,
+ clock: mClock,
+ }
+ var partitions []Partition
+ errCh := make(chan error, 1)
+ go func() {
+ var err error
+ partitions, err = uut.run()
+ errCh <- err
+ }()
+ trap.MustWait(ctx).MustRelease(ctx)
+ mClock.Advance(time.Second * 2).MustWait(ctx)
+ err := testutil.RequireReceive(ctx, t, errCh)
+ require.NoError(t, err)
+ // 600 evaluations should be partitioned into 10 parts: []int{300, 150, 75, 38, 19, 9, 5, 2, 1, 1}
+ // c.f. TestPartitionEvaluations. That's 10 template versions and associated uploads.
+ require.Equal(t, 10, len(partitions))
+ require.Equal(t, 10, fClient.templateVersionsCount)
+ require.Equal(t, 10, fClient.uploadsCount)
+ require.Equal(t, 1, fClient.templateByNameCount)
+ require.Equal(t, 0, fClient.createTemplateCount)
+}
+
+func TestSetupPartitions_TemplateDoesntExist(t *testing.T) {
+ t.Parallel()
+ logger := testutil.Logger(t).Leveled(slog.LevelDebug)
+ ctx := testutil.Context(t, testutil.WaitShort)
+
+ orgID := uuid.New()
+ fClient := &fakeClient{
+ t: t,
+ expectedTemplateName: "test-template",
+ expectedOrgID: orgID,
+ templateByNameError: codersdk.NewTestError(http.StatusNotFound, "", ""),
+ matchedProvisioners: 1,
+ templateVersionJobStatus: codersdk.ProvisionerJobSucceeded,
+ }
+ mClock := quartz.NewMock(t)
+ trap := mClock.Trap().TickerFunc("waitForTemplateVersionJobs")
+ defer trap.Close()
+ uut := partitioner{
+ ctx: ctx,
+ client: fClient,
+ orgID: orgID,
+ templateName: "test-template",
+ numEvals: 600,
+ logger: logger,
+ clock: mClock,
+ }
+ var partitions []Partition
+ errCh := make(chan error, 1)
+ go func() {
+ var err error
+ partitions, err = uut.run()
+ errCh <- err
+ }()
+ trap.MustWait(ctx).MustRelease(ctx)
+ mClock.Advance(time.Second * 2).MustWait(ctx)
+ err := testutil.RequireReceive(ctx, t, errCh)
+ require.NoError(t, err)
+ // 600 evaluations should be partitioned into 10 parts: []int{300, 150, 75, 38, 19, 9, 5, 2, 1, 1}
+ // c.f. TestPartitionEvaluations. That's 10 template versions and associated uploads.
+ require.Equal(t, 10, len(partitions))
+ require.Equal(t, 10, fClient.templateVersionsCount)
+ require.Equal(t, 10, fClient.uploadsCount)
+ require.Equal(t, 1, fClient.templateByNameCount)
+ require.Equal(t, 1, fClient.createTemplateCount)
+}
+
+func TestSetupPartitions_NoMatchedProvisioners(t *testing.T) {
+ t.Parallel()
+ logger := testutil.Logger(t).Leveled(slog.LevelDebug)
+ ctx := testutil.Context(t, testutil.WaitShort)
+
+ orgID := uuid.New()
+ fClient := &fakeClient{
+ t: t,
+ expectedTemplateName: "test-template",
+ expectedOrgID: orgID,
+ matchedProvisioners: 0,
+ templateVersionJobStatus: codersdk.ProvisionerJobSucceeded,
+ }
+ mClock := quartz.NewMock(t)
+ uut := partitioner{
+ ctx: ctx,
+ client: fClient,
+ orgID: orgID,
+ templateName: "test-template",
+ numEvals: 600,
+ logger: logger,
+ clock: mClock,
+ }
+ errCh := make(chan error, 1)
+ go func() {
+ _, err := uut.run()
+ errCh <- err
+ }()
+ err := testutil.RequireReceive(ctx, t, errCh)
+ require.ErrorIs(t, err, ErrNoProvisionersMatched)
+ require.Equal(t, 1, fClient.templateVersionsCount)
+ require.Equal(t, 1, fClient.uploadsCount)
+ require.Equal(t, 1, fClient.templateByNameCount)
+ require.Equal(t, 0, fClient.createTemplateCount)
+}
+
+func TestSetupPartitions_JobFailed(t *testing.T) {
+ t.Parallel()
+ logger := testutil.Logger(t).Leveled(slog.LevelDebug)
+ ctx := testutil.Context(t, testutil.WaitShort)
+
+ orgID := uuid.New()
+ fClient := &fakeClient{
+ t: t,
+ expectedTemplateName: "test-template",
+ expectedOrgID: orgID,
+ matchedProvisioners: 1,
+ templateVersionJobStatus: codersdk.ProvisionerJobFailed,
+ }
+ mClock := quartz.NewMock(t)
+ trap := mClock.Trap().TickerFunc("waitForTemplateVersionJobs")
+ defer trap.Close()
+ uut := partitioner{
+ ctx: ctx,
+ client: fClient,
+ orgID: orgID,
+ templateName: "test-template",
+ numEvals: 600,
+ logger: logger,
+ clock: mClock,
+ }
+ errCh := make(chan error, 1)
+ go func() {
+ _, err := uut.run()
+ errCh <- err
+ }()
+ trap.MustWait(ctx).MustRelease(ctx)
+ mClock.Advance(time.Second * 2).MustWait(ctx)
+ err := testutil.RequireReceive(ctx, t, errCh)
+ require.ErrorAs(t, err, &ProvisionerJobUnexpectedStatusError{})
+ require.Equal(t, 10, fClient.templateVersionsCount)
+ require.Equal(t, 10, fClient.uploadsCount)
+ require.Equal(t, 1, fClient.templateByNameCount)
+ require.Equal(t, 0, fClient.createTemplateCount)
+}
+
+type fakeClient struct {
+ t testing.TB
+
+ expectedTemplateName string
+ expectedOrgID uuid.UUID
+ templateByNameError error
+
+ matchedProvisioners int
+ templateVersionJobStatus codersdk.ProvisionerJobStatus
+
+ createTemplateCount int
+ templateVersionsCount int
+ uploadsCount int
+ templateByNameCount int
+}
+
+func (f *fakeClient) TemplateByName(ctx context.Context, orgID uuid.UUID, templateName string) (codersdk.Template, error) {
+ f.templateByNameCount++
+ require.Equal(f.t, f.expectedOrgID, orgID)
+ require.Equal(f.t, f.expectedTemplateName, templateName)
+
+ if f.templateByNameError != nil {
+ return codersdk.Template{}, f.templateByNameError
+ }
+ return codersdk.Template{
+ ID: uuid.New(),
+ Name: f.expectedTemplateName,
+ }, nil
+}
+
+func (f *fakeClient) CreateTemplate(ctx context.Context, orgID uuid.UUID, createReq codersdk.CreateTemplateRequest) (codersdk.Template, error) {
+ f.createTemplateCount++
+ require.Equal(f.t, f.expectedOrgID, orgID)
+ require.Equal(f.t, f.expectedTemplateName, createReq.Name)
+
+ return codersdk.Template{
+ ID: uuid.New(),
+ Name: f.expectedTemplateName,
+ }, nil
+}
+
+func (f *fakeClient) CreateTemplateVersion(ctx context.Context, orgID uuid.UUID, createReq codersdk.CreateTemplateVersionRequest) (codersdk.TemplateVersion, error) {
+ f.templateVersionsCount++
+ return codersdk.TemplateVersion{
+ ID: uuid.New(),
+ Name: f.expectedTemplateName,
+ MatchedProvisioners: &codersdk.MatchedProvisioners{Count: f.matchedProvisioners},
+ }, nil
+}
+
+func (f *fakeClient) Upload(ctx context.Context, contentType string, reader io.Reader) (codersdk.UploadResponse, error) {
+ f.uploadsCount++
+ return codersdk.UploadResponse{
+ ID: uuid.New(),
+ }, nil
+}
+
+func (f *fakeClient) TemplateVersion(ctx context.Context, versionID uuid.UUID) (codersdk.TemplateVersion, error) {
+ return codersdk.TemplateVersion{
+ ID: versionID,
+ Job: codersdk.ProvisionerJob{Status: f.templateVersionJobStatus},
+ MatchedProvisioners: &codersdk.MatchedProvisioners{Count: f.matchedProvisioners},
+ }, nil
+}
From be22c38161698f3269172179f9ee5cc6ea918b44 Mon Sep 17 00:00:00 2001
From: david-fraley <67079030+david-fraley@users.noreply.github.com>
Date: Tue, 7 Oct 2025 15:46:47 -0500
Subject: [PATCH 076/298] docs: update release versions in docs (#20196)
---
docs/install/kubernetes.md | 8 ++++----
docs/install/rancher.md | 4 ++--
docs/install/releases/index.md | 12 ++++++------
3 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/docs/install/kubernetes.md b/docs/install/kubernetes.md
index 5cab1a2350e2d..61ccf0a668dda 100644
--- a/docs/install/kubernetes.md
+++ b/docs/install/kubernetes.md
@@ -136,7 +136,7 @@ We support two release channels: mainline and stable - read the
helm install coder coder-v2/coder \
--namespace coder \
--values values.yaml \
- --version 2.26.0
+ --version 2.27.0
```
- **OCI Registry**
@@ -147,7 +147,7 @@ We support two release channels: mainline and stable - read the
helm install coder oci://ghcr.io/coder/chart/coder \
--namespace coder \
--values values.yaml \
- --version 2.26.0
+ --version 2.27.0
```
- **Stable** Coder release:
@@ -160,7 +160,7 @@ We support two release channels: mainline and stable - read the
helm install coder coder-v2/coder \
--namespace coder \
--values values.yaml \
- --version 2.25.2
+ --version 2.26.1
```
- **OCI Registry**
@@ -171,7 +171,7 @@ We support two release channels: mainline and stable - read the
helm install coder oci://ghcr.io/coder/chart/coder \
--namespace coder \
--values values.yaml \
- --version 2.25.2
+ --version 2.26.1
```
You can watch Coder start up by running `kubectl get pods -n coder`. Once Coder
diff --git a/docs/install/rancher.md b/docs/install/rancher.md
index 7a5c95f017a94..20e73f0a86940 100644
--- a/docs/install/rancher.md
+++ b/docs/install/rancher.md
@@ -134,8 +134,8 @@ kubectl create secret generic coder-db-url -n coder \
1. Select a Coder version:
- - **Mainline**: `2.20.x`
- - **Stable**: `2.19.x`
+ - **Mainline**: `2.27.0`
+ - **Stable**: `2.26.1`
Learn more about release channels in the [Releases documentation](./releases/index.md).
diff --git a/docs/install/releases/index.md b/docs/install/releases/index.md
index 2a8ef1d704273..2b7b985076562 100644
--- a/docs/install/releases/index.md
+++ b/docs/install/releases/index.md
@@ -57,13 +57,13 @@ pages.
| Release name | Release Date | Status | Latest Release |
|------------------------------------------------|--------------------|------------------|----------------------------------------------------------------|
-| [2.21](https://coder.com/changelog/coder-2-21) | April 02, 2025 | Not Supported | [v2.21.3](https://github.com/coder/coder/releases/tag/v2.21.3) |
| [2.22](https://coder.com/changelog/coder-2-22) | May 16, 2025 | Not Supported | [v2.22.1](https://github.com/coder/coder/releases/tag/v2.22.1) |
-| [2.23](https://coder.com/changelog/coder-2-23) | June 03, 2025 | Security Support | [v2.23.2](https://github.com/coder/coder/releases/tag/v2.23.4) |
-| [2.24](https://coder.com/changelog/coder-2-24) | August 07, 2025 | Security Support | [v2.24.3](https://github.com/coder/coder/releases/tag/v2.24.3) |
-| [2.25](https://coder.com/changelog/coder-2-25) | September 04, 2025 | Stable | [v2.25.2](https://github.com/coder/coder/releases/tag/v2.25.2) |
-| [2.26](https://coder.com/changelog/coder-2-26) | September 02, 2025 | Mainline | [v2.26.0](https://github.com/coder/coder/releases/tag/v2.26.0) |
-| 2.27 | October 07, 2025 | Not Released | N/A |
+| [2.23](https://coder.com/changelog/coder-2-23) | June 03, 2025 | Not Supported | [v2.23.5](https://github.com/coder/coder/releases/tag/v2.23.5) |
+| [2.24](https://coder.com/changelog/coder-2-24) | July 01, 2025 | Not Supported | [v2.24.4](https://github.com/coder/coder/releases/tag/v2.24.4) |
+| [2.25](https://coder.com/changelog/coder-2-25) | August 05, 2025 | Security Support | [v2.25.3](https://github.com/coder/coder/releases/tag/v2.25.3) |
+| [2.26](https://coder.com/changelog/coder-2-26) | September 03, 2025 | Stable | [v2.26.1](https://github.com/coder/coder/releases/tag/v2.26.1) |
+| [2.27](https://coder.com/changelog/coder-2-27) | October 02, 2025 | Mainline | [v2.27.0](https://github.com/coder/coder/releases/tag/v2.27.0) |
+| 2.28 | | Not Released | N/A |
> [!TIP]
From d0f434b6723d8bf35ba98c691abdc1db282f237b Mon Sep 17 00:00:00 2001
From: Stephen Kirby <58410745+stirby@users.noreply.github.com>
Date: Tue, 7 Oct 2025 22:36:05 -0500
Subject: [PATCH 077/298] feat(docs): add bridge documentation for early access
(#20188)
---
docs/ai-coder/ai-bridge.md | 268 ++++
docs/images/aibridge/aibridge_diagram.png | Bin 0 -> 183745 bytes
.../aibridge/grafana_user_leaderboard.png | Bin 0 -> 51915 bytes
.../aibridge/grafana_user_prompts_logging.png | Bin 0 -> 222102 bytes
docs/manifest.json | 7 +
.../dashboards/grafana/aibridge/README.md | 39 +
.../grafana/aibridge/dashboard.json | 1411 +++++++++++++++++
.../grafana/aibridge/grafana_dashboard.png | Bin 0 -> 474367 bytes
8 files changed, 1725 insertions(+)
create mode 100644 docs/ai-coder/ai-bridge.md
create mode 100644 docs/images/aibridge/aibridge_diagram.png
create mode 100644 docs/images/aibridge/grafana_user_leaderboard.png
create mode 100644 docs/images/aibridge/grafana_user_prompts_logging.png
create mode 100644 examples/monitoring/dashboards/grafana/aibridge/README.md
create mode 100644 examples/monitoring/dashboards/grafana/aibridge/dashboard.json
create mode 100644 examples/monitoring/dashboards/grafana/aibridge/grafana_dashboard.png
diff --git a/docs/ai-coder/ai-bridge.md b/docs/ai-coder/ai-bridge.md
new file mode 100644
index 0000000000000..5d62d2b3833d9
--- /dev/null
+++ b/docs/ai-coder/ai-bridge.md
@@ -0,0 +1,268 @@
+# AI Bridge
+
+> [!NOTE]
+> AI Bridge is currently an _experimental_ feature.
+
+
+
+Bridge is a smart proxy for AI. It acts as a man-in-the-middle between your users' coding agents / IDEs
+and providers like OpenAI and Anthropic. By intercepting all the AI traffic between these clients and
+the upstream APIs, Bridge can record user prompts, token usage, and tool invocations.
+
+Bridge solves 3 key problems:
+
+1. **Centralized authn/z management**: no more issuing & managing API tokens for OpenAI/Anthropic usage.
+ Users use their Coder session or API tokens to authenticate with `coderd` (Coder control plane), and
+ `coderd` securely communicates with the upstream APIs on their behalf. Use a single key for all users.
+2. **Auditing and attribution**: all interactions with AI services, whether autonomous or human-initiated,
+ will be audited and attributed back to a user.
+3. **Centralized MCP administration**: define a set of approved MCP servers and tools which your users may
+ use, and prevent users from using their own.
+
+## When to use AI Bridge
+
+As the library of LLMs and their associated tools grow, administrators are pressured to provide auditing, measure adoption, provide tools through MCP, and track token spend. Disparate SAAS platforms provide _some_ of these for _some_ tools, but there is no centralized, secure solution for these challenges.
+
+If you are an administrator or devops leader looking to:
+
+- Measure AI tooling adoption across teams or projects
+- Provide an LLM audit trail to security administrators
+- Manage token spend in a central dashboard
+- Investigate opportunities for AI automation
+- Uncover the high-leverage use cases from experienced engineers
+
+We advise trying Bridge as self-hosted proxy to monitor LLM usage agnostically across AI powered IDEs like Cursor and headless agents like Claude Code.
+
+## Setup
+
+Bridge runs inside the Coder control plane, requiring no separate compute to deploy or scale. Once enabled, `coderd` hosts the bridge in-memory and brokers traffic to your configured AI providers on behalf of authenticated users.
+
+**Required**:
+
+1. A **premium** licensed Coder deployment
+1. Feature must be [enabled](#activation) using the server flag
+1. One or more [provider](#providers) API keys must be configured
+
+### Activation
+
+To enable this feature, activate the `aibridge` experiment using an environment variable or a CLI flag.
+Additionally, you will need to enable Bridge explicitly:
+
+```sh
+CODER_EXPERIMENTS="aibridge" CODER_AIBRIDGE_ENABLED=true coder server
+# or
+coder server --experiments=aibridge --aibridge-enabled=true
+```
+
+_If you have other experiments enabled, separate them by commas._
+
+### Providers
+
+Bridge currently supports OpenAI and Anthropic APIs.
+
+**API Key**:
+
+The single key used to authenticate all requests from Bridge to OpenAI/Anthropic APIs.
+
+- `CODER_AIBRIDGE_OPENAI_KEY` or `--aibridge-openai-key`
+- `CODER_AIBRIDGE_ANTHROPIC_KEY` or `--aibridge-anthropic-key`
+
+**Base URL**:
+
+The API to which Bridge will relay requests.
+
+- `CODER_AIBRIDGE_OPENAI_BASE_URL` or `--aibridge-openai-base-url`, defaults to `https://api.openai.com/v1/`
+- `CODER_AIBRIDGE_ANTHROPIC_BASE_URL` or `--aibridge-anthropic-base-url`, defaults to `https://api.anthropic.com/`
+
+Bridge is compatible with _[Google Vertex AI](https://cloud.google.com/vertex-ai?hl=en)_, _[AWS Bedrock](https://aws.amazon.com/bedrock/)_, and other LLM brokers. You may specify the base URL(s) above to the appropriate API endpoint for your provider.
+
+---
+
+> [!NOTE]
+> See [Supported APIs](#supported-apis) section below for a comprehensive list.
+
+## Collected Data
+
+Bridge collects:
+
+- The last `user` prompt of each request
+- All token usage (associated with each prompt)
+- Every tool invocation
+
+All of these records are associated to an "interception" record, which maps 1:1 with requests received from clients but may involve several interactions with upstream providers. Interceptions are associated with a Coder identity, allowing you to map consumption and cost with teams or individuals in your organization:
+
+
+
+These logs can be used to determine usage patterns, track costs, and evaluate tooling adoption.
+
+This data is currently accessible through the API and CLI (experimental), which we advise administrators export to their observability platform of choice. We've configured a Grafana dashboard to display Claude Code usage internally which can be imported as a starting point for your tooling adoption metrics.
+
+
+
+We provide an example Grafana dashboard that you can import as a starting point for your tooling adoption metrics. See [here](../examples/monitoring/dashboards/grafana/aibridge/README.md).
+
+## Implementation Details
+
+`coderd` runs an in-memory instance of `aibridged`, whose logic is mostly contained in https://github.com/coder/aibridge. In future releases we will support running external instances for higher throughput and complete memory isolation from `coderd`.
+
+
+See a diagram of how Bridge interception works
+
+```mermaid
+
+sequenceDiagram
+ actor User
+ participant Client
+ participant Bridge
+
+ User->>Client: Issues prompt
+ activate Client
+
+ Note over User, Client: Coder session key used as AI token
+ Client-->>Bridge: Sends request
+
+ activate Bridge
+ Note over Client, Bridge: Coder session key passed along
+
+ Note over Bridge: Authenticate
+ Note over Bridge: Parse request
+
+ alt Rejected
+ Bridge-->>Client: Send response
+ Client->>User: Display response
+ end
+
+ Note over Bridge: If first request, establish connection(s) with MCP server(s) and list tools
+
+ Note over Bridge: Inject MCP tools
+
+ Bridge-->>AIProvider: Send modified request
+
+ activate AIProvider
+
+ AIProvider-->>Bridge: Send response
+
+ Note over Client: Client is unaware of injected tools and invocations, just receives one long response
+
+ alt Has injected tool calls
+ loop
+ Note over Bridge: Invoke injected tool
+ Bridge-->>AIProvider: Send tool result
+ AIProvider-->>Bridge: Send response
+ end
+ end
+
+ deactivate AIProvider
+
+ Bridge-->>Client: Relay response
+ deactivate Bridge
+
+ Client->>User: Display response
+ deactivate Client
+```
+
+
+
+## MCP
+
+[Model Context Protocol (MCP)](https://modelcontextprotocol.io/docs/getting-started/intro) is a mechanism for connecting AI applications to external systems.
+
+Bridge can connect to MCP servers and inject tools automatically, enabling you to centrally manage the list of tools you wish to grant your users.
+
+> [!NOTE]
+> Only MCP servers which support OAuth2 Authorization are supported currently. In future releases we will support [optional authorization](https://modelcontextprotocol.io/specification/2025-06-18/basic/authorization#protocol-requirements).
+>
+> [_Streamable HTTP_](https://modelcontextprotocol.io/specification/2025-06-18/basic/transports#streamable-http) is the only supported transport currently. In future releases we will support the (now deprecated) [_Server-Sent Events_](https://modelcontextprotocol.io/specification/2025-06-18/basic/transports#backwards-compatibility) transport.
+
+Bridge makes use of [External Auth](../admin/external-auth/index.md) applications, as they define OAuth2 connections to upstream services. If your External Auth application hosts a remote MCP server, you can configure Bridge to connect to it, retrieve its tools and inject them into requests automatically - all while using each individual user's access token.
+
+For example, GitHub has a [remote MCP server](https://github.com/github/github-mcp-server?tab=readme-ov-file#remote-github-mcp-server) and we can use it as follows.
+
+```bash
+CODER_EXTERNAL_AUTH_0_TYPE=github
+CODER_EXTERNAL_AUTH_0_CLIENT_ID=...
+CODER_EXTERNAL_AUTH_0_CLIENT_SECRET=...
+# Tell Bridge where it can find this service's remote MCP server.
+CODER_EXTERNAL_AUTH_0_MCP_URL=https://api.githubcopilot.com/mcp/
+```
+
+See the diagram in [Implementation Details](#implementation-details) for more information.
+
+You can also control which tools are injected by using an allow and/or a deny regular expression on the tool names:
+
+```bash
+CODER_EXTERNAL_AUTH_0_MCP_TOOL_ALLOW_REGEX=(.+_gist.*)
+CODER_EXTERNAL_AUTH_0_MCP_TOOL_DENY_REGEX=(create_gist)
+```
+
+In the above example, all tools containing `_gist` in their name will be allowed, but `create_gist` is denied.
+
+The logic works as follows:
+
+- If neither the allow/deny patterns are defined, all tools will be injected.
+- The deny pattern takes precedence.
+- If only a deny pattern is defined, all tools are injected except those explicitly denied.
+
+In the above example, if you prompted your AI model with "list your available github tools by name", it would reply something like:
+
+> Certainly! Here are the GitHub-related tools that I have available:
+>
+> 1. `bmcp_github_update_gist`
+> 2. `bmcp_github_list_gists`
+
+Bridge marks automatically injected tools with a prefix `bmcp_` ("bridged MCP"). It also namespaces all tool names by the ID of their associated External Auth application (in this case `github`).
+
+## Tool Injection
+
+If a model decides to invoke a tool and it has a `bmcp_` suffix and Bridge has a connection with the related MCP server, it will invoke the tool. The tool result will be passed back to the upstream AI provider, and this will loop until the model has all of its required data. These inner loops are not relayed back to the client; all it seems is the result of this loop. See [Implementation Details](#implementation-details).
+
+In contrast, tools which are defined by the client (i.e. the [`Bash` tool](https://docs.claude.com/en/docs/claude-code/settings#tools-available-to-claude) defined by _Claude Code_) cannot be invoked by Bridge, and the tool call from the model will be relayed to the client, after which it will invoke the tool.
+
+If you have the `oauth2` and `mcp-server-http` experiments enabled, Coder's own [internal MCP tools](mcp-server.md) will be injected automatically.
+
+### Troubleshooting
+
+- **Too many tools**: should you receive an error like `Invalid 'tools': array too long. Expected an array with maximum length 128, but got an array with length 132 instead`, you can reduce the number by filtering out tools using the allow/deny patterns documented in the [MCP](#mcp) section.
+
+- **Coder MCP tools not being injected**: in order for Coder MCP tools to be injected, the internal MCP server needs to be active. Follow the instructions in the [MCP Server](mcp-server.md) page to enable it.
+
+- **External Auth tools not being injected**: this is generally due to the requesting user not being authenticated against the External Auth app; when this is the case, no attempt is made to connect to the MCP server.
+
+## Known Issues / Limitations
+
+- Codex CLI currently does not work with Bridge due to a JSON marshaling issue: https://github.com/coder/aibridge/issues/19
+- Claude Code web searches do not report correctly: https://github.com/coder/aibridge/issues/11
+
+## Supported APIs
+
+API support is broken down into two categories:
+
+- **Intercepted**: requests are intercepted, audited, and augmented - full Bridge functionality
+- **Passthrough**: requests are proxied directly to the upstream, no auditing or augmentation takes place
+
+Where relevant, both streaming and non-streaming requests are supported.
+
+### OpenAI
+
+**Intercepted**:
+
+- [`/v1/chat/completions`](https://platform.openai.com/docs/api-reference/chat/create)
+
+**Passthrough**:
+
+- [`/v1/models(/*)`](https://platform.openai.com/docs/api-reference/models/list)
+- [`/v1/responses`](https://platform.openai.com/docs/api-reference/responses/create) _(Interception support coming in **Beta**)_
+
+### Anthropic
+
+**Intercepted**:
+
+- [`/v1/messages`](https://docs.claude.com/en/api/messages)
+
+**Passthrough**:
+
+- [`/v1/models(/*)`](https://docs.claude.com/en/api/models-list)
+
+## Troubleshooting
+
+To report a bug, file a feature request, or view a list of known issues, please visit our [GitHub repository for Bridge](https://github.com/coder/aibridge). If you encounter issues with Bridge during early access, please reach out to us via [Discord](https://discord.gg/coder).
diff --git a/docs/images/aibridge/aibridge_diagram.png b/docs/images/aibridge/aibridge_diagram.png
new file mode 100644
index 0000000000000000000000000000000000000000..fe9d39b766d1f0b80e5589241bbfa7d5c3344b7a
GIT binary patch
literal 183745
zcmeFYRajilvOWwUgpdRX?hxD|xVyW%26uwH1%kT`?l24*+#$i;-5myJaQ{#C-oJgG
zbFRP3uOBX^hc&CaS5>`L^;WHLB?U>O4|pG7U|^7>rNmTVU=Yw?VBYM!e*^uduzSA}
z1||STT1;5YBlCC_K}%Kh72%v1=gY`1#4n<1KYp;N303^iAtWCkTW44ofTh>r-!lP#5KAk@qA|#Ap-r7^v^-*T=WFMHLiI
z?^iQ2SG@hXZ}mc|K{T+?#s58o=zR4N{+YnQOw@j{`@7eFkK8v_s{ee3fx(o@_`B(U
zj}oCJjDJ4E2*FPk|91jI8^;0v-{)SPLj=hCG9mfMQ3)((1b
zt6_O8=y*H{ay)r|6e!V^W!REsq}PK9_y!_HL-1UkOsIivo{AQ`GT8#Ai@3{3f47kv
zIXFZk7=BoExcd-dN-Rdtx+(^L&J+w)JwEaf#M#2>A{^tEDJ3@>P#EJ`kq4|ilBcb6
zF{!|XxapaQInPkX1v*%SaxwZixDFJoh@de!+Tu;2K*_csN^wbDRuE;`0+xb<8!X(X
zATXOv@=5=Ir$eOkZYq=8w1U6_ZZ#s$!*95NnuGtA$W!Owi`w5k1%#5&74bSUbmOai
z9WdGu1`&ndYQMBFw14B53%Q7?@
zHb)G`!(;9RV?)FYo4Qu+MN4enSjtqcTa>MG&px-5w}*)=`lDQnKAieR23dUlMO%5`
z(5aHP>%0UBy7C}l>1S6vIu!C!$~5L?$EA_91illluTc_$OPCM&EVNsRcc>{}K*jkh
zd$&auoH5^oPYrr3zXdjJ@IghZ|9fxbjrzJZ0ft2EOhj|Jd;
z9uMv;rmFls8R4N!87M?@N|M(mQ6oNpYW&8{j1FcMu|OU+7w*%5V5SO(stCQOJe4C)
z(F(~8`D|V>lFRmcaY@zWr}z#Actzmn*SX=};w~=mMavUq4)JzJMtyaoF4T#|{t5yR
zI?%AOP*iK9!ta&DM2egxyvY;GmKjkFx
z<+;y4r-oSv#r&eaTQTX&**7orjRf_LkO~6k46D@e@t8x!!d=M9nrp%Z8MK6S7#SUM
z>sDQ;<1@P~=UlAEi+H+Bm)g>TD^Oy6Mf!DKiJq|JFRhS^@AaiRZqa}a~_zXIMY`>mh3XIf6QSr4TB
zbqK$=g(bwjY047by+yypnWaS@lOM1`b9~y7>?lgAi+?MFI8<1r`&v_wSA|;U`V_oF
zX_j3$Wqc3kTZ1Q@$!xlmp2;96Lle&6pCKr0%Zyp5tbZx}!Lw7^_G4+Ykmk5@j+Gjw
z{4N8~uLng6a@GU2422R@t3>3uCz5weK}dm24wlkdfee$|s8#;Q!w?4lSiB5aktwoAM@P`n!P75v
z4Nxk!)SgvJPi=(PtTmA(Cc`6#`6ivW)-!skwzqKBWsB+_3tt+JuY@CV3mx3UQKK(M
z#DD%y{a^OADo>fa;%v&2}amQ5jp?C*FWY1NMrBs?MFzNVdK+2D_
z?-yzJ94m`72gS2Yy_|7qLNexTq3R!anbP7sR0e6q#Fw3+FKNL;i6tE2_N)Udk+vi0
z00+NYa&Z}P3#m@dYhuw)sF?cXf8e)TCSj`F>Ww#q>=l*TeI$M)kSAy*CTb3Y!sB&g
zb7C=x+@bzTs2^uy<9o{ude))@ngF*vnPO31ahFSkJY}s=I&TjBE=5q#!MSFVTdF-W
zY1PeYN`H^IfJ=4Ymc8;M;RiiA6Fwd^P_&nIW_abPNd52|M!nYOTI^HaIfht3&GEpdK4$tmcIXq@R=
zQ=lA%=9ofj0qO9Cn9&ob0-B;IKJ%&aiIg*aVy30)kg;LiYL2+r{v=MdEV)Inm;sxE
z@Nn^TDRnxsIH$wrzPUgT(iYMpn{m32zSz?I>cXni0bnO}MO9aSFVTp68FG`NNVW
zL#f3Kl!Et=X9<;@6PK?cm2WvT?Z>g`TBN{cY~KaM-wrh{NI9|PK4a4yA$xvbYVG)!
zJY$)e(}LM^Iu1CAof4C2^rMRt_?&9uWBHJh=i|{Dy
zMzUQsMlv;CesX8uqxx3_6=#yrzTaLK<4DXhN9Abc9SbnqRWpzafeSyG&?!`;CuW%i
z4$(7k0w)^DE;$rb%G=NM6UKj$rNB!MgM{beHDJ6j2%|V$P12gRQ>|0_S7|i-EC<;L
zY%Pkk8QRNB^D7OSP3t0q%+j#>ISqc6#8(Y@SXL%UDFkTH0@(;;%^Fq3^x+Y}x)~?afnrhugcHa*FOx18IJ$_2X|N2z_^VYpNSFO+qA(P5$
z`RE7?Ql~?Uu-7Q{5kpwi)y4&lpE20RQCNtkyDG
zz!W-oj)Asm+DVGS=3q;`CDhKk{2qR7%vVWR-p)RG2+&p)#4c+>tj1s^rM!x8UCrjs
zJkRnmPzRxrg9G9j?5kwpYL|T|KpkLbVxIeApfM*~2`D)ZdeBbewK@(mm6yj>yA^h$
z9D(IPSwpDDG^iBPQqnKeV;LEoYtm$@w>ERV<{ToFdOZ4<|luM_A_$n9{
zAVh_pj1zv8@63G(pV)^l=~&=NlVe+AFQxeTuY-D>z9}ouGVCS@xCMar$7cTO
zICKNM?xI-?`^}lhSkI=Xn}UC0C(CM4x>e2@q@S$OD$LRQybmeN6t@)Mn5U9%MZg`f
zmZqf$pVG^BXD$T^7yAXab)Z^hy3u8S34wTW1mV0RbSUEY(sh1!O;mJ)>(N7`MzVvc
zv8u-C*m%usQR=^Hb@Rphqb9;f&QUksMug;9jB_>bxX|`0P~HQPb}d4+w(l`f9>OYP
zJ7am3myrhr`+e^ZzTE^rWZ1rUhmRPeL_4O7^L-=I73p(CJI1?ds+np`vu+P7$u4mm
zS=-yyF2O0|5#39^Ll&yA$aC?m*)!!F&*Q1+jUP@0Oj*3LGI5KwPacD#6t~qn0_H;D
zk!Ph)`>>OvpRWs@25nw48$*#N^l}Fqy_1Mz4(vK#!JkL1(Qn1+h_x1Q@U4)}B0qxG
z^)&9wZPVC9F3B(10Jk%NtV0x$AxN2L%Z3%{CBoLNZaGeaT%7%OiIUb0k3Fa8L)=^l
zswNei3!Fy!tec>OrIQdxSj
z=B3rVBS_GQnFpJGaRQ3C{_-4&Sc}2F?YAN%=CcLAGxTq=Z@MUpCSG
zaN_2rqGeZccV;@c*>JIX%$0d!X(6DYfFEzbGHjR^C2~UMzJpx>CFq@tM+YPJ#!Yc$
z0aG`q7LMK)dneU%-W9;(T1aOyB9I){YMT=cs1d4g*zm&(S
zrb-aMj_0LrbDk{+?ab-ldrLr#TXaY66x$H(#p_KMwM}qjd?+Go8V55$RBbBOqN~4r!oeli=$d~Y>la&aXfkG%~O
zFxAm=w?TxFIF7PjH5If*z+x2m8st4;i5<$X7(G{x^&=PRnoE
zzeB}GKdb86Z@=bw6DNb>B{;ATPkc?JroaB%pwqC~^hfA)ad;Zi3abeg`q9T&;dR(aijkh>b@TLFbjO
zM5WW9;dFmGUg>SF;go#`DrS{l4QbEopunMp?;_@`AJkX?BLoZkm&$(WCoT3|N|Y`0
zLGKoIt&kk{Hk-&6X{`t=W;yhRpU#ifcN2*Fknm4!ff@{Hh5}Bvh`R}Zch|ZE#|6zo
z8SIaTNvGcYBZD_pU=#K-dH(Nvp8)Q+dD{5=mb1G@Ifhc|jQ8uo8^Sk-{0C2235bsh
zGyr;nt!s&ZlyEO-=+XCtRg`J!aKvY+tp{;O#2up0@tzpe{W<>RsnEQ$`a94W;d=U^
zqcNuz$)dNGify=)SAdD*D8OlO2v<3MHU?<_yuRq3ENej2J~glYe8kxKbjIlpa!IU)
z%g*8V0qwo9uy@f=;JT^5eSQ$^XD{>h^pG&Flxd!;=kjnJW!e{1XVm6$L+V#>4`v
z^!eowP_gmoG+BP?T;*e;g!EOqMN%
zZ^Jx&JcR4MbVa=X`UE(*(myI#pD14`a)~<}sH#+dlvc`9zW!$B8#HH)X`Gy+)jK6o
zF>7BI^G50Ew-%N9>!SFHg&XNmMfqfl5c@7^^_;c(HLYMZ2is7c#<1oyQes%;#ZYo=
z3dT%GI;~&+yq;0Jny-k5f$19`kflrRX~f|kAi4|dN6bj%D*j9@*|61GVrD&_HD*|2F<(g}If{~$4X_4n
z2kV*42!U;Sr3nf3J^>XS%-ZR3by1~5ulB3#^IP(*qHebU`!4l^Anv?aD)avwYX)(|#TAVypE4$6*JvkEo!4b0sMIn2uo7{vCpu<4pOC7Zm2UB}|{t|`j(FzQk
zvyJ3ZQF;7~x=;YH0s(Z=8Ae@EC{nSL(m+IR1KnYRmr}hK%G3*L`*a6Ul0mU!y2hjr
z7WYtZw%yIIP`BHe+4(|jy$SlNQaW`y=|RE%2~EK_^rdYe4X4&)FDBn>MM}fp>U1;}
zgY!$3a>bCjk4Nx2WwSHMWyzKm#f$d#R@P7%HxFh-$kn46s8`OxTZiP;rz^RZfaEA=
zb>!_zKzz?G6*?xf_5giNI-2q}Q1kB)iRAl^>tNC{9j<2R$v2yg*c+Kd^g!ZlquR1$g+Au}9Th*uv}exr$b^g1nKu
zzFPTt_)?+S3uWtL)5)RmRs>WoLz^19{3Ue~?FhT)iNVI#qU`n{FBICTxu8Nk08Rvc
zdS_^bT)iH}#Ozg+e7#=Sr0b6?+x})=ac56!Kq0IUin6wWePO(weIj*aLnTQfn2kwp
zS2Oj{bg3ncI?lkpog%4R$4{0ze_tRTCC)atY1TzSXj+hj_})XBCg-LqKSOL<(1FH^
zqzZRg$Qe8FsC!MMJ&>^?kCimNHg!eUkZ!EVu59oZ`(6#sQbX**w3UXIY?p$L1j0O8
zj(javi5|SaGx4)me3w8mDqgK87C~_qaBwb_9G2~jCPH6$v5&k%R1{k^)n`ZHRCtN7
z!bz4|8S6w#RD{^eHBe?vwHlncH{nb+8){u_S1by~XlUBqd*r;GT*Eo!Ow2~|J;?c8
z<37Dcp8imsqANn<(C%CYMq_ulUrSG0d~9PP<*ELG7H-Z!IX>5z;2npo_az5l^+WN}
zi{B`6Fe3(iqBdtjC^BWQ(!SUPyaTcu#>mPg49zg)&5O
zd5HUA(=?}lOu~?DP#x60N9(tic_dc9DgLc(TJA+{;2c;fkvJ{e1D@6)FV198`)wP2
zpQp1ZlzfVDm+3`kZQyx5yMA-pZiwX3*0kvL%0@*Jj^F;IB*w|Px>_I~lyxFV#I2>o
zB)o*N;b^`oYVriOBt5}UjuT`SzjCKH(@dNvI0O#-z>Nz<>CMhv5Da@G?G&mqj@lU`
z1-|v1B$SaNmxkK~#LLMbN**}CO>yQ4ll1s4JXtN*~s4yYt=jMBhbvyMr`
zmsf@WGQ8L{CzuM#u%*AeMr-Ow%!);sMpW7(2YeHL$>X824t3JLJ~_1WXMSZ
z<4n=EBv3_ju8;-=!s_G`Ryf|J@uIC3XLhSm=5VBa6IT%3b^p#n4yaappnGo5dfOdl
zCS1?0mZYF!Q)83mUB#IA!JZT03r2ihSQC|$p`jJx$z+U%&ey@N5E)kRS$AP-NAEzi
z9>SK!Uasux@%?+)Tp&wszd`fIiW}1}ESXz0=Lb&D#2*^Q%>`m8
z%kPg(&gxxD$?e>7p>cd(uD@5m@s$?L8n{_ojlN>Agc#Q>$zq#?(HWw$qNMXgKAjfx
z;#1S5BYm;}X@+0k8zLw5$<|)@w`y=(9Qp`7&xC3ny-?dicF?nFFiUMqPAPvi;yvIz-BPtG|x;_cJ
zq+e__V5J<&dunamDJjnPxTdJTCQ3rVdHXpPEDI0za(
zttCfS*5+om9cV#k?c`5wN|*5`HzBxBS;qr
z2_r?$KKgCr82{2a2gf*d#>hf4o0OoIGm<5}t>D35iK$ok>Tt=_0xf>On0*?6bj-)%
z>$rT2fo$T$ReW^4>rgr=bP&0DjR^+5nf{?iy!l-3VwHxE4OQ*j{v)j}j9jV-PVWQZ
za{dO)0ENGm>wk>^Ms{{~)cA7g;v*p#7_UrYSa)!s^z2r|sRQ1Bdo%Q>rl-kBefj0K
z-oxZ7tSJ3umlV?b04)F9BfKd8>c_|CBC8hUw=giL;8R@@s7K>;8^O^Jg_%&z?N?y1>JVw+wOd;5a)A=uP%e?P@#DWYI^mjL
z0t!#(xzXYM2uL2!&V=R^W5^$1Hi)Z0p!+iQIr5{I;#OX}2jZCJ!L)DC6nk~$U*G@(
zBQ!rr#?L=>v|y9=2|Z^`(PIJW^f(s==H=q*D!o(Z`r74tFCQcH9RG~})0Yxb3HP7>
z-1R$aH7d@NusOT9T-{!p)Gqq@`L)Erw;;y$%gW2kD@bo%co6FT=*(H~2}dU+B;@5~
z3oxglp;>l6o^Zt={BOTY03(gPNB-Tb^4;Tog<)f5;*THxpZobUc{)on0!qRAy)Meggvv+WQm82ZPy)v6!Pj|Lvxkpy)+X#CUaISlt0c
zM@Kg|H|OQ$#m6h}_rB-Xl$VbdBPGfAWNP2p-@m=d7e~2<0QSbzeQYx`Gh65-?liZZ
znj_9iwy6|cHg?}AgV*jb^*_%Ck^Ix{b3VRzwhtUg^YZda&&W99AvnZ23FaP#oY&CL8-wADv|Oh9G%AgN)1*7>BNF8@EWWL*Ufq_^}P
zE2n&QSmWD~d)@tngv3oSc6~HYrI7l4YiAI7-1)S8R597a6vm5!hTkd
zny$n5{#dqnT`N1%f?9b>adC0$t9$LKLPiIx?MB2zK(9sBiwnc$Bp}4*UrjkLG}hME
ze=Sf5rI)24i{Hme=7sxjZ`I5J7`*!2nX#Fo^mny?kN@3}bupg3{GZmXT&l3U?Wjso
z7#Pc{^z`(mrY2bc<7$U*Ye&c0*x1Lr>P?yg&AlsVy!pZen7>$kz6FdwaUk!H|rMj3^e6
zp01;!;&i-F4c#ug&DFVel9zjb_;6YQCa52bHRcEDMb4^K!
zPC+d;7nD4js7`
zw4mnNtKWrqjzv)A3+UIdvpcb=YIoc2L-O{1ghN37M94GqSCwb<{|pRR{tkfE(9jSU
z7dNifGBnKTHP+VB8ZfOH8j^{Za=AX7y}#U#CFH$XcIdo@Kveurwo8|%i^a_@#LZS$
zsQ&kB=+5)6K|#
zb^eca{x0CT%5e;RVO98RJ(kLvnvGu9)}-m&&U+=w1xe1uZvr=3&pJLLBd;|(TR`C{
zCubd`3cNX9M90CgG%+!uu`n^YyqZ=d=5{jejlhH+9}EVcwci@}`E@AFgLwa^I}nBD
z>^uQ?yX)1#qFCwW7uU_Dc49ZSy)m}egjG@C}
z6l-d$n^>Nh)omrUdb`VF)DSYgIf6Wny3kf~FB|in_rWV5J0Ap+{_?r7un-3iZ!C)!
z@W-O>0OfBPLbHp7l0RhcMzo;=Arq~yeYM0JP8
z_Vwv)Ys@veBf9pcfk3_2Q;)OX;76Yirp<`On}C&`XSJ%mCEz3
ze{2rFHwR$Y>?_VkY(_aLDXpgOdG+=6q*b&SA54sm$1=H9)zw|y1N-{=#sy!WuE5hp
zD&Rjs2(1>sX{LYA0B_NW+=5#27}%Q<1^%sW0gSk~sUAF^K&YBd!&9z=!=hhVoWFB!
zQJTItfRNj(q%2Hlxia;CVN{R}lOD+LAju=+LLQkj1_fkbpeJg{Weda2pcSjY-pa_y
zc_nYhg_8skrb5J-3Au!k3D8;{QJ(#{GMI|JWvw%qTdNEQv<&wa5YhW;EaX>xxVAg<
zkm=FBqpMsVrsv#1>OsRT$(qu(uP`yB=8oU2j~Cx&<5GFJgaM)(ias=h<|7AZ=jYQF
zHR{N*Oeulq_+cX}Py7|MwXDq|PPa%-7OpPnaC|?OmX@Z0ik&YHM{fdiD=QTg6=Qpi
z(^6BZr$9FImHhrMZE}?Ooc1dz47$fBC-QP~81A0dwzhH#3fZg{$T{Owq)^j7S#ErU
zK6e8fYwL$8StfA_2`o&^EN{pN)va2LU&x_;r~3*91t>
zO5NE*0s{6sxs&l)AKRIOLh1Q_s}p~tmD0aGOagXBm70D%!>;&Z_WHn-;`8-2Eewnv
z^njdmxwgM`z^#rTt%HWc`TKA`*z*m
z-QAs&on3uL?(*^ysF)+*xYd)v>7b#h`SIJxBqc!8$&YowecWrT{Fk|^YJ;?_=UWGtOua=m6?`z|h
z$A_tCHG5_2H|r#+-70#ML;Q8t`Vt$jW7&(Xu8(=D7B8IScGr!PO)8FiIc1!fax0F9
z3u}Z3<5{aOb!oZRAAB9VVrDzl_*b81=GMouRt55mhAlcRT)(bTS3Et=q>KydKAg4<
z!m7^C3)bEh{gERzhVN+KzDsK-{`nO?do2YE;JAv_MwcVFLz00`RqLU9}NuN;wl*
zPVq5Dn!Oj>QvDfHjy|)H3JcxRD}wZYrtu1s|HYy4kdB94yOY0!#|tM3jb3koEnbsB87g@pru{_K6Y
zK7wMQL@W`%&)qo`3957($JW+53JXo4p3tN}hTmyN%EY8#t5_w1?toY`^`9_mLs|UE
zQDUCt0A{*xeB5ogV;w?m37?Th!&HX;@o4Z5#C|Hy%Dg8@LtXmlu%}RO%$PYE)BP|d
zqAd80-`vY*J0|o+iG&$hFWQ(
z!+J+~dHKAdzka*}^dk1JUk}!{MGp2d`WF7iWj2YK(3M
zT#Zv-?Jaz5KC3W3Rhm7s{ct(f`#`x}`lH*!m7Y*!Fww#11l<^zQjCDMlbk)tA;CF21p0t!w2dUhsb>rVv06Umo
zY92dN5cb9&P1Vl>G0_QHSabr$lvGt~EylAA+P$KQ1v{W8hnyukS7{yzuZufpTD*0zP?&*(x1+5^X?Ol5&b;$%vDhMzu(V!JuIt&22Rje^y>P$
zqM`ybZLS~lzxiW8%(oVVcb?pj@ZPo2x-wcFiv0W8Eq;SbB_my1BV=XkkIcQ#X;vNd
zDgJkFHM$(6g}ISQ`aK}bw`QEn&mMop0}f^Mp)PPR7WN?k&%ghuY22By&bHS9s`n*EDL{X
zv4fkq-?q0H2kypG7!oq3xOvsZf*`@8#B#)^b~alZtmbo5h6!w^=d;{BX}oKnP;#E{
z7rhfFv55a2Gc9<(k_v>=`ke=(=wMMu=?OCFb;SJ|M0H-%tD%XYQ{#(oxt|>zl8^GV
ze%Y(bhM-b2Ffh>4vaqsd2>N&ANw@g|(~uI?<|<#F
z7+K-j8X{z|Ebt20c##X!JSsXt-Uhs$liFqP*czM9?Su3ss_YFf(L!lj
zPigGCEXXQGN8}#H)(kz?!wP?l5IRWkv2*kJJRIrP`UpPQP4giqN_{^Z4Kz20!zS9K
ztR&jDH81`&VE!GIP*SUNJ27>
zZDLcxKKSSCnw#?*TgllUw+1#)nm24_yd;CwnB89`nf%?tucy)@Imdio>$GPQG*gJi
zj(&s$Yb%E;y!g`Hoaf!OhAV4Kti%fFH$1&k;$S;5bgvt{EY`%DKi0F0cRyo`tFO%P
z4Trxr+TOQ1i>@AS&GQkzoSu#5z^L9Le#B;aHNDU~E0wE0TZv6!cr}^~CSpyiP#T+=
znOR)C4@^EeKK6UM=obw|mQQCJoSU2L>gpOFKkFy<=kqw<$Q2G68XmqqTPG$Wdg(?H
z#K6XeW_wVJTU=a}Ph&AVTWg2L$x!{!@9?=F&ERY`8+FNTMTp0qnaS={Rna0l{7klV=biFGg#;x36lhM&W
zX&fLRIJ8k%`i0Z=|B+KZd|6rR+9zV9AIsl1i>%}C#_QY+`5rWfUH!&jIpZq-3sY>r
z%cYain(j>eRcoX%vfrap-|}sA%7ACzS{p73=9!6frmyL~b^)NFQu}L)c#rlKrX#SU
z`rdLbxRL965u~RY)5^xaXKP&)FvE;dn$6~7X)O?$lDAZ7KG4{7<&`1
zclD|D45ewP%MM~vC2&7O##6bsMy1bAV`+R2i#q6U13tT>0gJ0EAS*$Vp&r*sNmjKI
z+#xG)bc)%0o@;HMa(nHVP^^d2I(V$+BhWOD&1$Of@bC~y6D8AWLK7dq^FIhCeNolF
zetl(O!TW0TyHvd_+yCVrdcj%8qkVS>l7s|dR%{ajl(GR6r+NCDy7el4`d3l_Enq2d
zJzeI6zDhNLT(WYDfbQor=lceTm$m-C*==
zdVIMZ7gv?}`wG?;>(9V`*89#|nXmF*uCh9pIqmPp7yY(&|12ro9oD{jS&S@sjK-_T
zu_7Qy_6x%*c3!Xae49JrlPw*O)qQjsp0a(t?9Co6AUsvocE|rLgk5?xblX=2<>s=Y
z|2W;wq*NR8G~L>5Q^=(}{&u5iZh=YM?elDEaK*KY?Hdojp;oe4ZU|a
zw>unjHzz*bwKv_^*w@SX1&JITx8bTs|s-pPqizX9LZ*69V94)-Gtc-!4{uHahRS^g^vb6N{o5R`Rp&{#)CP!vw
z=J4?Fs`i_uRA!SDM*YK+lTo9u?@)-^jQ;$9axuMqeOTDott~BX!w;@>|9NFAmU}bW
zZrB|8_3U<8&8b*SEjh~(^60RSl==wHZtLH(E~yD_@+kWD!BumM(Oj0N8L9dg7ZVkQ
z)2ju##hAVi&+EDeJZ(VnmN;u9_UMc&2F$2!dBuE{F7W2;Xo-Z}yT-6%9*a5dOA
z7Ou`6n;TxOs}J~N+**A&R7P7QHbrYs;yoD{+3)Tk=yy5->9ET1m$h5t+$Yp-<(PXe
z5FCGQ_U(_4+)w#c(6NeU$mrj!_QlQrv5Kto+2QDqGp_+##42$?YLW0rtYAhj9%`54
zHPSU!f2KV6?g@mVm!uYld;7>qck8S#`XkGGYCy$Ki#`QP*C!I;+>~I~oCn$di_wLi@a4~LfZv93Hdh}N9
zKeD3jMD~3#3X`kY;9IS(<%@V_$Hn`$51_RA_5zEI9U8J#BD)rfZwe#Tsd^9sR_?-B
z?R{}tLzg|UAd}!tD(_zaC*X9fWNyRp-_Rae9}xx2T<*EtZsSIG}h
z7I>+su+HUTtJnHxG)tP!;3ZR=kXWnR>CE)>QCnXcJ$_1coT0X2A(u8_?($x}k0V9n
z6DbP|i`iPn++31$7p*Xv_N<0_iUrY&qpQ!6Uuv&otu4shrBNX9n~%Goex?VD0Ppqp
zrpuO;{Rk8L@Srz5HN+0y$`W#oh{K&;ykT}=fr4d1gkWXqO@Xs5xfx;
zk#cT)0?Hm}($4oLMZNu_TRjATspZ_=Z+^U@Gn4%qO|`DsMn2;v#Lh}g8!aPY1^&r~
zEs#+3;ns^EQ4jWY9$z}!y?lq$9PMZ0ibM9WU?`c`{N^Unu#MH^+_$5NqV3Xgkb%r}
zrMS(=`J18&rm~5So~>KY#<#4i-BC7YVvZ%>xD2+(*|Xh@m`<>Um2kxN5#0H-xhK?rBWnOt-PjH4ikj^(1iMp~0(*GiO
z+tY72SoV$E3*jNO?PtR|bMW
zAl2#Oo;{E1p#tMt_`L328cbmsIpgGRRRS#0Y?0B?QjE}F>9UzQm}-XZi3z)V##I#tol#nohf^yq)Hhoycw=
zC;JcHWx)foF|B>m`f~g!!R{v>Y>n{*qK2OAE6eG-1I(uh<`I=dOD&vLg7C4o^91jo
z#_h@o@#v-$pW0aWrE{bi;L!}8=BhfQY~Mc~sE$AG$b|=MQ@NkC2|S#BY|RM9ZZ$J0
zH|z1Pee;6ac*UR?8!L@H=5-yvb{TOc+Ui&3LCLlC&7iQ`T}H+C@oFs#4MM!SF6-G#
zv65(``9hl6!Sdrn?8!3ZvYtos+iM(&8*Liw;HZg>rd=DQOXf%#U(urp0*pS|Wx|-n
zd_CXyj60dI$fZGyX}cY@oYDQn9aqTI)X-6A8ZPQAfZW#qWSC+9?77^4X=9aZyw&mL
zs>-`daPesjW4zT+0`r1S!1wGiYEFZ;W-MonhZtM1x6@$wzVy7Wp`MsQz*iDfNX-DE
zW}tCeu1?G7@USQ?c)F26`{t+cgn2(}@5yno-v3-9T`AXI-^I}o;
zry$2GP2ZahtapiPp|CP}47E6V-d{+|-2)S1j(QX+7(fc3Ui{~HZr1zpIul(CQNxo(
z%xf`MOzwTwsU3^o$(j3y;X72uD7CP?p8kvv2g8CoD6a5rb(RJ?E>24yD{=Q(hjy6G
zG%2je6V4`-zov2mu_g5yGvh>c_&ze~x43NeglBNrMMOo($;x_f{>0Aqy;;;W^iA&G{E8C=
zGQt#YDTNY>xd*VqklECGE9;3^9G!oIuLb_mpB
zK6*G`16bR26>3Gh$cm%%+AZ&y*V26B72!L1q`+6Yq&t|9!?c*wm?i%TfZ7fw;%JuM
z^4K?a8QKq*L)UgI1Qkfc{KC_z=*~2cxDLduMXoJa*oKoDzTe;hhHFNa+XD^uHetnL
z19V%m^b7WLOB%{5e}?H$@qQ6x5!5r}Dr+fg893}6EZn?{d+#A$ghtkoaU;J#y|W8Q
z)Q2Xku{Y{*AL!nSkT%8v$-0(UB@{`^sdth&(-*n8buuiyJAME(Nva*4rXOsnZ2Y#Z
z>09zDB=3FZF!f(s`{tJW_5Ie!NBFL~=kcfY4eoC`$N7zB8o~ha+V;a%o_WacYfPBP
z)#dz)&|6F!zkhm#e82mDRDE-NT;IBP+&F14Nn;yrFtHokXl&a~8r!yQyRmJfvF+rY
z-#Pc(d)|L%=Ck*jS^HTJz8F#lAy+Q?;z93*=#9R=+D^|h-!zsraDm1N2+Fh2asEfy
zKC;cJFZ;~e#``9-^=Y!L7GVASB!INQ{AZ>X)lhq
z1fw%=ZsRpuV|<$K>Wxwv4%=4y8Kt?u)1|!#WMiW$WVt?8ARN}-5q_Vi69PmpHJljt
zMf)3^?Q-fm!YYQLCS1d!t>2!s0aG(JVcodmettC}@
z+0@(3cG>d;K4+hcAxs1qW^o##pxW1?KkL;&>H;8ZQOxo*!YxrjSuNxVzP>FvCKloiLx^8GtDi|Mq>mKPfc
zhXsvbLD;Y8&z~Kji7qcMuN1}H@GuoS`|{e_YiV)TDri^>>R^D@>#m@f0)4W*z5Vm;
zb_xy-4lT5QeZ2z&aDO1#wXS!6eyq*UJA!cLjYj*8lP#~Wdpu!eL`(b$B@Nkgxjezdj>T;NW<~*0@asqG8DA*4r;T#U!Irm+lQ)*d8Zh(
zfqeZlKTGdT0HUyu)f|N__hq@SC0JW-Hj}6pg_!HkM;dyk3X!j}-nZR0(pH_?Dk`5I=6YQ7cC?i>#AQK7e?9Dc(rEIKQjJ1unts`oOtrV`d^QQH>=C03!s__rT
zkA^1ly)Ct`-3O5<(Mc%kcef`d>xhBJ6PWP+I$m?Z9&c)A_csDzU>C2?mMCz1r1|qT
z-PP&pjN-z*RngrXN_;2Xr`kRW*Wb#;o}PpEFlvtylVlUVdo8uS@Bgvs;Fyf1sjI$4
z+8A6MI#W+i7%11{M1J;pxPY!It@8nUy0o-~aXqlz19n)ZLB{(r-5VME7plQ`g=$Sd
z-YaNtO3^lkYiQF*E4KS4E~aagCMv+asLn$nTq%o;e#a(H9}yXa+R(SQ=cvj247MW5
zp>owL=>`d#UXh)hv$otO?K0jUJhDudOJ+!`5Ko#DsF>?8$`m=nn|}hiIh|`l441ND
z7ark87KgF*#8r|;xpfc1Kc}rW3NRuGan&k@pQH_H6m~;e%nS-6KgI6d)Ke)F%Ji96
zBym`226<^2DmT(oT4=dcZE_VDw^-}XhRrme2M8X0>pt~e=Dguq|Vz^{vd|2tDh#FczuD@h@
ztn_u1AbW>CMDhD2=ZEGs
z2cEnwcLfnY`NZm6H^DApo9`NF_dbJ7R+Ri_lG?!s(l8z-^i^c+;X
z9*uwId{L7gl^yJ^W9@#9k{-R}TfJOgX0%_)DnviyXqRw0S(EL^RzcPseKr=_%s(Yf
zt6tV?9ggMZHJFe2ZkNN?t-9>g^;+2I0jdqM(aBLnC0htk3FvP(la;r=v}I)bu#VHVqmhqMV;E~;-z{Wg*A60FZ;NzRpt5W!s
zJ5s2*eYH8$K2E9b@$`J{eWDKo5LVdKHGdU^-2iZ}_&EQK_^9N6bg2|={sM#8Quo3g
z{21-l-Yq)~$aqO7g-1cZ#W|!$azCiAFhQHdG&_apC&{{n?g(l2p6smCnPKL-$*$#l
z5mR687!XzE@Rlyc{6h62w2SS+3a`Ph|%2l#tUWs!B_*@9#6e>-8E$
z^8k%T6HZz5faxxmn^xbkUmnhJ0f0q$(Z$@0%Z5^c{Q2pgB*aKqb2mr{c!MqJPNt-}
zg7v$>JgY#KD{}c8qS1m$?y~h(^R6P#^Y-{c3^1*Xv?qCmD(Ev@u~Lc5n{=mC7M6F{
z?C0yZLJueYP?*RV7+;yxe1&sa&E5l_E~2vQ4`mNm1OEX*c;Q*^JY1P&@xY%bG_n(P
zlcSuhPI3YH#BFy!lV%~5O#c!ox*LZ&NNQw%%&eWx-t}Bk5|VxO)lT#hEPmP9z})n|
zk1vcoPas(7DuplTGx%B1b(NyvVd#)o{kI-#9|JdnBR#oNVpfA%{HLKD7hjuf&cVfpXlLR#_4
zqJ8^<(#qR6$|Pmfns!P8F(mSP$?uDqL`$buK4kp2>znub$<(~Jp0x$T1~mwaE1G>P
z77Z^ZRvY9@)G}N6aai0HxF6NbHF5*tBSZ0fD0u>jy~%t@56#9u+%pG$-gt-$yZRu6eM1qkt=NrFSsC6{e4L*0g$cng1nqQmg%en%8!{z^>pjd2-*$A|8=
z*xXE+h(k^cZP_pT8!+xgw&5g&m<;vOQDz3w;5~+kTW=*$C--$IXSoeXz9-c?#MqEg
z*JCeI3VHoAH0L82VN}{eg(4dP4}%8H^(65XSd2f@^*T~VmCI8`CtRvfJ2#AZA3xGD
za{3cuiDO_QmRmrzX+XC_!P=a=*2)3!vy)eO@=Hy^!G|6)9v&%2VjicCd96go(s|%n
zHgXA)D6A6$YhxnoWU%$7QhL~aITEF}lD6XqDwCP`8>%RNVKCXj
z#K@FlY0?afr!KIQqXH+PVJ`~E6MananwZoATRkVug*$?L<0#QWjQg*
zvX6wPqflnPs@(jXtWS26z!xwd{1H03=n!+2){$uK+THUJD{L9<%8_-|BX&(^wZApf
zFYm7?(XfX`D+Y_S-bz{#Q5~7}_19$4Q+R~0N=jF(-HA6boljeZ@#*9J?oNNg8awdu
zpB`-_jD&U@FaJKxAbA`hhq}41dkf$C&!wMR1y~P!;h<3s_LVac4E=(LsdM`cd7n@B
zsPU7?%@O6oC3vq*cGS
zPlU~EEamL%EG{k%VkkB@yC^BmgIJmr$z!ZI(&5lKX=NbdIf%R3_3>iC#?}nt3cNh6
zr*8>uE}1F5)cxUyloPy0Dhe!M^=Lk$E6836d!V)1lAPI}8se>};t@!WlN$N(80jI$yn6&GFdvUnf$
zcOikR{WkV$vo|+ggDFvrEAfsS$4@&WEi?PQ?+N5Dl!-0O^W(dl$?cuL8+<~doUOa(
zN6M=AHtJZG*LHW^Kf^pOBZa?rHQR&rS*20G+A^x;IYE*0G2K5?R$t{diWTM!VFDBs
zn^h8}Ha+YeKTK2t28tcDWfzT%ON#=>M&cS09C>Pl(U-_4@h$nd!;RNwInr-%Boxo@
zwOauaT|Kb~^^YfP;l?%!6ql0(okU@?CYPhr;Bq%u=v(fq+77CvYps@(LFngW8BOl6
zUVBN^N!Gu5CIm849MIG!9P0OX
z?(CKdW@47;-7a^7LSMu%L3r&!x{v`O;(C2{Os;KZO}g+&`spMT8{!N%e+R+YJcxlZ>ap@ia3bUc-V(H
zobOEPh_q_st?n~d!ZM}vOx^iR>ddGB$jZ7}*vGe$n%|v}{FeQU34#!L(U;HNlw^|r
z39c5Vj6-^rZ%oeMqKR81kE^X7laWh>PkT}(ruk4R@o>=88v7tdUxsuGIFp>p0&Gib6>KPR+rlyIX-J0(UN4(W=u_XXhgD;IdZVxx4jgYy4izG3qKy
z<&=bd&5F=hnY3Oxw)q^I@gN@OfQ;((GRr~BjB+RgADySszqNa3s=#)+h@94L_q_Z9
z>C&IWSy=o<6469yfCy(H*xvJA(K6TYR;4OUw;Qat^@YO%KUA1K9h8o7oj%oGCc@>T
z5EkTbxTz|-So1{+VXj#`AQBkFwQe7b`-U6&q>>l9BiW-)eU8g~M$#}le$fwfn~i(N
z3UnF1Z+1yaRfV`)?0F6WU*5-zZP=@sXNbto}niF_7t@A`?tnoY3VYpUvuUp04a}NwjJMT+DHT=`p3h-A3cZR@h~Do2jT|G2Gb6r@Qaqxb}Vsc)k{YX)6MG
zj@A2$J6!cWqIkFPy597%T8K8{y)R3mdFC4>pRCUKIU1#QNe?H|DPzTu3AmsBd?C!>a0ntB0TG$i>y4!|*kgzGYSk(hRowKk4`vG`L8=lE
zpq%zc7aK(O0G*wG)sjCq9dwGNbEB$q!MVk6UN+=P$5cwpa`Li5U6AKs6rSYX`a{M8
z@RU`uco(x7#+Q7(ewPG&J$wVtCwVP0mF4oT!`P>40E^R$Rb8}wK)}agklLtL_?#V}og0982h
zUb$kmB?Vsd1Al$!fEhA5M$I47Y1}kVZz5rZ(%Y_BjJx>zhjAvHdl4MpiD->DdqeSf
zd^Nut^q3rG9hP~~5_wEz@NYQibKN^vRN{B0&ruz8L&eB#nyICAV0`wDKle76spH0e
zH_<4M;x$s!95pCdK^);TTS@h?8!^hy8`M=&)~zP8S>2;neU?#d$ULOqsB7HPIJ$U)
z5$5#gROf(GAxD#d(-q=0`T^j@bro++maL=qo}jL5TGC?3m^2pc{Vr8FxF!@iiFq~7
z#(@g6*Nk+B7CovoEek&Fy}6|ONUEoi)l;}W86`Bz@43a{ip^T6@H}Qt+PNQQr3JZl
z(Oo4p(+=cQECpXG0g)1t4`CSBXLCj$RmCI+<9Hj>Va0M}IXSagSZk@y)Sff_gJR-U
zz6f%{OKRuegcLZ>Q^gKt%0Z2f@lMHeEz)nSiR1~^0{$cES@P1gNAussba)%>dTiX_
z!oB1}!L;!j%7TyH3M97UVRCVcCxfgo8yt{G4S!6*!yteE0tKv_oUofto
zHBv-HAiS6|L2vGFeitZ=wD+=-;JMiZIl0GTj(|{i;|Nd~F2<8THWeT5pLsa`S^?O1
zBB|B9#1IPikt^U|hPDUQ1ejF7%9VEVR!vTqTGBOhMrY%2lHURAcwxL2-=~Sl{={X!
z4d`*6B(h%z{_HF^M3b=$oAw%>SR0yJ<6zWKPQBJgy6ZI8XD%1lNvQ6&^jR-dmD8~a
zZ`EsI3m&>$WzjqSbN^5bc6NI=pYmCiV-{anrdJA8{6MOj>uWv{M~PTx7Ov?8UvYcc$vkd`+|c{*>rlbcnS*
zenFP(#8wSMo}D~(x%lI4@MTw{fFiWx3|nZZklpD%@cST4?e7;v{mLU@lg0&
z1vOx(^SM&K-Tn1|l7SzVIDnHD5WWwRzFb^rtE#H1tAE45XmCDX1)=@b8jUm{awse7
zz0c=sc64;KOmV$NC5Sl-QW<2i*<@vB6Q)l%7idlx-?AP8S+NoSp~>5B^9u_PK%#Kh
z7*C`T@VKwf7|dwV;U#aU;iSBBS)B}Ex%wB4nwGR(#1%Bc{Eme|h4%nHE2LwDv>|{w
z2H7)fSy5MlfeC~o1wg>#nJLm*&8MF`$W7w6Htt^_8NuM-%odR~|4`JODYVi~FR*H(
zrp{atT_m#_-MI^kfL|-(%pD(J5{>*@7Hw2!iuysyIiIYg%RKkUN+v
z-T=g<7goS1&UKoNU$ajFqph5plHf|Kq@$u^FLWs)IX!yuP>TEMiMYu4asN-%STd{BP|^w?G;U7l}$q4MX7%*O6|-T-F8W>Bw}^CrZ7tyapceX
znVM$@HFJck6y`#TibIO$OqC8Y5W0#;9*=~w+p>SbFx
zeq5V#v8R(SCl(I6;87e_Ww3eNzJu<*xiLTb9lza1Ln_;fY4s;BR
zzhWs6pg<24%yqqAP^G1%_44$@@tInFzhBY;k%2(;A$Sy&Pmsodl!OFCzmkl;M{cX0
zD?MRdE_*%2f@gA$t}4!FOCj%nXQb|FAx>u~>V`G=x#cwNR+Z?)R_&HKuZFoj$B-#!K|0=SNwNS3X|wF
z+a0|fZO}?g@*e1?q+~ppxHq+J&8bz)#(Rf#vx80+(Tx1WQE?QyP4>POwn?DUw%sH`
zYURmg75ZnvlH98oX3e%{lWQ6zfrS@sH~gV&v77HEH8{d+LyltI3P)W3Qm7xtz?onC
zI_T5n9d(Cu7`%uD&@S*7Z0Aav%9E^a{t+_7@Md}DX;6Ejrec0l)xXp&n|&|dJMX=8
zLOfLE$|N37!1|FZhZ88&H=vZ*CHzMJJX%z>$+3{9N{yNN8V9VDSY>q|Pz}$g$}g(P
zpp6Zq_OS21uFXdQHAEVwI(XfqrZv9pY>%V9{c+<7c%4(jsKj56(4=#-61dToK5N$t
z=CGgT!-1SdLY>IJMbr^@#Xu91bGy&gKtftbQP~JLyAzU7G1wF7TY%9DrC!OFn_K*-
z{)>C8+N9Ypo&i+@2Pkh%xnm@X%#%|xrV1t5F5FiR3u3sPpb|ab_N^eGBou%--sNkvx#SJ}(qqXKdRJFCG8U7&vnDR;3=AZ{1t3zG8u_(CEE>
zS5<=>o%V;m&9EIJ^CJ%0ZMG_TrEJSOh$6eyZA{SlB6(Y`gg2s)@bj?^a%^ZR#hkW$
z?Y+#|iHMD=pjmWr;3e{SFa7b5=iYz4%TBtL=~+}d+&tys4k(!ES9-GRvQj=KHBf~N
zMeKNa1X5>we!PS9piQ6*JCiT!;o*S}H3NbHpPrs#NkzRso)7;Kv7N2d=jZ2(&$?O2
zsjHXHn4+PfIbUviJ>TqGZ?r{zV;)>vTZ?68O_c(sN9Ix0s&N~SrzGombA11PMKGD#
zMr4)d`u5nr*X?4PUwMNu)+fvr?zG}D$MP9sq!6S@}Gf2+E-$S{RA@G^}
z4aWq(5UI@p225d_l8DC?91ASXMt8<+QX@lBuvWY)20{0)V{`^kYjg3k;W@5kCJxuK
zj{@?GDDo~f(=BLf5|BCo=0%#XL2+q1@j?G9`Xn$vxzcBYBbnTbllpuN=p1hlH!)#0
zP~f>Ka)=QI_VPX|jWmVuA~s-{bmEwl$0Bnk<}=;4{#jau5q1NrA6OdrAErvt-F5av
zHii!s!9+SI<)C|m9LEOqrOna}I<)AXx!BI+a6E=OKR-MV$qE1qL7x_$SwKK}I4wUa
z0h^2A+qy)4Q3;X9qe(i`ESqKA=w`TulUa_+3~OR!c7$p8h-=}^%8VH%XJu>>Tfyd0
z+?}+JNm}3yCFMYart^m1z8Kywx=6^moP)etBbfHo^mg9#I-G^>)109a0q_TQuV5K$
z(uwu7Iz~qKKi_$$VJ6HVN3b|ge^m~yzaQf;8O9mt&uy`Yq(S}atDu?c=C1%qijT`6FaZp+Ddb;i+(Cm9Y04Q+sGW|f^i+B-%LwW^nYvT(;0`8
z;$z9Z|CyDO)=@VpCAy!cmf)o*Q@4$R0}uF-%S)D$K)q%1rzCOgaHUuYM#IO|M*~h3
zIKg3I?xhr|O6j&CX0E|Au+)OQlHe=rC#;iFYo$ZLx|7*Ld&`u~sH9b660<^fK2&TP
z3FKpSNd~feYgyXNDnx8xF^e=dchwo%4(4h`_tsy|2a6qannwP-ZlO?)HfeXt+H
z(VAQow&-TRc#}Ls=kk`Kf+K)XHz-<2xa~XWD8c;taliHpzL}C0;P`+~@BxOhj8|Hr
z*Q6*{On!-v%cTAnT9=jj(KElqlmMPhiULJqc9rz`eXSrnTLb$PdrH3Y*?!kwHfnm)
z8zLJ#AMoKa7-LaY3oO}RT4u{t
zNUnEy26&X3@esyNw?C)6H0i!J=R6-60%6fAjd*
zJ?St17~$~=TOBMN$O~XTnjTz7$K6_^QsXsAa7eK&WU!iRvnmFAx=Gm~nMDX1{oMp8
zVd|DuK(u3kE96URU><@<}vE
ziL|#UC)l`Y>QeF*A%tImsF+nugMsdFc=+zMW;!+SJ
zbSg_`#qLfHJ1YwyFT@Z{d{sy!)wV6tU>O>J_zI|6=6qQz_hnT-rWtcGXx%@pmneVf+eT-wz+RM=
z5FHZ6S97D{U}oT!L1fVq#dS(kK%b~o!e4DQn)BviW!K(KS#A(RQQ@?Doy<8#7wl{Z
z?$U0iX0+XHSNwAAdx1_CRN=*?Aozj4k*-3x+Ua#FpVGh`q_2~hUOqz`t^vsAT=F#e
zO{MnpLUyf-R`WXphT}@-x-K>-8mWm$D
zE*mjl;&wK^dyM5VH2g&9(7V;rgV<#r;npBMNve)o-sfv0pVgtu*E}Dj-6PDAY;rQ(
zeFVTzNM}`8H+lYxX;~B{noQVFX=iVYt(m;UV;1!=6d9h|G0;(k_VElI6Bg#0aftLp6hthR$Vm467-kcuxUU3-=R~^wRCr2YaQqJEh!B
zMW)iF4K2hd)HXNE?hv!n-RNi+M2)4-I#27x;`_@7$JUF6s*%hfoxc^T`RCy{u{=YO
z(VG=gO(yFyHtHR&%^pXi6qLA0w!A10gby>Crl)Y45XFEwpQ=i3q}3Bi3^w7Oe3Q3FuR4lgcv
zL7KDS;bD+ukX$m!@qCq)f}-eGvvs5e4~KmbVxMMtFbzs6v<@u%cWrkJRy#uW-0l!=&B
zOI69JbBv-fw?)kuo1|ljlOCK?)I&Gn%~fj?jr|U4#&UB>rm3S#?^IBuvN(y)7J0|(
zpMQ%WViL$K%z#WhQ!(vs1kxxt8^K6Nw+WyV
z2-Xt99XfLHX-M)?W2M2*p%fgfV&xViD7qLAA4CBL7}ShcYV77>6B=z+O~lBAXV6KM
zN7N?^PsDdZKzwOsTn8VuyG!(&Toi>tK8)4@z*WLz8U{H9xcg6OPkWz-WSW1VAGx24
zTl9pA=4Lk(gC!d{br!l_Cdbj%n%A{Iiug*$#MhE@Ybky2S4OB~y@~<``$teHX_yvy
z6kGVr#X_e0az@3LAYlvZHWLgM*NBKs8%Dy54!^*4kfR?=gmyi=!cpU)GU%1Fe1nr*
zE)z%)a3Yg5B2MS!b3d7vS`Zn?O`Mx55DpAw7unB6MDnF__BV(vv1nY7B*I1ec|hgR
zt=6>5*xHjf!kfpkepF*~{ZcSxp(G-~#P3PIMxMY0FQW*b2lyG1mmMblE0&3m0opeq
zBI4V;qy=p3G9^%%dMt2eZvP-VE{V4r|IC3%N~_B<&5PPo0gc(JLw_VH@;2JC0;O)N
z#BA(P2C=v*@rR{+hgmkDr}pnx-=|pW_$a#72B+tQ%6kt?lkvpVp+4!ceTB?VE=ha6xYY&S9;H%^S>0t*Sqc;3#fKHvgg~6_dj17MnVJgS@
za4!-cUG~lI&Um3+KsOs@+Y&2N7X4N5xTjItPQDG=;iYWFXDVfS3%lMTEU|hiwWDD$
zMjVaEW~#pE>0Xl8MKb77DbaHnVEWeTlUgR4&?(IHU5dbw-K-Bw@Yo$Ln=+iHLvfFh5af
z%08PB`}jk6diiM{Wnu*AhXyJ5QdL6rml!jDyd6-$S*d=3V6z-Osl2-Apih+^mGsIp
z8ON>CXyz`~bBx@ZUoYJhDRDx%?~#Njo^QQ!?EpzzhXx1Bl*(4>O+c-fGl=#NQawLj
zUFp`Uf$F8QGKum92JH^DT)FRvdmu}$esoznt+oa`E2=N?BMs&YWj8lBASL>!VI49r
zJjx>jn$Jq1dH#jI-WN8nZqT2F@ip;v-i-AWNN-UTW1e6H<6QIv+>|m-WCJU5TjD6w
z?>9wumT=k5<&7_zr(kIkq%(L;R>e#ju~!V{cOQM*y@l+vC~jk5xP@;7BFq`?mo(hT5Ch6x=@3+?#@Q{$-?
z%PsdY6z5}3W?vbUvRC{&rMY!KvSO9}{p`
zXyGMx+07A4J7+nsihb3g%6_Tx6s%=>Ws6+-MS_s*%+qM+%*5XZU#8UkeW5c01Y|I%$SPb^JH+bQmf0*IXmzY~usD9UubB*sFo#QKh}u>q)4ngK48f
zPc+H=(s)7JLl-@10xxIt!%U${A@|21$_eh{AkEWmx40Q}+4y@DGu&>h13=p4!0riU
zLi3Kqax<}rvvRiHBB+U%H|vD&Iud#ild#wvx!4pe;HzR%bd9A(`YgL)>KRtId8h7N
zk=2MOW@$0zJ>xMhhsA0}XzXOEYxM$vIx4lh#c?CeQ2BrWAIxWZ4#A|guwvQn9NI9`
z`uv3qG=X{Wxu!>!;k4@8F`Fa|AU&{wi(X1RvTy~JIv72khv=QVXg(3;KHsg1YJX~(
z??UksnPm`QEqgwnA$bgzg-PKFJW@y+)RqcFj9APG>pe;4r3ors#d?_>A7^pS!
z85-f;9|70t$dZPNzm08px!XrvWJsu9YQ^eR*Qd*|
z%!<ywgJ}^@=*d==qCU%z_s5E>-@Vg>bt+irZ6V1?4s$)ki>#$G;Z=E>
z_M+7u-eF%!HM%d~h1c$4$Ck!3aKQO-m5@Y!g$eU$sINsxBc(Mxyau7;-0ueED&DoBK|(=^pS2#B#4_W{vWB0C#5TBx{rW@L
zWGj2nTduz+O24}Dw2!jF#c-_~AMQsV;l)P&@bW4QyYXdMdrx~A6;Nvg
zhbJ#)c(y#kI2iEE>f!eoLrqA4xcV$VTSb`YqeX4-H+W!B%AJ*$vqC&