diff --git a/.cspell.json b/.cspell.json index b13fa591f..c94adfffd 100644 --- a/.cspell.json +++ b/.cspell.json @@ -28,14 +28,15 @@ "Bluesky", "Boguslawski", "bradrydzewski", + "buildkit", "BUILDPLATFORM", "buildx", - "buildkit", "caddyfile", "ccmenu", "CERTDIR", "certmagic", "charmbracelet", + "checkmake", "cicd", "ciphertext", "Cloudron", @@ -48,6 +49,7 @@ "datacenter", "DATASOURCE", "Debugf", + "dejavusans", "Demilestoned", "desaturate", "devx", @@ -119,15 +121,16 @@ "mapstructure", "markdownlint", "mdbook", - "Milestoned", "memswap", "Metas", "mhmxs", + "Milestoned", "moby", "Msgf", "mstruebing", "multiarch", "multierr", + "narqo", "netdns", "Netrc", "Nextcloud", @@ -142,6 +145,7 @@ "octocat", "openapi", "opensource", + "opentype", "Pacman", "picus", "Pinia", @@ -175,6 +179,7 @@ "secprofile", "selfhosted", "sess", + "sfnt", "shellescape", "sigstore", "Sonatype", @@ -208,8 +213,8 @@ "unsanitize", "Upsert", "urfave", - "useragent", "usecase", + "useragent", "varchar", "varz", "Vieter", @@ -238,32 +243,33 @@ "zerologger" ], "ignorePaths": [ - "*.excalidraw", - "*.svg", - "*_test.go", ".cspell.json", ".git/**/*", ".gitignore", ".golangci.yaml", ".vscode/extensions.json", + "*_test.go", + "*.excalidraw", + "*.svg", + "**/*.pb.go", + "**/fixtures/**", + "**/testdata/**", "CHANGELOG.md", - "Makefile", + "docs/versioned_docs/", "flake.nix", "go.mod", - "**/*.pb.go", + "Makefile", + "package.json", "server/store/datastore/migration/**/*", "web/components.d.ts", "web/src/assets/locales/**/*", - "**/fixtures/**", - "**/testdata/**", - "docs/versioned_docs/", - "package.json", // generated - "go.sum", - "flake.lock", - "pnpm-lock.yaml", + "**/mocks/**", "**/node_modules/**/*", "cmd/server/openapi/docs.go", + "flake.lock", + "go.sum", + "pnpm-lock.yaml", "renovate.json", // TODO: remove the following "docs/**/*.js", diff --git a/.gitpod.yml b/.gitpod.yml index 836669fac..6e3d463a7 100644 --- a/.gitpod.yml +++ b/.gitpod.yml @@ -10,7 +10,7 @@ tasks: WOODPECKER_BACKEND_DOCKER_NETWORK: ci_default init: | # renovate: datasource=golang-version depName=golang - GO_VERSION=1.25.5 + GO_VERSION=1.26.0 rm -rf ~/go curl -fsSL https://dl.google.com/go/go$GO_VERSION.linux-amd64.tar.gz | tar xzs -C ~/ go mod tidy diff --git a/.golangci.yaml b/.golangci.yaml index be309508d..f76440bfd 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -49,10 +49,10 @@ linters: agent: list-mode: lax files: - - '**/agent/**/*.go' - '**/agent/*.go' - - '**/cmd/agent/**/*.go' + - '**/agent/**/*.go' - '**/cmd/agent/*.go' + - '**/cmd/agent/**/*.go' deny: - pkg: go.woodpecker-ci.org/woodpecker/v3/cli - pkg: go.woodpecker-ci.org/woodpecker/v3/cmd/cli @@ -63,70 +63,89 @@ linters: cli: list-mode: lax files: - - '**/cli/**/*.go' - '**/cli/*.go' - - '**/cmd/cli/**/*.go' + - '**/cli/**/*.go' - '**/cmd/cli/*.go' + - '**/cmd/cli/**/*.go' deny: - pkg: go.woodpecker-ci.org/woodpecker/v3/agent - - pkg: go.woodpecker-ci.org/woodpecker/v3/server - pkg: go.woodpecker-ci.org/woodpecker/v3/cmd/agent - pkg: go.woodpecker-ci.org/woodpecker/v3/cmd/server + - pkg: go.woodpecker-ci.org/woodpecker/v3/rpc + - pkg: go.woodpecker-ci.org/woodpecker/v3/server - pkg: go.woodpecker-ci.org/woodpecker/v3/web pipeline: list-mode: lax files: - - '**/pipeline/**/*.go' - - '**/pipeline/*.go' - '!**/cli/pipeline/*.go' - '!**/cli/pipeline/**/*.go' - '!**/server/pipeline/*.go' - '!**/server/pipeline/**/*.go' + - '**/pipeline/*.go' + - '**/pipeline/**/*.go' deny: - pkg: go.woodpecker-ci.org/woodpecker/v3/agent - pkg: go.woodpecker-ci.org/woodpecker/v3/cli - pkg: go.woodpecker-ci.org/woodpecker/v3/cmd + - pkg: go.woodpecker-ci.org/woodpecker/v3/rpc - pkg: go.woodpecker-ci.org/woodpecker/v3/server - pkg: go.woodpecker-ci.org/woodpecker/v3/web server: list-mode: lax files: - - '**/server/**/*.go' - - '**/server/*.go' - - '**/cmd/server/**/*.go' - '**/cmd/server/*.go' - - '**/web/**/*.go' + - '**/cmd/server/**/*.go' + - '**/server/*.go' + - '**/server/**/*.go' - '**/web/*.go' + - '**/web/**/*.go' deny: - pkg: go.woodpecker-ci.org/woodpecker/v3/agent - pkg: go.woodpecker-ci.org/woodpecker/v3/cli - pkg: go.woodpecker-ci.org/woodpecker/v3/cmd/agent - pkg: go.woodpecker-ci.org/woodpecker/v3/cmd/cli - pkg: go.woodpecker-ci.org/woodpecker/v3/woodpecker-go/woodpecker + rpc: + list-mode: lax + files: + - '!**/agent/rpc/*.go' + - '!**/agent/rpc/**/*.go' + - '!**/server/rpc/*.go' + - '!**/server/rpc/**/*.go' + - '**/rpc/*.go' + - '**/rpc/**/*.go' + deny: + - pkg: go.woodpecker-ci.org/woodpecker/v3/agent + - pkg: go.woodpecker-ci.org/woodpecker/v3/cli + - pkg: go.woodpecker-ci.org/woodpecker/v3/cmd + - pkg: go.woodpecker-ci.org/woodpecker/v3/server + - pkg: go.woodpecker-ci.org/woodpecker/v3/web shared: list-mode: lax files: - - '**/shared/**/*.go' - - '**/shared/*.go' - '!**/pipeline/shared/*.go' - '!**/pipeline/shared/**/*.go' + - '**/shared/*.go' + - '**/shared/**/*.go' deny: - pkg: go.woodpecker-ci.org/woodpecker/v3/agent - pkg: go.woodpecker-ci.org/woodpecker/v3/cli - pkg: go.woodpecker-ci.org/woodpecker/v3/cmd - pkg: go.woodpecker-ci.org/woodpecker/v3/pipeline + - pkg: go.woodpecker-ci.org/woodpecker/v3/rpc - pkg: go.woodpecker-ci.org/woodpecker/v3/server - pkg: go.woodpecker-ci.org/woodpecker/v3/web woodpecker-go: list-mode: lax files: - - '**/woodpecker-go/woodpecker/**/*.go' - '**/woodpecker-go/woodpecker/*.go' + - '**/woodpecker-go/woodpecker/**/*.go' deny: - pkg: go.woodpecker-ci.org/woodpecker/v3/agent - pkg: go.woodpecker-ci.org/woodpecker/v3/cli - pkg: go.woodpecker-ci.org/woodpecker/v3/cmd - pkg: go.woodpecker-ci.org/woodpecker/v3/pipeline + - pkg: go.woodpecker-ci.org/woodpecker/v3/rpc - pkg: go.woodpecker-ci.org/woodpecker/v3/server - pkg: go.woodpecker-ci.org/woodpecker/v3/shared - pkg: go.woodpecker-ci.org/woodpecker/v3/web diff --git a/.mockery.yaml b/.mockery.yaml index 0990c2916..1f0dfe261 100644 --- a/.mockery.yaml +++ b/.mockery.yaml @@ -5,7 +5,7 @@ filename: mock_{{.InterfaceName}}.go pkgname: mocks recursive: true packages: - go.woodpecker-ci.org/woodpecker/v3/pipeline/rpc: + go.woodpecker-ci.org/woodpecker/v3/rpc: config: recursive: false go.woodpecker-ci.org/woodpecker/v3/server/forge: diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ec3b53f24..b1c6cad74 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -12,7 +12,7 @@ repos: - id: trailing-whitespace exclude: ^docs/versioned_docs/.+/40-cli.md$ - repo: https://github.com/golangci/golangci-lint - rev: v2.7.2 + rev: v2.10.1 hooks: - id: golangci-lint - repo: https://github.com/igorshubovych/markdownlint-cli @@ -22,7 +22,7 @@ repos: exclude: '^(docs/versioned_docs/.*|CHANGELOG.md)$' language_version: 22.15.1 - repo: https://github.com/mrtazz/checkmake - rev: 0.2.2 + rev: v0.3.2 hooks: - id: checkmake exclude: '^docker/Dockerfile.make$' # actually a Dockerfile and not a makefile @@ -31,11 +31,11 @@ repos: hooks: - id: hadolint - repo: https://github.com/rbubley/mirrors-prettier - rev: v3.7.4 + rev: v3.8.1 hooks: - id: prettier - repo: https://github.com/adrienverge/yamllint.git - rev: v1.37.1 + rev: v1.38.0 hooks: - id: yamllint args: [--strict, -c=.yamllint.yaml] diff --git a/.woodpecker/binaries.yaml b/.woodpecker/binaries.yaml index 63932ae1c..f24e6bc33 100644 --- a/.woodpecker/binaries.yaml +++ b/.woodpecker/binaries.yaml @@ -7,9 +7,9 @@ when: - .woodpecker/binaries.yaml variables: - - &golang_image 'docker.io/golang:1.25' + - &golang_image 'docker.io/golang:1.26' - &node_image 'docker.io/node:24-alpine' - - &xgo_image 'docker.io/techknowlogick/xgo:go-1.25.x' + - &xgo_image 'docker.io/techknowlogick/xgo:go-1.26.x' # cspell:words bindata netgo diff --git a/.woodpecker/docker.yaml b/.woodpecker/docker.yaml index 3f6348056..67cf70d84 100644 --- a/.woodpecker/docker.yaml +++ b/.woodpecker/docker.yaml @@ -1,8 +1,8 @@ variables: - - &golang_image 'docker.io/golang:1.25' + - &golang_image 'docker.io/golang:1.26' - &node_image 'docker.io/node:24-alpine' - - &xgo_image 'docker.io/techknowlogick/xgo:go-1.25.x' - - &buildx_plugin 'docker.io/woodpeckerci/plugin-docker-buildx:6.0.3' + - &xgo_image 'docker.io/techknowlogick/xgo:go-1.26.x' + - &buildx_plugin 'docker.io/woodpeckerci/plugin-docker-buildx:6.0.4' - &platforms_release 'linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/386,linux/amd64,linux/ppc64le,linux/riscv64,linux/s390x,freebsd/arm64,freebsd/amd64,openbsd/arm64,openbsd/amd64' - &platforms_server 'linux/arm/v7,linux/arm64/v8,linux/amd64,linux/ppc64le,linux/riscv64' - &platforms_preview 'linux/amd64' diff --git a/.woodpecker/docs.yaml b/.woodpecker/docs.yaml index 583b18e36..747f6e67e 100644 --- a/.woodpecker/docs.yaml +++ b/.woodpecker/docs.yaml @@ -1,5 +1,5 @@ variables: - - &golang_image 'docker.io/golang:1.25' + - &golang_image 'docker.io/golang:1.26' - &node_image 'docker.io/node:24-alpine' - &alpine_image 'docker.io/alpine:3.23' - path: &when_path @@ -79,7 +79,7 @@ steps: - event: manual - name: deploy-preview - image: docker.io/woodpeckerci/plugin-surge-preview:1.4.1 + image: docker.io/woodpeckerci/plugin-surge-preview:1.4.2 settings: path: 'docs/build/' surge_token: diff --git a/.woodpecker/links.yaml b/.woodpecker/links.yaml index 1a53972f5..f23ce6056 100644 --- a/.woodpecker/links.yaml +++ b/.woodpecker/links.yaml @@ -4,7 +4,7 @@ when: steps: - name: links - image: docker.io/lycheeverse/lychee:0.22.0 + image: docker.io/lycheeverse/lychee:0.23.0 failure: ignore depends_on: [] commands: diff --git a/.woodpecker/release-helper.yaml b/.woodpecker/release-helper.yaml index 62766dc34..252bb159c 100644 --- a/.woodpecker/release-helper.yaml +++ b/.woodpecker/release-helper.yaml @@ -6,7 +6,7 @@ when: steps: - name: release-helper - image: docker.io/woodpeckerci/plugin-ready-release-go:3.4.0 + image: docker.io/woodpeckerci/plugin-ready-release-go:3.4.1 settings: release_branch: ${CI_COMMIT_BRANCH} forge_type: github diff --git a/.woodpecker/securityscan.yaml b/.woodpecker/securityscan.yaml index 7382a027b..ee396b62c 100644 --- a/.woodpecker/securityscan.yaml +++ b/.woodpecker/securityscan.yaml @@ -34,6 +34,7 @@ steps: services: server: image: *trivy_plugin + failure: ignore # as we don't care about the exit code settings: service: true db-repository: mirror.gcr.io/aquasec/trivy-db:2 diff --git a/.woodpecker/static.yaml b/.woodpecker/static.yaml index d6b48144a..d46741e9a 100644 --- a/.woodpecker/static.yaml +++ b/.woodpecker/static.yaml @@ -3,7 +3,7 @@ when: steps: - name: lint-editorconfig - image: docker.io/woodpeckerci/plugin-editorconfig-checker:0.3.2 + image: docker.io/woodpeckerci/plugin-editorconfig-checker:0.3.3 depends_on: [] when: - event: pull_request diff --git a/.woodpecker/test.yaml b/.woodpecker/test.yaml index 8387f45ae..4a26a65a5 100644 --- a/.woodpecker/test.yaml +++ b/.woodpecker/test.yaml @@ -1,5 +1,5 @@ variables: - - &golang_image 'docker.io/golang:1.25' + - &golang_image 'docker.io/golang:1.26' - &when - path: &when_path # related config files - '.woodpecker/test.yaml' @@ -11,6 +11,7 @@ variables: - 'pipeline/schema/**' # tools updates - Makefile + - 'codecov.yaml' event: pull_request when: @@ -55,7 +56,7 @@ steps: lint: depends_on: - vendor - image: golangci/golangci-lint:v2.7.2 + image: golangci/golangci-lint:v2.10.1 commands: - make lint when: *when @@ -127,7 +128,7 @@ steps: - test - sqlite pull: true - image: docker.io/woodpeckerci/plugin-codecov:2.1.6 + image: docker.io/woodpeckerci/plugin-codecov:2.2.2 settings: files: - agent-coverage.out @@ -151,7 +152,7 @@ services: when: *when mysql: - image: docker.io/mysql:9.5.0 + image: docker.io/mysql:9.6.0 ports: ['3306'] environment: MYSQL_DATABASE: test diff --git a/CHANGELOG.md b/CHANGELOG.md index 60700a909..2975ced04 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,176 @@ # Changelog +## [3.13.0](https://github.com/woodpecker-ci/woodpecker/releases/tag/v3.13.0) - 2026-01-14 + +### ❤️ Thanks to all contributors! ❤️ + +@6543, @Javex, @KhalidAlansary, @MartinSchmidt, @abhiyerra, @anbraten, @bentasker, @gjuoun, @gsaslis, @henkka, @jolheiser, @mogsie, @qwerty287, @sloonz, @sugar700, @tuxmainy, @xoxys + +### 🔒 Security + +- Update quic-go/qpack & quic-go/quic-go [[#5885](https://github.com/woodpecker-ci/woodpecker/pull/5885)] +- fix: updateRepoPermissions to cleanup old permissions [[#5790](https://github.com/woodpecker-ci/woodpecker/pull/5790)] + +### ✨ Features + +- Add cli contexts [[#5929](https://github.com/woodpecker-ci/woodpecker/pull/5929)] + +### 📈 Enhancement + +- Allow to add a note to secrets [[#5898](https://github.com/woodpecker-ci/woodpecker/pull/5898)] +- Log addon errors [[#5923](https://github.com/woodpecker-ci/woodpecker/pull/5923)] +- Custom vars for crons [[#5897](https://github.com/woodpecker-ci/woodpecker/pull/5897)] +- Allow to disable a cron [[#5896](https://github.com/woodpecker-ci/woodpecker/pull/5896)] +- Add background to status icons [[#5880](https://github.com/woodpecker-ci/woodpecker/pull/5880)] +- Fix dead page and cleanup router [[#5519](https://github.com/woodpecker-ci/woodpecker/pull/5519)] +- feat(kubernetes): add support for pod affinity and anti-affinity configurations [[#5854](https://github.com/woodpecker-ci/woodpecker/pull/5854)] +- Public key endpoint [[#5860](https://github.com/woodpecker-ci/woodpecker/pull/5860)] +- Allow untrusted repo to still drop network for steps [[#5820](https://github.com/woodpecker-ci/woodpecker/pull/5820)] +- Add support for headless Kubernetes services [[#5764](https://github.com/woodpecker-ci/woodpecker/pull/5764)] +- server/forge: rename var to be more descriptive and test value [[#5806](https://github.com/woodpecker-ci/woodpecker/pull/5806)] +- add events query parameter to badge url [[#5728](https://github.com/woodpecker-ci/woodpecker/pull/5728)] +- Extract default step-builder options into server [[#5785](https://github.com/woodpecker-ci/woodpecker/pull/5785)] +- feat: include CI_COMMIT_TAG env in deployment events [[#5773](https://github.com/woodpecker-ci/woodpecker/pull/5773)] + +### 🐛 Bug Fixes + +- Use repo-user for api call of cron [[#5967](https://github.com/woodpecker-ci/woodpecker/pull/5967)] +- Close opened file on LogFind [[#5961](https://github.com/woodpecker-ci/woodpecker/pull/5961)] +- Delete/Deactivate repo ignores missing repo at forge [[#5953](https://github.com/woodpecker-ci/woodpecker/pull/5953)] +- Correctly update repo permissions [[#5928](https://github.com/woodpecker-ci/woodpecker/pull/5928)] +- Revert repos pagination for GH and BB [[#5924](https://github.com/woodpecker-ci/woodpecker/pull/5924)] +- fix: send correct argument to rpc call for name/url [[#5922](https://github.com/woodpecker-ci/woodpecker/pull/5922)] +- fix: secrets-file flag [[#5909](https://github.com/woodpecker-ci/woodpecker/pull/5909)] +- Do not run crons for disabled repos [[#5884](https://github.com/woodpecker-ci/woodpecker/pull/5884)] +- Show warning if there is no workflow to run [[#5883](https://github.com/woodpecker-ci/woodpecker/pull/5883)] +- fix(datastore): fix pagination bug in workflowsDelete skipping records [[#5881](https://github.com/woodpecker-ci/woodpecker/pull/5881)] +- Remove rounded corners in fullscreen log view [[#5879](https://github.com/woodpecker-ci/woodpecker/pull/5879)] +- Fix some ListItems and Queue view background in dark mode [[#5878](https://github.com/woodpecker-ci/woodpecker/pull/5878)] +- Make disabled checkboxes match overall style [[#5869](https://github.com/woodpecker-ci/woodpecker/pull/5869)] +- Fix CLI trusted updating [[#5861](https://github.com/woodpecker-ci/woodpecker/pull/5861)] +- Send configuration as part of the request for external configuration [[#5831](https://github.com/woodpecker-ci/woodpecker/pull/5831)] +- fix(bitbucketdatacenter): fix CI_COMMIT_PULL_REQUEST [[#5769](https://github.com/woodpecker-ci/woodpecker/pull/5769)] +- On set/get of repo make sure forge_id is set and on fetch respected [[#5717](https://github.com/woodpecker-ci/woodpecker/pull/5717)] +- Improve repair endpoints [[#5767](https://github.com/woodpecker-ci/woodpecker/pull/5767)] + +### 📚 Documentation + +- chore(deps): lock file maintenance [[#5963](https://github.com/woodpecker-ci/woodpecker/pull/5963)] +- chore(deps): update dependency @types/node to v24.10.7 [[#5954](https://github.com/woodpecker-ci/woodpecker/pull/5954)] +- chore(deps): update dependency @types/react to v19.2.8 [[#5941](https://github.com/woodpecker-ci/woodpecker/pull/5941)] +- chore(deps): update dependency @types/node to v24.10.6 [[#5935](https://github.com/woodpecker-ci/woodpecker/pull/5935)] +- chore(deps): update dependency @types/node to v24.10.5 [[#5933](https://github.com/woodpecker-ci/woodpecker/pull/5933)] +- fix(docs): update woodpecker-cli secret command [[#5927](https://github.com/woodpecker-ci/woodpecker/pull/5927)] +- Update Docs and nix-flake to reflect current dev environment [[#5926](https://github.com/woodpecker-ci/woodpecker/pull/5926)] +- Update Helm chart installation command [[#5872](https://github.com/woodpecker-ci/woodpecker/pull/5872)] +- docs: add BunnyCDN Cache Purge Plugin [[#5906](https://github.com/woodpecker-ci/woodpecker/pull/5906)] +- chore(deps): update dependency isomorphic-dompurify to v2.35.0 [[#5904](https://github.com/woodpecker-ci/woodpecker/pull/5904)] +- chore(deps): update dependency @types/node to v24.10.4 [[#5862](https://github.com/woodpecker-ci/woodpecker/pull/5862)] +- chore(deps): update docs npm deps non-major [[#5855](https://github.com/woodpecker-ci/woodpecker/pull/5855)] +- chore(deps): update docs npm deps non-major [[#5829](https://github.com/woodpecker-ci/woodpecker/pull/5829)] +- Update link for Codeberg Pages Deploy plugin [[#5811](https://github.com/woodpecker-ci/woodpecker/pull/5811)] +- chore(deps): update dependency yaml to v2.8.2 [[#5803](https://github.com/woodpecker-ci/woodpecker/pull/5803)] +- chore(deps): update dependency prettier to v3.7.3 [[#5799](https://github.com/woodpecker-ci/woodpecker/pull/5799)] +- chore(deps): update docs npm deps non-major [[#5791](https://github.com/woodpecker-ci/woodpecker/pull/5791)] +- chore(deps): update dependency isomorphic-dompurify to v2.33.0 [[#5778](https://github.com/woodpecker-ci/woodpecker/pull/5778)] +- chore(deps): update docs npm deps non-major [[#5774](https://github.com/woodpecker-ci/woodpecker/pull/5774)] + +### 📦️ Dependency + +- fix(deps): update module gitlab.com/gitlab-org/api/client-go to v1.14.0 [[#5969](https://github.com/woodpecker-ci/woodpecker/pull/5969)] +- fix(deps): update golang-packages [[#5966](https://github.com/woodpecker-ci/woodpecker/pull/5966)] +- fix(deps): update module gitlab.com/gitlab-org/api/client-go to v1.12.0 [[#5962](https://github.com/woodpecker-ci/woodpecker/pull/5962)] +- chore(deps): update dependency simple-icons to v16.5.0 [[#5957](https://github.com/woodpecker-ci/woodpecker/pull/5957)] +- fix(deps): update golang-packages [[#5956](https://github.com/woodpecker-ci/woodpecker/pull/5956)] +- chore(deps): update dependency @types/node to v24.10.7 [[#5955](https://github.com/woodpecker-ci/woodpecker/pull/5955)] +- fix(deps): update module github.com/google/go-github/v80 to v81 [[#5946](https://github.com/woodpecker-ci/woodpecker/pull/5946)] +- chore(deps): update woodpeckerci/plugin-git docker tag to v2.8.0 [[#5945](https://github.com/woodpecker-ci/woodpecker/pull/5945)] +- chore(deps): update golangci/golangci-lint docker tag to v2.8.0 [[#5944](https://github.com/woodpecker-ci/woodpecker/pull/5944)] +- chore(deps): update docker.io/woodpeckerci/plugin-codecov docker tag to v2.2.0 [[#5943](https://github.com/woodpecker-ci/woodpecker/pull/5943)] +- chore(deps): update web npm deps non-major [[#5942](https://github.com/woodpecker-ci/woodpecker/pull/5942)] +- chore(deps): update docker.io/woodpeckerci/plugin-surge-preview docker tag to v1.4.2 [[#5938](https://github.com/woodpecker-ci/woodpecker/pull/5938)] +- chore(deps): update docker.io/woodpeckerci/plugin-ready-release-go docker tag to v3.4.1 [[#5937](https://github.com/woodpecker-ci/woodpecker/pull/5937)] +- chore(deps): update docker.io/woodpeckerci/plugin-docker-buildx docker tag to v6.0.4 [[#5936](https://github.com/woodpecker-ci/woodpecker/pull/5936)] +- chore(deps): update docker.io/woodpeckerci/plugin-editorconfig-checker docker tag to v0.3.3 [[#5934](https://github.com/woodpecker-ci/woodpecker/pull/5934)] +- fix(deps): update module gitlab.com/gitlab-org/api/client-go to v1.11.0 [[#5919](https://github.com/woodpecker-ci/woodpecker/pull/5919)] +- chore(deps): lock file maintenance [[#5916](https://github.com/woodpecker-ci/woodpecker/pull/5916)] +- chore(deps): update dependency simple-icons to v16.4.0 [[#5915](https://github.com/woodpecker-ci/woodpecker/pull/5915)] +- fix(deps): update module github.com/mattn/go-sqlite3 to v1.14.33 [[#5910](https://github.com/woodpecker-ci/woodpecker/pull/5910)] +- chore(deps): lock file maintenance [[#5913](https://github.com/woodpecker-ci/woodpecker/pull/5913)] +- chore(deps): lock file maintenance [[#5907](https://github.com/woodpecker-ci/woodpecker/pull/5907)] +- chore(deps): update dependency simple-icons to v16.3.0 [[#5905](https://github.com/woodpecker-ci/woodpecker/pull/5905)] +- chore(deps): update web npm deps non-major [[#5903](https://github.com/woodpecker-ci/woodpecker/pull/5903)] +- fix(deps): update module google.golang.org/grpc to v1.78.0 [[#5901](https://github.com/woodpecker-ci/woodpecker/pull/5901)] +- chore(deps): lock file maintenance [[#5895](https://github.com/woodpecker-ci/woodpecker/pull/5895)] +- fix(deps): update module github.com/tink-crypto/tink-go/v2 to v2.6.0 [[#5894](https://github.com/woodpecker-ci/woodpecker/pull/5894)] +- chore(deps): update dependency @antfu/eslint-config to v6.7.2 [[#5893](https://github.com/woodpecker-ci/woodpecker/pull/5893)] +- chore(deps): update dependency vue-i18n to v11.2.7 [[#5892](https://github.com/woodpecker-ci/woodpecker/pull/5892)] +- chore(deps): update dependency vue-tsc to v3.2.0 [[#5891](https://github.com/woodpecker-ci/woodpecker/pull/5891)] +- Migrate to maintained tink-go [[#5886](https://github.com/woodpecker-ci/woodpecker/pull/5886)] +- chore(deps): update web npm deps non-major [[#5887](https://github.com/woodpecker-ci/woodpecker/pull/5887)] +- fix(deps): update module gitlab.com/gitlab-org/api/client-go to v1.10.0 [[#5888](https://github.com/woodpecker-ci/woodpecker/pull/5888)] +- fix(deps): update golang-packages [[#5877](https://github.com/woodpecker-ci/woodpecker/pull/5877)] +- fix(deps): update module gitlab.com/gitlab-org/api/client-go to v1.9.0 [[#5873](https://github.com/woodpecker-ci/woodpecker/pull/5873)] +- fix(deps): update golang-packages [[#5870](https://github.com/woodpecker-ci/woodpecker/pull/5870)] +- chore(deps): lock file maintenance [[#5868](https://github.com/woodpecker-ci/woodpecker/pull/5868)] +- fix(deps): update module github.com/gdgvda/cron to v0.6.0 [[#5867](https://github.com/woodpecker-ci/woodpecker/pull/5867)] +- chore(deps): update dependency @intlify/unplugin-vue-i18n to v11.0.3 [[#5866](https://github.com/woodpecker-ci/woodpecker/pull/5866)] +- chore(deps): update dependency @antfu/eslint-config to v6.7.1 [[#5865](https://github.com/woodpecker-ci/woodpecker/pull/5865)] +- chore(deps): update web npm deps non-major [[#5864](https://github.com/woodpecker-ci/woodpecker/pull/5864)] +- chore(deps): update dependency @types/node to v24.10.4 [[#5863](https://github.com/woodpecker-ci/woodpecker/pull/5863)] +- chore(deps): update web npm deps non-major [[#5859](https://github.com/woodpecker-ci/woodpecker/pull/5859)] +- chore(deps): update pre-commit hook igorshubovych/markdownlint-cli to v0.47.0 [[#5858](https://github.com/woodpecker-ci/woodpecker/pull/5858)] +- fix(deps): update golang-packages [[#5856](https://github.com/woodpecker-ci/woodpecker/pull/5856)] +- fix(deps): update golang-packages [[#5851](https://github.com/woodpecker-ci/woodpecker/pull/5851)] +- fix(deps): update golang-packages [[#5849](https://github.com/woodpecker-ci/woodpecker/pull/5849)] +- chore(deps): lock file maintenance [[#5847](https://github.com/woodpecker-ci/woodpecker/pull/5847)] +- chore(deps): update web npm deps non-major [[#5837](https://github.com/woodpecker-ci/woodpecker/pull/5837)] +- chore(deps): update dependency golangci/golangci-lint to v2.7.2 [[#5845](https://github.com/woodpecker-ci/woodpecker/pull/5845)] +- chore(deps): update pre-commit hook golangci/golangci-lint to v2.7.2 [[#5846](https://github.com/woodpecker-ci/woodpecker/pull/5846)] +- fix(deps): update module gitlab.com/gitlab-org/api/client-go to v1.7.0 [[#5840](https://github.com/woodpecker-ci/woodpecker/pull/5840)] +- fix(deps): update module github.com/google/go-github/v79 to v80 [[#5838](https://github.com/woodpecker-ci/woodpecker/pull/5838)] +- chore(deps): update pre-commit non-major [[#5836](https://github.com/woodpecker-ci/woodpecker/pull/5836)] +- chore(deps): update docker.io/lycheeverse/lychee docker tag to v0.22.0 [[#5833](https://github.com/woodpecker-ci/woodpecker/pull/5833)] +- chore(deps): update dependency golangci/golangci-lint to v2.7.1 [[#5832](https://github.com/woodpecker-ci/woodpecker/pull/5832)] +- chore(deps): update docker.io/alpine docker tag to v3.23 [[#5830](https://github.com/woodpecker-ci/woodpecker/pull/5830)] +- chore(deps): update docker.io/woodpeckerci/plugin-trivy docker tag to v1.4.4 [[#5828](https://github.com/woodpecker-ci/woodpecker/pull/5828)] +- chore(deps): update dependency golang to v1.25.5 [[#5827](https://github.com/woodpecker-ci/woodpecker/pull/5827)] +- fix(deps): update golang-packages [[#5816](https://github.com/woodpecker-ci/woodpecker/pull/5816)] +- fix(deps): update module gitlab.com/gitlab-org/api/client-go to v1.3.1 [[#5812](https://github.com/woodpecker-ci/woodpecker/pull/5812)] +- fix(deps): update module gitlab.com/gitlab-org/api/client-go to v1.3.0 [[#5807](https://github.com/woodpecker-ci/woodpecker/pull/5807)] +- chore(deps): lock file maintenance [[#5808](https://github.com/woodpecker-ci/woodpecker/pull/5808)] +- chore(deps): update pre-commit hook rbubley/mirrors-prettier to v3.7.3 [[#5804](https://github.com/woodpecker-ci/woodpecker/pull/5804)] +- fix(deps): update dependency simple-icons to v16 [[#5802](https://github.com/woodpecker-ci/woodpecker/pull/5802)] +- fix(deps): update module github.com/docker/cli to v29.1.1+incompatible [[#5801](https://github.com/woodpecker-ci/woodpecker/pull/5801)] +- chore(deps): update dependency prettier to v3.7.3 [[#5800](https://github.com/woodpecker-ci/woodpecker/pull/5800)] +- chore(deps): update pre-commit hook rbubley/mirrors-prettier to v3.7.2 [[#5795](https://github.com/woodpecker-ci/woodpecker/pull/5795)] +- fix(deps): update module gitlab.com/gitlab-org/api/client-go to v1 [[#5794](https://github.com/woodpecker-ci/woodpecker/pull/5794)] +- chore(deps): update web npm deps non-major [[#5792](https://github.com/woodpecker-ci/woodpecker/pull/5792)] +- chore(deps): update pre-commit hook rbubley/mirrors-prettier to v3.7.1 [[#5793](https://github.com/woodpecker-ci/woodpecker/pull/5793)] +- fix(deps): update module github.com/docker/cli to v29.1.0+incompatible [[#5789](https://github.com/woodpecker-ci/woodpecker/pull/5789)] +- fix(deps): update golang-packages [[#5787](https://github.com/woodpecker-ci/woodpecker/pull/5787)] +- chore(deps): lock file maintenance [[#5784](https://github.com/woodpecker-ci/woodpecker/pull/5784)] +- chore(deps): update dependency simple-icons to v15.22.0 [[#5782](https://github.com/woodpecker-ci/woodpecker/pull/5782)] +- chore(deps): update dependency vue-tsc to v3.1.5 [[#5781](https://github.com/woodpecker-ci/woodpecker/pull/5781)] +- chore(deps): update dependency @types/lodash to v4.17.21 [[#5780](https://github.com/woodpecker-ci/woodpecker/pull/5780)] +- chore(deps): update dependency vue-i18n to v11.2.1 [[#5779](https://github.com/woodpecker-ci/woodpecker/pull/5779)] +- chore(deps): update pre-commit hook igorshubovych/markdownlint-cli to v0.46.0 [[#5776](https://github.com/woodpecker-ci/woodpecker/pull/5776)] +- chore(deps): update web npm deps non-major [[#5775](https://github.com/woodpecker-ci/woodpecker/pull/5775)] +- fix(deps): update golang-packages [[#5770](https://github.com/woodpecker-ci/woodpecker/pull/5770)] +- fix(deps): update golang-packages [[#5765](https://github.com/woodpecker-ci/woodpecker/pull/5765)] + +### Misc + +- Revert "Send configuration as part of the request for external configuration" [[#5835](https://github.com/woodpecker-ci/woodpecker/pull/5835)] +- Allow packagers to set WebUI root to custom path [[#5809](https://github.com/woodpecker-ci/woodpecker/pull/5809)] +- fix(queue): force agent cancellation on lease expiration [[#5823](https://github.com/woodpecker-ci/woodpecker/pull/5823)] +- Extract interval into composition [[#5818](https://github.com/woodpecker-ci/woodpecker/pull/5818)] +- Fix outdated Makefile target [[#5817](https://github.com/woodpecker-ci/woodpecker/pull/5817)] +- Makefile: add target to generate man pages [[#5810](https://github.com/woodpecker-ci/woodpecker/pull/5810)] +- Split make install targets [[#5796](https://github.com/woodpecker-ci/woodpecker/pull/5796)] +- Use golangci docker image [[#5797](https://github.com/woodpecker-ci/woodpecker/pull/5797)] +- Clarify envvars documentation [[#5788](https://github.com/woodpecker-ci/woodpecker/pull/5788)] + ## [3.12.0](https://github.com/woodpecker-ci/woodpecker/releases/tag/v3.12.0) - 2025-11-18 ### ❤️ Thanks to all contributors! ❤️ diff --git a/Makefile b/Makefile index 5d0f5b551..b391dc6f1 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,9 @@ # renovate: datasource=github-releases depName=mvdan/gofumpt GOFUMPT_VERSION := v0.9.2 # renovate: datasource=github-releases depName=golangci/golangci-lint -GOLANGCI_LINT_VERSION := v2.7.2 +GOLANGCI_LINT_VERSION := v2.10.1 # renovate: datasource=docker depName=docker.io/techknowlogick/xgo -XGO_VERSION := go-1.25.x +XGO_VERSION := go-1.26.x GO_PACKAGES ?= $(shell go list ./... | grep -v /vendor/) @@ -123,7 +123,7 @@ generate: install-mockery generate-openapi ## Run all code generations CGO_ENABLED=0 go generate ./... generate-openapi: ## Run openapi code generation and format it - CGO_ENABLED=0 go run github.com/swaggo/swag/cmd/swag fmt --exclude pipeline/rpc/proto + CGO_ENABLED=0 go run github.com/swaggo/swag/cmd/swag fmt --exclude rpc/proto CGO_ENABLED=0 go generate cmd/server/openapi.go generate-license-header: install-addlicense @@ -162,6 +162,7 @@ install-protoc-gen-go: go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest; \ fi +.PHONY: install-tools install-tools: install-golangci-lint install-gofumpt install-addlicense install-mockery install-protoc-gen-go ## Install development tools ui-dependencies: ## Install UI dependencies @@ -233,6 +234,7 @@ build-tarball: ## Build tar archive .PHONY: build build: build-agent build-server build-cli ## Build all binaries +.PHONY: release-frontend release-frontend: build-ui ## Build frontend cross-compile-server: ## Cross compile the server diff --git a/pipeline/log/line_writer.go b/agent/log/line_writer.go similarity index 97% rename from pipeline/log/line_writer.go rename to agent/log/line_writer.go index b88cbd671..3c3227434 100644 --- a/pipeline/log/line_writer.go +++ b/agent/log/line_writer.go @@ -23,8 +23,8 @@ import ( "github.com/rs/zerolog/log" - "go.woodpecker-ci.org/woodpecker/v3/pipeline/rpc" "go.woodpecker-ci.org/woodpecker/v3/pipeline/shared" + "go.woodpecker-ci.org/woodpecker/v3/rpc" ) // LineWriter sends logs to the client. diff --git a/pipeline/log/line_writer_test.go b/agent/log/line_writer_test.go similarity index 90% rename from pipeline/log/line_writer_test.go rename to agent/log/line_writer_test.go index 551899a45..e080ef7c9 100644 --- a/pipeline/log/line_writer_test.go +++ b/agent/log/line_writer_test.go @@ -20,9 +20,9 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" - "go.woodpecker-ci.org/woodpecker/v3/pipeline/log" - "go.woodpecker-ci.org/woodpecker/v3/pipeline/rpc" - "go.woodpecker-ci.org/woodpecker/v3/pipeline/rpc/mocks" + "go.woodpecker-ci.org/woodpecker/v3/agent/log" + "go.woodpecker-ci.org/woodpecker/v3/rpc" + "go.woodpecker-ci.org/woodpecker/v3/rpc/mocks" ) func TestLineWriter(t *testing.T) { diff --git a/agent/logger.go b/agent/logger.go index 47413df90..528b8830c 100644 --- a/agent/logger.go +++ b/agent/logger.go @@ -20,13 +20,15 @@ import ( "github.com/rs/zerolog" + "go.woodpecker-ci.org/woodpecker/v3/agent/log" "go.woodpecker-ci.org/woodpecker/v3/pipeline" backend "go.woodpecker-ci.org/woodpecker/v3/pipeline/backend/types" - "go.woodpecker-ci.org/woodpecker/v3/pipeline/log" - "go.woodpecker-ci.org/woodpecker/v3/pipeline/rpc" + "go.woodpecker-ci.org/woodpecker/v3/pipeline/logging" + pipeline_utils "go.woodpecker-ci.org/woodpecker/v3/pipeline/utils" + "go.woodpecker-ci.org/woodpecker/v3/rpc" ) -func (r *Runner) createLogger(_logger zerolog.Logger, uploads *sync.WaitGroup, workflow *rpc.Workflow) pipeline.Logger { +func (r *Runner) createLogger(_logger zerolog.Logger, uploads *sync.WaitGroup, workflow *rpc.Workflow) logging.Logger { return func(step *backend.Step, rc io.ReadCloser) error { defer rc.Close() @@ -35,6 +37,7 @@ func (r *Runner) createLogger(_logger zerolog.Logger, uploads *sync.WaitGroup, w Logger() uploads.Add(1) + defer uploads.Done() var secrets []string for _, secret := range workflow.Config.Secrets { @@ -44,13 +47,11 @@ func (r *Runner) createLogger(_logger zerolog.Logger, uploads *sync.WaitGroup, w logger.Debug().Msg("log stream opened") logStream := log.NewLineWriter(r.client, step.UUID, secrets...) - if err := log.CopyLineByLine(logStream, rc, pipeline.MaxLogLineLength); err != nil { + if err := pipeline_utils.CopyLineByLine(logStream, rc, pipeline.MaxLogLineLength); err != nil { logger.Error().Err(err).Msg("copy limited logStream part") } logger.Debug().Msg("log stream copied, close ...") - uploads.Done() - return nil } } diff --git a/agent/rpc/auth_client_grpc.go b/agent/rpc/auth_client_grpc.go index 7abc7835d..92eb1cb98 100644 --- a/agent/rpc/auth_client_grpc.go +++ b/agent/rpc/auth_client_grpc.go @@ -20,7 +20,7 @@ import ( "google.golang.org/grpc" - "go.woodpecker-ci.org/woodpecker/v3/pipeline/rpc/proto" + "go.woodpecker-ci.org/woodpecker/v3/rpc/proto" ) const authClientTimeout = time.Second * 5 diff --git a/agent/rpc/client_grpc.go b/agent/rpc/client_grpc.go index 2b5de5b65..e42c23476 100644 --- a/agent/rpc/client_grpc.go +++ b/agent/rpc/client_grpc.go @@ -28,8 +28,8 @@ import ( grpcproto "google.golang.org/protobuf/proto" backend "go.woodpecker-ci.org/woodpecker/v3/pipeline/backend/types" - "go.woodpecker-ci.org/woodpecker/v3/pipeline/rpc" - "go.woodpecker-ci.org/woodpecker/v3/pipeline/rpc/proto" + "go.woodpecker-ci.org/woodpecker/v3/rpc" + "go.woodpecker-ci.org/woodpecker/v3/rpc/proto" ) const ( @@ -148,15 +148,16 @@ func (c *client) Next(ctx context.Context, filter rpc.Filter) (*rpc.Workflow, er return w, nil } -// Wait blocks until the workflow is complete. -func (c *client) Wait(ctx context.Context, workflowID string) (err error) { +// Wait blocks until the workflow with the given ID is marked as completed or canceled by the server. +func (c *client) Wait(ctx context.Context, workflowID string) (canceled bool, err error) { retry := c.newBackOff() req := new(proto.WaitRequest) req.Id = workflowID for { - _, err = c.client.Wait(ctx, req) + resp, err := c.client.Wait(ctx, req) if err == nil { - break + // wait block was released normally as expected by server + return resp.GetCanceled(), nil } switch status.Code(err) { @@ -164,10 +165,10 @@ func (c *client) Wait(ctx context.Context, workflowID string) (err error) { if ctx.Err() != nil { // expected as context was canceled log.Debug().Err(err).Msgf("grpc error: wait(): context canceled") - return nil + return false, nil } log.Error().Err(err).Msgf("grpc error: wait(): code: %v", status.Code(err)) - return err + return false, err case codes.Aborted, codes.DataLoss, @@ -178,16 +179,15 @@ func (c *client) Wait(ctx context.Context, workflowID string) (err error) { log.Warn().Err(err).Msgf("grpc error: wait(): code: %v", status.Code(err)) default: log.Error().Err(err).Msgf("grpc error: wait(): code: %v", status.Code(err)) - return err + return false, err } select { case <-time.After(retry.NextBackOff()): case <-ctx.Done(): - return ctx.Err() + return false, ctx.Err() } } - return nil } // Init signals the workflow is initialized. @@ -199,6 +199,7 @@ func (c *client) Init(ctx context.Context, workflowID string, state rpc.Workflow req.State.Started = state.Started req.State.Finished = state.Finished req.State.Error = state.Error + req.State.Canceled = state.Canceled for { _, err = c.client.Init(ctx, req) if err == nil { @@ -238,7 +239,7 @@ func (c *client) Init(ctx context.Context, workflowID string, state rpc.Workflow return nil } -// Done signals the workflow is complete. +// Done let agent signal to server the workflow has stopped. func (c *client) Done(ctx context.Context, workflowID string, state rpc.WorkflowState) (err error) { retry := c.newBackOff() req := new(proto.DoneRequest) @@ -247,6 +248,7 @@ func (c *client) Done(ctx context.Context, workflowID string, state rpc.Workflow req.State.Started = state.Started req.State.Finished = state.Finished req.State.Error = state.Error + req.State.Canceled = state.Canceled for { _, err = c.client.Done(ctx, req) if err == nil { @@ -330,7 +332,7 @@ func (c *client) Extend(ctx context.Context, workflowID string) (err error) { return nil } -// Update updates the workflow state. +// Update let agent updates the step state at the server. func (c *client) Update(ctx context.Context, workflowID string, state rpc.StepState) (err error) { retry := c.newBackOff() req := new(proto.UpdateRequest) @@ -342,6 +344,7 @@ func (c *client) Update(ctx context.Context, workflowID string, state rpc.StepSt req.State.Exited = state.Exited req.State.ExitCode = int32(state.ExitCode) req.State.Error = state.Error + req.State.Canceled = state.Canceled for { _, err = c.client.Update(ctx, req) if err == nil { diff --git a/agent/runner.go b/agent/runner.go index f5640982e..900221588 100644 --- a/agent/runner.go +++ b/agent/runner.go @@ -25,9 +25,10 @@ import ( "github.com/rs/zerolog/log" "google.golang.org/grpc/metadata" - "go.woodpecker-ci.org/woodpecker/v3/pipeline" backend "go.woodpecker-ci.org/woodpecker/v3/pipeline/backend/types" - "go.woodpecker-ci.org/woodpecker/v3/pipeline/rpc" + pipeline_errors "go.woodpecker-ci.org/woodpecker/v3/pipeline/errors" + pipeline_runtime "go.woodpecker-ci.org/woodpecker/v3/pipeline/runtime" + "go.woodpecker-ci.org/woodpecker/v3/rpc" "go.woodpecker-ci.org/woodpecker/v3/shared/constant" "go.woodpecker-ci.org/woodpecker/v3/shared/utils" ) @@ -50,13 +51,15 @@ func NewRunner(workEngine rpc.Peer, f rpc.Filter, h string, state *State, backen } } -func (r *Runner) Run(runnerCtx, shutdownCtx context.Context) error { //nolint:contextcheck +// Run executes a workflow using a backend, tracks its state and reports the state back to the server. +func (r *Runner) Run(runnerCtx, shutdownCtx context.Context) error { log.Debug().Msg("request next execution") + // Preserve metadata AND cancellation from runnerCtx. meta, _ := metadata.FromOutgoingContext(runnerCtx) - ctxMeta := metadata.NewOutgoingContext(context.Background(), meta) + ctxMeta := metadata.NewOutgoingContext(shutdownCtx, meta) - // get the next workflow from the queue + // Fetch next workflow from the queue workflow, err := r.client.Next(runnerCtx, r.filter) if err != nil { return err @@ -65,6 +68,7 @@ func (r *Runner) Run(runnerCtx, shutdownCtx context.Context) error { //nolint:co return nil } + // Compute workflow timeout timeout := time.Hour if minutes := workflow.Timeout; minutes != 0 { timeout = time.Duration(minutes) * time.Minute @@ -73,12 +77,8 @@ func (r *Runner) Run(runnerCtx, shutdownCtx context.Context) error { //nolint:co repoName := extractRepositoryName(workflow.Config) // hack pipelineNumber := extractPipelineNumber(workflow.Config) // hack - r.counter.Add( - workflow.ID, - timeout, - repoName, - pipelineNumber, - ) + // Track workflow execution in runner state + r.counter.Add(workflow.ID, timeout, repoName, pipelineNumber) defer r.counter.Done(workflow.ID) logger := log.With(). @@ -89,63 +89,79 @@ func (r *Runner) Run(runnerCtx, shutdownCtx context.Context) error { //nolint:co logger.Debug().Msg("received execution") - workflowCtx, cancel := context.WithTimeout(ctxMeta, timeout) - defer cancel() + // Workflow execution context. + // This context is the SINGLE source of truth for cancellation. + workflowCtx, _ := context.WithTimeout(ctxMeta, timeout) //nolint:govet + workflowCtx, cancelWorkflowCtx := context.WithCancelCause(workflowCtx) + defer cancelWorkflowCtx(nil) // Add sigterm support for internal context. - // Required when the pipeline is terminated by external signals - // like kubernetes. + // Required to be able to terminate the running workflow by external signals. workflowCtx = utils.WithContextSigtermCallback(workflowCtx, func() { - logger.Error().Msg("Received sigterm termination signal") + logger.Error().Msg("received sigterm termination signal") + // WithContextSigtermCallback would cancel the context too, but we want our own custom error + cancelWorkflowCtx(pipeline_errors.ErrCancel) }) - canceled := false + // Listen for remote cancel events (UI / API). + // When canceled, we MUST cancel the workflow context + // so that workflow execution stop immediately. go func() { - logger.Debug().Msg("listen for cancel signal") + logger.Debug().Msg("start listening for server side cancel signal") - if err := r.client.Wait(workflowCtx, workflow.ID); err != nil { - canceled = true - logger.Warn().Err(err).Msg("cancel signal received") - cancel() + if canceled, err := r.client.Wait(workflowCtx, workflow.ID); err != nil { + logger.Error().Err(err).Msg("server returned unexpected err while waiting for workflow to finish run") + cancelWorkflowCtx(err) } else { - logger.Debug().Msg("done listening for cancel signal") + if canceled { + logger.Debug().Err(err).Msg("server side cancel signal received") + cancelWorkflowCtx(pipeline_errors.ErrCancel) + } + // Wait returned without error, meaning the workflow finished normally + logger.Debug().Msg("cancel listener exited normally") } }() + // Periodically extend the workflow lease while running go func() { for { select { case <-workflowCtx.Done(): - logger.Debug().Msg("pipeline done") + logger.Debug().Msg("workflow context done") return case <-time.After(constant.TaskTimeout / 3): - logger.Debug().Msg("pipeline lease renewed") + logger.Debug().Msg("renewing workflow lease") if err := r.client.Extend(workflowCtx, workflow.ID); err != nil { - log.Error().Err(err).Msg("extending pipeline deadline failed") + logger.Error().Err(err).Msg("failed to extend workflow lease") } } } }() - state := rpc.WorkflowState{} - state.Started = time.Now().Unix() + state := rpc.WorkflowState{ + Started: time.Now().Unix(), + } - err = r.client.Init(runnerCtx, workflow.ID, state) - if err != nil { - logger.Error().Err(err).Msg("workflow initialization failed") - // TODO: should we return here? + if err := r.client.Init(runnerCtx, workflow.ID, state); err != nil { + logger.Error().Err(err).Msg("signaling workflow initialization to server failed") + // We have an error, maybe the server is currently unreachable or other server-side errors occurred. + // So let's clean up and end this not yet started workflow run. + cancelWorkflowCtx(err) + return err } var uploads sync.WaitGroup - //nolint:contextcheck - err = pipeline.New(workflow.Config, - pipeline.WithContext(workflowCtx), - pipeline.WithTaskUUID(fmt.Sprint(workflow.ID)), - pipeline.WithLogger(r.createLogger(logger, &uploads, workflow)), - pipeline.WithTracer(r.createTracer(ctxMeta, &uploads, logger, workflow)), - pipeline.WithBackend(*r.backend), - pipeline.WithDescription(map[string]string{ + + // Run pipeline + err = pipeline_runtime.New( + workflow.Config, + pipeline_runtime.WithContext(workflowCtx), + pipeline_runtime.WithTaskUUID(fmt.Sprint(workflow.ID)), + pipeline_runtime.WithLogger(r.createLogger(logger, &uploads, workflow)), + pipeline_runtime.WithTracer(r.createTracer(ctxMeta, &uploads, logger, workflow)), + pipeline_runtime.WithBackend(*r.backend), + pipeline_runtime.WithDescription(map[string]string{ "workflow_id": workflow.ID, "repo": repoName, "pipeline_number": pipelineNumber, @@ -154,37 +170,35 @@ func (r *Runner) Run(runnerCtx, shutdownCtx context.Context) error { //nolint:co state.Finished = time.Now().Unix() - if errors.Is(err, pipeline.ErrCancel) { - canceled = true - } else if canceled { - err = errors.Join(err, pipeline.ErrCancel) - } - if err != nil { state.Error = err.Error() + if errors.Is(err, pipeline_errors.ErrCancel) { + state.Canceled = true + // cleanup joined error messages + state.Error = pipeline_errors.ErrCancel.Error() + } } logger.Debug(). Str("error", state.Error). - Bool("canceled", canceled). + Bool("canceled", state.Canceled). Msg("workflow finished") - logger.Debug().Msg("uploading logs and traces / states ...") + // Ensure all logs/traces are uploaded before finishing + logger.Debug().Msg("waiting for logs and traces upload") uploads.Wait() - logger.Debug().Msg("uploaded logs and traces / states") - - logger.Debug(). - Str("error", state.Error). - Msg("updating workflow status") + logger.Debug().Msg("logs and traces uploaded") + // Update workflow state doneCtx := runnerCtx if doneCtx.Err() != nil { doneCtx = shutdownCtx } + if err := r.client.Done(doneCtx, workflow.ID, state); err != nil { - logger.Error().Err(err).Msg("updating workflow status failed") + logger.Error().Err(err).Msg("failed to update workflow status") } else { - logger.Debug().Msg("updating workflow status complete") + logger.Debug().Msg("signaling workflow stopped done") } return nil diff --git a/agent/tracer.go b/agent/tracer.go index a3af590d3..df4b0c814 100644 --- a/agent/tracer.go +++ b/agent/tracer.go @@ -16,6 +16,7 @@ package agent import ( "context" + "errors" "runtime" "strconv" "sync" @@ -23,13 +24,16 @@ import ( "github.com/rs/zerolog" - "go.woodpecker-ci.org/woodpecker/v3/pipeline" - "go.woodpecker-ci.org/woodpecker/v3/pipeline/rpc" + pipeline_errors "go.woodpecker-ci.org/woodpecker/v3/pipeline/errors" + "go.woodpecker-ci.org/woodpecker/v3/pipeline/state" + "go.woodpecker-ci.org/woodpecker/v3/pipeline/tracing" + "go.woodpecker-ci.org/woodpecker/v3/rpc" ) -func (r *Runner) createTracer(ctxMeta context.Context, uploads *sync.WaitGroup, logger zerolog.Logger, workflow *rpc.Workflow) pipeline.TraceFunc { - return func(state *pipeline.State) error { +func (r *Runner) createTracer(ctxMeta context.Context, uploads *sync.WaitGroup, logger zerolog.Logger, workflow *rpc.Workflow) tracing.TraceFunc { + return func(state *state.State) error { uploads.Add(1) + defer uploads.Done() stepLogger := logger.With(). Str("image", state.Pipeline.Step.Image). @@ -43,12 +47,15 @@ func (r *Runner) createTracer(ctxMeta context.Context, uploads *sync.WaitGroup, StepUUID: state.Pipeline.Step.UUID, Exited: state.Process.Exited, ExitCode: state.Process.ExitCode, - Started: time.Now().Unix(), // TODO: do not do this - Finished: time.Now().Unix(), + Started: state.Process.Started, + Canceled: errors.Is(state.Process.Error, pipeline_errors.ErrCancel), } if state.Process.Error != nil { stepState.Error = state.Process.Error.Error() } + if state.Process.Exited { + stepState.Finished = time.Now().Unix() + } defer func() { stepLogger.Debug().Msg("update step status") @@ -60,7 +67,6 @@ func (r *Runner) createTracer(ctxMeta context.Context, uploads *sync.WaitGroup, } stepLogger.Debug().Msg("update step status complete") - uploads.Done() }() if state.Process.Exited { return nil diff --git a/checkmake.ini b/checkmake.ini new file mode 100644 index 000000000..90fc7b3e2 --- /dev/null +++ b/checkmake.ini @@ -0,0 +1,2 @@ +[maxbodylength] +disabled = true diff --git a/cli/context/context.go b/cli/context/context.go new file mode 100644 index 000000000..64b074966 --- /dev/null +++ b/cli/context/context.go @@ -0,0 +1,174 @@ +// Copyright 2026 Woodpecker Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package context + +import ( + "context" + "fmt" + "os" + + "github.com/rs/zerolog/log" + "github.com/urfave/cli/v3" + + "go.woodpecker-ci.org/woodpecker/v3/cli/common" + "go.woodpecker-ci.org/woodpecker/v3/cli/internal/config" + "go.woodpecker-ci.org/woodpecker/v3/cli/output" +) + +// Command exports the context command set. +var Command = &cli.Command{ + Name: "context", + Aliases: []string{"ctx"}, + Usage: "manage contexts", + Description: "Contexts can be used to manage users on one or multiple servers.\nTo create a new context run the setup command", + Commands: []*cli.Command{ + listCommand, + useCommand, + deleteCommand, + renameCommand, + }, +} + +var listCommand = &cli.Command{ + Name: "list", + Aliases: []string{"ls"}, + Usage: "list all contexts", + Flags: append(common.OutputFlags("table"), []cli.Flag{ + &cli.BoolFlag{ + Name: "output-no-headers", + Usage: "do not print headers in output", + }, + }...), + Action: listContexts, +} + +var useCommand = &cli.Command{ + Name: "use", + Usage: "set the current context", + ArgsUsage: "", + Action: useContext, +} + +var deleteCommand = &cli.Command{ + Name: "delete", + Aliases: []string{"rm"}, + Usage: "delete a context", + ArgsUsage: "", + Action: deleteContext, +} + +var renameCommand = &cli.Command{ + Name: "rename", + Usage: "rename a context", + ArgsUsage: " ", + Action: renameContext, +} + +func listContexts(_ context.Context, c *cli.Command) error { + contexts, err := config.LoadContexts() + if err != nil { + return err + } + + if len(contexts.Contexts) == 0 { + fmt.Println("No contexts found. Run 'woodpecker-cli setup' to create one.") + return nil + } + + _, outOpt := output.ParseOutputOptions(c.String("output")) + out := os.Stdout + noHeader := c.Bool("output-no-headers") + table := output.NewTable(out) + + // Add custom field mapping + table.AddFieldFn("Name", func(obj any) string { + c, ok := obj.(config.Context) + if !ok { + return "???" + } + + if contexts.CurrentContext == c.Name { + return c.Name + " *" + } + + return c.Name + }) + table.AddFieldAlias("ServerURL", "Server URL") + table.AddFieldAlias("LogLevel", "Log Level") + table.AddFieldAlias("Name", "Name (selected)") + + cols := []string{"Name (selected)", "Server URL"} + + if len(outOpt) > 0 { + cols = outOpt + } + if !noHeader { + table.WriteHeader(cols) + } + for _, c := range contexts.Contexts { + if err := table.Write(cols, c); err != nil { + return err + } + } + + return table.Flush() +} + +func useContext(_ context.Context, c *cli.Command) error { + contextName := c.Args().First() + if contextName == "" { + return fmt.Errorf("context name is required") + } + + err := config.SetCurrentContext(contextName) + if err != nil { + return err + } + + log.Info().Msgf("Switched to context '%s'", contextName) + return nil +} + +func deleteContext(_ context.Context, c *cli.Command) error { + contextName := c.Args().First() + if contextName == "" { + return fmt.Errorf("context name is required") + } + + err := config.DeleteContext(c, contextName) + if err != nil { + return err + } + + log.Info().Msgf("Context '%s' deleted", contextName) + return nil +} + +func renameContext(_ context.Context, c *cli.Command) error { + if c.Args().Len() < 2 { //nolint:mnd // min args + return fmt.Errorf("both old name and new name are required") + } + + oldName := c.Args().Get(0) + newName := c.Args().Get(1) + + err := config.RenameContext(oldName, newName) + if err != nil { + return err + } + + log.Info().Msgf("Context renamed from '%s' to '%s'", oldName, newName) + return nil +} diff --git a/cli/exec/exec.go b/cli/exec/exec.go index 35b60fbac..c338f435f 100644 --- a/cli/exec/exec.go +++ b/cli/exec/exec.go @@ -45,7 +45,10 @@ import ( "go.woodpecker-ci.org/woodpecker/v3/pipeline/frontend/yaml/compiler" "go.woodpecker-ci.org/woodpecker/v3/pipeline/frontend/yaml/linter" "go.woodpecker-ci.org/woodpecker/v3/pipeline/frontend/yaml/matrix" - pipelineLog "go.woodpecker-ci.org/woodpecker/v3/pipeline/log" + "go.woodpecker-ci.org/woodpecker/v3/pipeline/logging" + pipeline_runtime "go.woodpecker-ci.org/woodpecker/v3/pipeline/runtime" + "go.woodpecker-ci.org/woodpecker/v3/pipeline/tracing" + pipeline_utils "go.woodpecker-ci.org/woodpecker/v3/pipeline/utils" "go.woodpecker-ci.org/woodpecker/v3/shared/constant" "go.woodpecker-ci.org/woodpecker/v3/shared/utils" ) @@ -318,12 +321,12 @@ func execWithAxis(ctx context.Context, c *cli.Command, file, repoPath string, ax fmt.Printf("ctrl+c received, terminating current pipeline '%s'\n", confStr) }) - return pipeline.New(compiled, - pipeline.WithContext(pipelineCtx), //nolint:contextcheck - pipeline.WithTracer(pipeline.DefaultTracer), - pipeline.WithLogger(defaultLogger), - pipeline.WithBackend(backendEngine), - pipeline.WithDescription(map[string]string{ + return pipeline_runtime.New(compiled, + pipeline_runtime.WithContext(pipelineCtx), //nolint:contextcheck + pipeline_runtime.WithTracer(tracing.DefaultTracer), + pipeline_runtime.WithLogger(defaultLogger), + pipeline_runtime.WithBackend(backendEngine), + pipeline_runtime.WithDescription(map[string]string{ "CLI": "exec", }), ).Run(ctx) @@ -348,7 +351,7 @@ func convertPathForWindows(path string) string { return filepath.ToSlash(path) } -var defaultLogger = pipeline.Logger(func(step *backend_types.Step, rc io.ReadCloser) error { +var defaultLogger = logging.Logger(func(step *backend_types.Step, rc io.ReadCloser) error { logWriter := NewLineWriter(step.Name, step.UUID) - return pipelineLog.CopyLineByLine(logWriter, rc, pipeline.MaxLogLineLength) + return pipeline_utils.CopyLineByLine(logWriter, rc, pipeline.MaxLogLineLength) }) diff --git a/cli/exec/flags.go b/cli/exec/flags.go index 27aa3fb1f..dafe9f81d 100644 --- a/cli/exec/flags.go +++ b/cli/exec/flags.go @@ -80,7 +80,7 @@ var flags = []cli.Flag{ }, &cli.StringFlag{ Sources: cli.EnvVars("WOODPECKER_SECRETS_FILE"), - Name: "secrets", + Name: "secrets-file", Usage: "path to yaml file with secrets map", }, diff --git a/cli/internal/config/config.go b/cli/internal/config/config.go index 8a6b221f0..c4abfa9dc 100644 --- a/cli/internal/config/config.go +++ b/cli/internal/config/config.go @@ -31,20 +31,46 @@ func (c *Config) MergeIfNotSet(c2 *Config) { } } -var skipSetupForCommands = []string{"setup", "help", "h", "version", "update", "lint", "exec", "completion", ""} +var skipSetupForCommands = []string{"setup", "help", "h", "version", "update", "lint", "exec", "completion", "", "context", "ctx"} func Load(ctx context.Context, c *cli.Command) error { if firstArg := c.Args().First(); slices.Contains(skipSetupForCommands, firstArg) { return nil } + contextConfig, contextErr := GetCurrentContext(ctx, c) + if contextErr == nil { + if !c.IsSet("server") { + err := c.Set("server", contextConfig.ServerURL) + if err != nil { + return err + } + } + if !c.IsSet("token") { + err := c.Set("token", contextConfig.Token) + if err != nil { + return err + } + } + if !c.IsSet("log-level") && contextConfig.LogLevel != "" { + err := c.Set("log-level", contextConfig.LogLevel) + if err != nil { + return err + } + } + log.Debug().Any("config", contextConfig).Msg("loaded config from context") + return nil + } + + // TODO: remove with next major release + // Fallback: try legacy config file (for backward compatibility) config, err := Get(ctx, c, c.String("config")) if err != nil { return err } if config.ServerURL == "" || config.Token == "" { - log.Info().Msg("woodpecker-cli is not set up, run `woodpecker-cli setup` or provide required environment variables/flags") + log.Info().Msg("woodpecker-cli is not set up, run `woodpecker-cli setup` to create a context") return errors.New("woodpecker-cli is not configured") } @@ -63,7 +89,7 @@ func Load(ctx context.Context, c *cli.Command) error { return err } - log.Debug().Any("config", config).Msg("loaded config") + log.Debug().Any("config", config).Msg("loaded config from legacy file") return nil } diff --git a/cli/internal/config/context.go b/cli/internal/config/context.go new file mode 100644 index 000000000..11f729ad3 --- /dev/null +++ b/cli/internal/config/context.go @@ -0,0 +1,245 @@ +// Copyright 2026 Woodpecker Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package config + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "os" + "path/filepath" + + "github.com/adrg/xdg" + "github.com/rs/zerolog/log" + "github.com/urfave/cli/v3" + "github.com/zalando/go-keyring" +) + +// Context represents a single CLI context with its connection details. +type Context struct { + Name string `json:"name"` + ServerURL string `json:"server_url"` + LogLevel string `json:"log_level,omitempty"` +} + +// Contexts holds all contexts and tracks the current active one. +type Contexts struct { + CurrentContext string `json:"current_context"` + Contexts map[string]Context `json:"contexts"` +} + +func getContextsPath() (string, error) { + configPath, err := xdg.ConfigFile("woodpecker/contexts.json") + if err != nil { + return "", err + } + return configPath, nil +} + +// LoadContexts loads all contexts from the contexts file. +func LoadContexts() (*Contexts, error) { + contextsPath, err := getContextsPath() + if err != nil { + return nil, err + } + + content, err := os.ReadFile(contextsPath) + if err != nil { + if os.IsNotExist(err) { + return &Contexts{ + Contexts: make(map[string]Context), + }, nil + } + return nil, err + } + + var contexts Contexts + err = json.Unmarshal(content, &contexts) + if err != nil { + return nil, err + } + + if contexts.Contexts == nil { + contexts.Contexts = make(map[string]Context) + } + + return &contexts, nil +} + +// SaveContexts saves all contexts to the contexts file. +func SaveContexts(contexts *Contexts) error { + data, err := json.MarshalIndent(contexts, "", " ") + if err != nil { + return err + } + + contextsPath, err := getContextsPath() + if err != nil { + return err + } + + // Ensure the directory exists. + dir := filepath.Dir(contextsPath) + if err := os.MkdirAll(dir, 0o755); err != nil { + return err + } + + return os.WriteFile(contextsPath, data, 0o600) +} + +// GetCurrentContext returns the current active context. +func GetCurrentContext(ctx context.Context, c *cli.Command) (*Config, error) { + contexts, err := LoadContexts() + if err != nil { + return nil, err + } + + if contexts.CurrentContext == "" { + return nil, errors.New("no context is currently set") + } + + context, exists := contexts.Contexts[contexts.CurrentContext] + if !exists { + return nil, fmt.Errorf("current context '%s' not found", contexts.CurrentContext) + } + + return GetContextConfig(c, &context) +} + +// GetContextConfig loads the config for a specific context including the token from keyring. +func GetContextConfig(c *cli.Command, ctx *Context) (*Config, error) { + conf := &Config{ + ServerURL: ctx.ServerURL, + LogLevel: ctx.LogLevel, + } + + // Load token from keyring + service := c.Root().Name + secret, err := keyring.Get(service, ctx.ServerURL) + if errors.Is(err, keyring.ErrUnsupportedPlatform) { + log.Warn().Msg("keyring is not supported on this platform") + return conf, nil + } + if errors.Is(err, keyring.ErrNotFound) { + return nil, fmt.Errorf("token not found in keyring for context '%s'", ctx.Name) + } + if err != nil { + return nil, err + } + + conf.Token = secret + return conf, nil +} + +// AddOrUpdateContext adds or updates a context and optionally sets it as current. +func AddOrUpdateContext(c *cli.Command, name, serverURL, token, logLevel string, setCurrent bool) error { + contexts, err := LoadContexts() + if err != nil { + return err + } + + contexts.Contexts[name] = Context{ + Name: name, + ServerURL: serverURL, + LogLevel: logLevel, + } + + if setCurrent || contexts.CurrentContext == "" { + contexts.CurrentContext = name + } + + // Save token to keyring + service := c.Root().Name + err = keyring.Set(service, serverURL, token) + if err != nil { + return err + } + + return SaveContexts(contexts) +} + +// DeleteContext removes a context. +func DeleteContext(c *cli.Command, name string) error { + contexts, err := LoadContexts() + if err != nil { + return err + } + + context, exists := contexts.Contexts[name] + if !exists { + return fmt.Errorf("context '%s' not found", name) + } + + // Try to delete token from keyring + service := c.Root().Name + err = keyring.Delete(service, context.ServerURL) + if err != nil && !errors.Is(err, keyring.ErrNotFound) { + log.Warn().Err(err).Msg("failed to delete token from keyring") + } + + delete(contexts.Contexts, name) + + // If we deleted the current context, unset it + if contexts.CurrentContext == name { + contexts.CurrentContext = "" + } + + return SaveContexts(contexts) +} + +// SetCurrentContext sets the current active context. +func SetCurrentContext(name string) error { + contexts, err := LoadContexts() + if err != nil { + return err + } + + if _, exists := contexts.Contexts[name]; !exists { + return fmt.Errorf("context '%s' not found", name) + } + + contexts.CurrentContext = name + return SaveContexts(contexts) +} + +// RenameContext renames an existing context. +func RenameContext(oldName, newName string) error { + contexts, err := LoadContexts() + if err != nil { + return err + } + + context, exists := contexts.Contexts[oldName] + if !exists { + return fmt.Errorf("context '%s' not found", oldName) + } + + if _, exists := contexts.Contexts[newName]; exists { + return fmt.Errorf("context '%s' already exists", newName) + } + + // Update the name in the context + context.Name = newName + contexts.Contexts[newName] = context + delete(contexts.Contexts, oldName) + + // Update current context if necessary + if contexts.CurrentContext == oldName { + contexts.CurrentContext = newName + } + + return SaveContexts(contexts) +} diff --git a/cli/internal/config/context_test.go b/cli/internal/config/context_test.go new file mode 100644 index 000000000..87401ba5a --- /dev/null +++ b/cli/internal/config/context_test.go @@ -0,0 +1,142 @@ +// Copyright 2026 Woodpecker Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package config + +import ( + "os" + "testing" + + "github.com/adrg/xdg" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestContextManagement(t *testing.T) { + // Create a temporary directory for test contexts + tmpDir := t.TempDir() + + // Override xdg directories for testing + t.Setenv("HOME", tmpDir) + xdg.Reload() + contextsFile, err := xdg.ConfigFile("woodpecker/contexts.json") + require.NoError(t, err) + + t.Run("LoadContexts returns empty when file doesn't exist", func(t *testing.T) { + contexts, err := LoadContexts() + require.NoError(t, err) + assert.NotNil(t, contexts) + assert.Empty(t, contexts.Contexts) + assert.Empty(t, contexts.CurrentContext) + }) + + t.Run("SaveContexts creates valid JSON", func(t *testing.T) { + contexts := &Contexts{ + CurrentContext: "test", + Contexts: map[string]Context{ + "test": { + Name: "test", + ServerURL: "https://test.example.com", + LogLevel: "info", + }, + }, + } + + err := SaveContexts(contexts) + require.NoError(t, err) + + // Verify file exists and contains valid JSON + data, err := os.ReadFile(contextsFile) + require.NoError(t, err) + assert.Contains(t, string(data), "test.example.com") + }) + + t.Run("LoadContexts reads saved contexts", func(t *testing.T) { + contexts, err := LoadContexts() + require.NoError(t, err) + assert.Equal(t, "test", contexts.CurrentContext) + assert.Len(t, contexts.Contexts, 1) + assert.Equal(t, "https://test.example.com", contexts.Contexts["test"].ServerURL) + }) + + t.Run("SetCurrentContext updates current context", func(t *testing.T) { + contexts := &Contexts{ + CurrentContext: "test", + Contexts: map[string]Context{ + "test": { + Name: "test", + ServerURL: "https://test.example.com", + }, + "prod": { + Name: "prod", + ServerURL: "https://prod.example.com", + }, + }, + } + err := SaveContexts(contexts) + require.NoError(t, err) + + err = SetCurrentContext("prod") + require.NoError(t, err) + + contexts, err = LoadContexts() + require.NoError(t, err) + assert.Equal(t, "prod", contexts.CurrentContext) + }) + + t.Run("SetCurrentContext fails for non-existent context", func(t *testing.T) { + err := SetCurrentContext("nonexistent") + assert.Error(t, err) + assert.Contains(t, err.Error(), "not found") + }) + + t.Run("RenameContext updates context name", func(t *testing.T) { + contexts := &Contexts{ + CurrentContext: "old", + Contexts: map[string]Context{ + "old": { + Name: "old", + ServerURL: "https://test.example.com", + }, + }, + } + err := SaveContexts(contexts) + require.NoError(t, err) + + err = RenameContext("old", "new") + require.NoError(t, err) + + contexts, err = LoadContexts() + require.NoError(t, err) + assert.Equal(t, "new", contexts.CurrentContext) + assert.Contains(t, contexts.Contexts, "new") + assert.NotContains(t, contexts.Contexts, "old") + assert.Equal(t, "new", contexts.Contexts["new"].Name) + }) + + t.Run("RenameContext fails if target exists", func(t *testing.T) { + contexts := &Contexts{ + Contexts: map[string]Context{ + "ctx1": {Name: "ctx1", ServerURL: "https://test1.example.com"}, + "ctx2": {Name: "ctx2", ServerURL: "https://test2.example.com"}, + }, + } + err := SaveContexts(contexts) + require.NoError(t, err) + + err = RenameContext("ctx1", "ctx2") + assert.Error(t, err) + assert.Contains(t, err.Error(), "already exists") + }) +} diff --git a/cli/output/output.go b/cli/output/output.go index 3610f89dc..3b5346d49 100644 --- a/cli/output/output.go +++ b/cli/output/output.go @@ -1,3 +1,17 @@ +// Copyright 2024 Woodpecker Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package output import ( diff --git a/cli/output/output_test.go b/cli/output/output_test.go new file mode 100644 index 000000000..3ca57330d --- /dev/null +++ b/cli/output/output_test.go @@ -0,0 +1,56 @@ +// Copyright 2026 Woodpecker Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package output + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestParseOutputOptions(t *testing.T) { + t.Parallel() + + testCases := []struct { + in string + out string + opts []string + }{ + { + in: "output", + out: "output", + }, + { + in: "output=a", + out: "output", + opts: []string{"a"}, + }, + { + in: "output=", + out: "output", + }, + { + in: "output=a,b", + out: "output", + opts: []string{"a", "b"}, + }, + } + + for _, tc := range testCases { + out, opts := ParseOutputOptions(tc.in) + assert.Equal(t, tc.out, out) + assert.Equal(t, tc.opts, opts) + } +} diff --git a/cli/output/table.go b/cli/output/table.go index 15c73194d..0e3c42c7a 100644 --- a/cli/output/table.go +++ b/cli/output/table.go @@ -1,3 +1,17 @@ +// Copyright 2024 Woodpecker Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package output import ( diff --git a/cli/output/table_test.go b/cli/output/table_test.go index ffd70ed6d..16a4c1161 100644 --- a/cli/output/table_test.go +++ b/cli/output/table_test.go @@ -1,10 +1,25 @@ +// Copyright 2024 Woodpecker Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package output import ( "bytes" "os" - "strings" "testing" + + "github.com/stretchr/testify/assert" ) type writerFlusherStub struct { @@ -18,6 +33,7 @@ func (s writerFlusherStub) Flush() error { type testFieldsStruct struct { Name string Number int + Bool bool } func TestTableOutput(t *testing.T) { @@ -27,49 +43,44 @@ func TestTableOutput(t *testing.T) { t.Run("AddAllowedFields", func(t *testing.T) { _, _ = to.AddAllowedFields(testFieldsStruct{}) - if _, ok := to.allowedFields["name"]; !ok { - t.Error("name should be a allowed field") - } + _, ok := to.allowedFields["name"] + assert.True(t, ok) }) t.Run("AddFieldAlias", func(t *testing.T) { to.AddFieldAlias("WoodpeckerCI", "wp") - if alias, ok := to.fieldAlias["wp"]; !ok || alias != "WoodpeckerCI" { - t.Errorf("'wp' alias should resolve to 'WoodpeckerCI', is: %v", alias) - } + alias, ok := to.fieldAlias["wp"] + assert.True(t, ok) + assert.Equal(t, "WoodpeckerCI", alias) }) t.Run("AddFieldOutputFn", func(t *testing.T) { to.AddFieldFn("WoodpeckerCI", FieldFn(func(_ any) string { return "WOODPECKER CI!!!" })) - if _, ok := to.fieldMapping["woodpeckerci"]; !ok { - t.Errorf("'WoodpeckerCI' field output fn should be set") - } + _, ok := to.fieldMapping["woodpeckerci"] + assert.True(t, ok) }) t.Run("ValidateColumns", func(t *testing.T) { err := to.ValidateColumns([]string{"non-existent", "NAME"}) - if err == nil || - strings.Contains(err.Error(), "name") || - !strings.Contains(err.Error(), "non-existent") { - t.Errorf("error should contain 'non-existent' but not 'name': %v", err) - } + assert.Error(t, err) + assert.ErrorContains(t, err, "non-existent") + assert.NotContains(t, err.Error(), "name") + + assert.NoError(t, to.ValidateColumns([]string{"name"})) }) t.Run("WriteHeader", func(t *testing.T) { to.WriteHeader([]string{"wp", "name"}) - if wfs.String() != "WP\tNAME\n" { - t.Errorf("written header should be 'WOODPECKER CI\\tNAME\\n', is: %q", wfs.String()) - } + assert.Equal(t, "WP\tNAME\n", wfs.String()) wfs.Reset() }) t.Run("WriteLine", func(t *testing.T) { - _ = to.Write([]string{"wp", "name", "number"}, &testFieldsStruct{"test123", 1000000000}) - if wfs.String() != "WOODPECKER CI!!!\ttest123\t1000000000\n" { - t.Errorf("written line should be 'WOODPECKER CI!!!\\ttest123\\t1000000000\\n', is: %q", wfs.String()) - } + err := to.Write([]string{"wp", "name", "number", "bool"}, &testFieldsStruct{"test123", 1000000000, true}) + assert.NoError(t, err) + err = to.Write([]string{"wp", "name", "number", "bool"}, &testFieldsStruct{"", 1000000000, false}) + assert.NoError(t, err) + assert.Equal(t, "WOODPECKER CI!!!\ttest123\t1000000000\tyes\nWOODPECKER CI!!!\t-\t1000000000\tno\n", wfs.String()) wfs.Reset() }) t.Run("Columns", func(t *testing.T) { - if len(to.Columns()) != 3 { - t.Errorf("unexpected number of columns: %v", to.Columns()) - } + assert.Len(t, to.Columns(), 4) }) } diff --git a/cli/pipeline/pipeline.go b/cli/pipeline/pipeline.go index 5f5821fee..5ba1987a1 100644 --- a/cli/pipeline/pipeline.go +++ b/cli/pipeline/pipeline.go @@ -73,6 +73,20 @@ func pipelineOutput(c *cli.Command, pipelines []*woodpecker.Pipeline, fd ...io.W if err := tmpl.Execute(out, pipelines); err != nil { return err } + case "go-format": + if len(outOpt) < 1 { + return fmt.Errorf("%w: missing template", output.ErrOutputOptionRequired) + } + + tmpl, err := template.New("_").Parse(outOpt[0] + "\n") + if err != nil { + return err + } + for _, p := range pipelines { + if err := tmpl.Execute(out, p); err != nil { + return err + } + } case "table": fallthrough default: diff --git a/cli/pipeline/pipeline_test.go b/cli/pipeline/pipeline_test.go index 3cf14ee26..0abe5a78c 100644 --- a/cli/pipeline/pipeline_test.go +++ b/cli/pipeline/pipeline_test.go @@ -40,6 +40,11 @@ func TestPipelineOutput(t *testing.T) { args: []string{"output", "--output", "go-template={{range . }}{{.Number}} {{.Status}} {{.Branch}}{{end}}"}, expected: "1 success main\n", }, + { + name: "go-format output", + args: []string{"output", "--output", "go-format={{.Number}} {{.Status}} {{.Branch}}"}, + expected: "1 success main\n", + }, { name: "invalid go-template", args: []string{"output", "--output", "go-template={{.InvalidField}}"}, diff --git a/cli/repo/repo.go b/cli/repo/repo.go index cdc8949a8..90dc91b7d 100644 --- a/cli/repo/repo.go +++ b/cli/repo/repo.go @@ -80,6 +80,20 @@ func repoOutput(c *cli.Command, repos []*woodpecker.Repo, fd ...io.Writer) error if err := tmpl.Execute(out, repos); err != nil { return err } + case "go-format": + if len(outOpt) < 1 { + return fmt.Errorf("%w: missing template", output.ErrOutputOptionRequired) + } + + tmpl, err := template.New("_").Parse(outOpt[0] + "\n") + if err != nil { + return err + } + for _, r := range repos { + if err := tmpl.Execute(out, r); err != nil { + return err + } + } case "table": fallthrough default: diff --git a/cli/repo/repo_test.go b/cli/repo/repo_test.go index bdf17e892..b27b06512 100644 --- a/cli/repo/repo_test.go +++ b/cli/repo/repo_test.go @@ -40,6 +40,16 @@ func TestRepoOutput(t *testing.T) { args: []string{"output", "--output", "go-template={{range . }}{{.Name}} {{.ForgeURL}} {{.Trusted.Network}}{{end}}"}, expected: "repo1 git.example.com true\n", }, + { + name: "go-format output", + args: []string{"output", "--output", "go-format={{.Name}} {{.ForgeURL}} {{.Trusted.Network}}"}, + expected: "repo1 git.example.com true\n", + }, + { + name: "invalid go-template", + args: []string{"output", "--output", "go-template={{.InvalidField}}"}, + wantErr: true, + }, } repos := []*woodpecker.Repo{ diff --git a/cli/setup/setup.go b/cli/setup/setup.go index 8b00467cf..e26cb1ab1 100644 --- a/cli/setup/setup.go +++ b/cli/setup/setup.go @@ -3,6 +3,7 @@ package setup import ( "context" "errors" + "fmt" "strings" "github.com/rs/zerolog/log" @@ -26,16 +27,29 @@ var Command = &cli.Command{ Name: "token", Usage: "token to authenticate with the woodpecker server", }, + &cli.StringFlag{ + Name: "context", + Aliases: []string{"ctx"}, + Usage: "name for the context (defaults to 'default')", + }, }, Action: setup, } func setup(ctx context.Context, c *cli.Command) error { - _config, err := config.Get(ctx, c, c.String("config")) + contextName := c.String("context") + if contextName == "" { + contextName = "default" + } + + // Check if context already exists + contexts, err := config.LoadContexts() if err != nil { return err - } else if _config != nil { - setupAgain, err := ui.Confirm("The woodpecker-cli was already configured. Do you want to configure it again?") + } + + if existingCtx, exists := contexts.Contexts[contextName]; exists { + setupAgain, err := ui.Confirm(fmt.Sprintf("Context '%s' already exists (server: %s). Do you want to reconfigure it?", contextName, existingCtx.ServerURL)) if err != nil { return err } @@ -78,16 +92,13 @@ func setup(ctx context.Context, c *cli.Command) error { } } - err = config.Save(ctx, c, c.String("config"), &config.Config{ - ServerURL: serverURL, - Token: token, - LogLevel: "info", - }) + // Save as context + err = config.AddOrUpdateContext(c, contextName, serverURL, token, "info", true) if err != nil { return err } - log.Info().Msg("woodpecker-cli has been successfully setup") + log.Info().Msgf("Context '%s' has been successfully created and set as current", contextName) return nil } diff --git a/cmd/agent/core/agent.go b/cmd/agent/core/agent.go index 889cd2c65..bf9adec76 100644 --- a/cmd/agent/core/agent.go +++ b/cmd/agent/core/agent.go @@ -43,7 +43,7 @@ import ( "go.woodpecker-ci.org/woodpecker/v3/pipeline" "go.woodpecker-ci.org/woodpecker/v3/pipeline/backend" "go.woodpecker-ci.org/woodpecker/v3/pipeline/backend/types" - "go.woodpecker-ci.org/woodpecker/v3/pipeline/rpc" + "go.woodpecker-ci.org/woodpecker/v3/rpc" "go.woodpecker-ci.org/woodpecker/v3/shared/logger" "go.woodpecker-ci.org/woodpecker/v3/shared/utils" "go.woodpecker-ci.org/woodpecker/v3/version" @@ -296,7 +296,7 @@ func run(ctx context.Context, c *cli.Command, backends []types.Backend) error { return nil } - log.Debug().Msg("polling new steps") + log.Debug().Msg("polling new workflow") if err := runner.Run(agentCtx, shutdownCtx); err != nil { log.Error().Err(err).Msg("runner error, retrying...") // Check if context is canceled diff --git a/cmd/agent/core/config_test.go b/cmd/agent/core/config_test.go index d14e60012..0a4c58c12 100644 --- a/cmd/agent/core/config_test.go +++ b/cmd/agent/core/config_test.go @@ -19,6 +19,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestReadAgentIDFileNotExists(t *testing.T) { @@ -27,16 +28,12 @@ func TestReadAgentIDFileNotExists(t *testing.T) { func TestReadAgentIDFileExists(t *testing.T) { tmpF, errTmpF := os.CreateTemp(t.TempDir(), "tmp_") - if !assert.NoError(t, errTmpF) { - return - } + require.NoError(t, errTmpF) defer os.Remove(tmpF.Name()) // there is an existing config errWrite := os.WriteFile(tmpF.Name(), []byte(`{"agent_id":3}`), 0o644) - if !assert.NoError(t, errWrite) { - return - } + require.NoError(t, errWrite) // read existing config actual := readAgentConfig(tmpF.Name()) @@ -49,9 +46,7 @@ func TestReadAgentIDFileExists(t *testing.T) { assert.EqualValues(t, 33, actual.AgentID) tmpF2, errTmpF := os.CreateTemp(t.TempDir(), "tmp_") - if !assert.NoError(t, errTmpF) { - return - } + require.NoError(t, errTmpF) defer os.Remove(tmpF2.Name()) // write new config diff --git a/cmd/cli/app.go b/cmd/cli/app.go index 2cdd62366..6d65561fb 100644 --- a/cmd/cli/app.go +++ b/cmd/cli/app.go @@ -19,6 +19,7 @@ import ( "go.woodpecker-ci.org/woodpecker/v3/cli/admin" "go.woodpecker-ci.org/woodpecker/v3/cli/common" + "go.woodpecker-ci.org/woodpecker/v3/cli/context" "go.woodpecker-ci.org/woodpecker/v3/cli/exec" "go.woodpecker-ci.org/woodpecker/v3/cli/info" "go.woodpecker-ci.org/woodpecker/v3/cli/lint" @@ -47,6 +48,7 @@ func newApp() *cli.Command { } app.Commands = []*cli.Command{ admin.Command, + context.Command, exec.Command, info.Command, lint.Command, diff --git a/cmd/server/flags.go b/cmd/server/flags.go index ac5a3fd66..779d91400 100644 --- a/cmd/server/flags.go +++ b/cmd/server/flags.go @@ -276,7 +276,12 @@ var flags = append([]cli.Flag{ &cli.StringFlag{ Sources: cli.EnvVars("WOODPECKER_CONFIG_SERVICE_ENDPOINT"), Name: "config-service-endpoint", - Usage: "url used for calling configuration service endpoint", + Usage: "url used for calling global configuration service endpoint", + }, + &cli.BoolFlag{ + Sources: cli.EnvVars("WOODPECKER_CONFIG_SERVICE_EXCLUSIVE"), + Name: "config-service-exclusive", + Usage: "whether global configuration service endpoint should be exclusive (skip forge)", }, &cli.StringFlag{ Sources: cli.EnvVars("WOODPECKER_EXTENSIONS_ALLOWED_HOSTS"), diff --git a/cmd/server/grpc_server.go b/cmd/server/grpc_server.go index 7e7cf2a1a..216dde8de 100644 --- a/cmd/server/grpc_server.go +++ b/cmd/server/grpc_server.go @@ -24,9 +24,9 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/keepalive" - "go.woodpecker-ci.org/woodpecker/v3/pipeline/rpc/proto" + "go.woodpecker-ci.org/woodpecker/v3/rpc/proto" "go.woodpecker-ci.org/woodpecker/v3/server" - woodpeckerGrpcServer "go.woodpecker-ci.org/woodpecker/v3/server/grpc" + woodpeckerGrpcServer "go.woodpecker-ci.org/woodpecker/v3/server/rpc" "go.woodpecker-ci.org/woodpecker/v3/server/store" ) diff --git a/cmd/server/openapi/docs.go b/cmd/server/openapi/docs.go index c232b012a..c5c78746b 100644 --- a/cmd/server/openapi/docs.go +++ b/cmd/server/openapi/docs.go @@ -1729,7 +1729,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/Secret" + "$ref": "#/definitions/SecretPatch" } } ], @@ -2681,7 +2681,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/Cron" + "$ref": "#/definitions/CronPatch" } } ], @@ -3921,7 +3921,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/Secret" + "$ref": "#/definitions/SecretPatch" } } ], @@ -4113,7 +4113,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/Secret" + "$ref": "#/definitions/SecretPatch" } } ], @@ -4678,6 +4678,17 @@ const docTemplate = `{ } } }, + "CancelInfo": { + "type": "object", + "properties": { + "canceled_by_user": { + "type": "string" + }, + "superseded_by": { + "type": "integer" + } + } + }, "Config": { "type": "object", "properties": { @@ -4705,8 +4716,12 @@ const docTemplate = `{ "type": "integer" }, "creator_id": { + "description": "TODO: drop with next major version", "type": "integer" }, + "enabled": { + "type": "boolean" + }, "id": { "type": "integer" }, @@ -4722,6 +4737,35 @@ const docTemplate = `{ "schedule": { "description": "@weekly,\t3min, ...", "type": "string" + }, + "variables": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + }, + "CronPatch": { + "type": "object", + "properties": { + "branch": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "schedule": { + "type": "string" + }, + "variables": { + "type": "object", + "additionalProperties": { + "type": "string" + } } } }, @@ -4949,6 +4993,9 @@ const docTemplate = `{ "branch": { "type": "string" }, + "cancel_info": { + "$ref": "#/definitions/CancelInfo" + }, "changed_files": { "type": "array", "items": { @@ -4970,7 +5017,7 @@ const docTemplate = `{ "errors": { "type": "array", "items": { - "$ref": "#/definitions/types.PipelineError" + "$ref": "#/definitions/errors.PipelineError" } }, "event": { @@ -5190,6 +5237,9 @@ const docTemplate = `{ "config_extension_endpoint": { "type": "string" }, + "config_extension_exclusive": { + "type": "boolean" + }, "config_file": { "type": "string" }, @@ -5283,6 +5333,9 @@ const docTemplate = `{ "config_extension_endpoint": { "type": "string" }, + "config_extension_exclusive": { + "type": "boolean" + }, "config_file": { "type": "string" }, @@ -5367,6 +5420,9 @@ const docTemplate = `{ "config_extension_endpoint": { "type": "string" }, + "config_extension_exclusive": { + "type": "boolean" + }, "config_file": { "type": "string" }, @@ -5424,6 +5480,9 @@ const docTemplate = `{ "name": { "type": "string" }, + "note": { + "type": "string" + }, "org_id": { "type": "integer" }, @@ -5435,6 +5494,32 @@ const docTemplate = `{ } } }, + "SecretPatch": { + "type": "object", + "properties": { + "events": { + "type": "array", + "items": { + "$ref": "#/definitions/WebhookEvent" + } + }, + "images": { + "type": "array", + "items": { + "type": "string" + } + }, + "name": { + "type": "string" + }, + "note": { + "type": "string" + }, + "value": { + "type": "string" + } + } + }, "StatusValue": { "type": "string", "enum": [ @@ -5651,6 +5736,52 @@ const docTemplate = `{ "EventManual" ] }, + "errors.PipelineError": { + "type": "object", + "properties": { + "data": {}, + "is_warning": { + "type": "boolean" + }, + "message": { + "type": "string" + }, + "type": { + "$ref": "#/definitions/errors.PipelineErrorType" + } + } + }, + "errors.PipelineErrorType": { + "type": "string", + "enum": [ + "linter", + "deprecation", + "compiler", + "generic", + "bad_habit" + ], + "x-enum-comments": { + "PipelineErrorTypeBadHabit": "some bad-habit error", + "PipelineErrorTypeCompiler": "some error with the config semantics", + "PipelineErrorTypeDeprecation": "using some deprecated feature", + "PipelineErrorTypeGeneric": "some generic error", + "PipelineErrorTypeLinter": "some error with the config syntax" + }, + "x-enum-descriptions": [ + "some error with the config syntax", + "using some deprecated feature", + "some error with the config semantics", + "some generic error", + "some bad-habit error" + ], + "x-enum-varnames": [ + "PipelineErrorTypeLinter", + "PipelineErrorTypeDeprecation", + "PipelineErrorTypeCompiler", + "PipelineErrorTypeGeneric", + "PipelineErrorTypeBadHabit" + ] + }, "metadata.Author": { "type": "object", "properties": { @@ -6071,52 +6202,6 @@ const docTemplate = `{ "$ref": "#/definitions/StatusValue" } } - }, - "types.PipelineError": { - "type": "object", - "properties": { - "data": {}, - "is_warning": { - "type": "boolean" - }, - "message": { - "type": "string" - }, - "type": { - "$ref": "#/definitions/types.PipelineErrorType" - } - } - }, - "types.PipelineErrorType": { - "type": "string", - "enum": [ - "linter", - "deprecation", - "compiler", - "generic", - "bad_habit" - ], - "x-enum-comments": { - "PipelineErrorTypeBadHabit": "some bad-habit error", - "PipelineErrorTypeCompiler": "some error with the config semantics", - "PipelineErrorTypeDeprecation": "using some deprecated feature", - "PipelineErrorTypeGeneric": "some generic error", - "PipelineErrorTypeLinter": "some error with the config syntax" - }, - "x-enum-descriptions": [ - "some error with the config syntax", - "using some deprecated feature", - "some error with the config semantics", - "some generic error", - "some bad-habit error" - ], - "x-enum-varnames": [ - "PipelineErrorTypeLinter", - "PipelineErrorTypeDeprecation", - "PipelineErrorTypeCompiler", - "PipelineErrorTypeGeneric", - "PipelineErrorTypeBadHabit" - ] } } }` diff --git a/cmd/server/setup.go b/cmd/server/setup.go index f8a34ae0a..5728a8b15 100644 --- a/cmd/server/setup.go +++ b/cmd/server/setup.go @@ -25,8 +25,8 @@ import ( "strings" "time" - "github.com/google/tink/go/subtle/random" "github.com/rs/zerolog/log" + "github.com/tink-crypto/tink-go/v2/subtle/random" "github.com/urfave/cli/v3" "go.woodpecker-ci.org/woodpecker/v3/server" diff --git a/codecov.yaml b/codecov.yaml new file mode 100644 index 000000000..a474fec9e --- /dev/null +++ b/codecov.yaml @@ -0,0 +1,2 @@ +ignore: + - '**/mocks/mock_*.go' diff --git a/docker-compose.gitpod.yaml b/docker-compose.gitpod.yaml index eb1bccf63..76d484afe 100644 --- a/docker-compose.gitpod.yaml +++ b/docker-compose.gitpod.yaml @@ -3,7 +3,7 @@ version: '3' services: gitea-database: - image: postgres:18.1-alpine + image: postgres:18.2-alpine environment: POSTGRES_USER: gitea POSTGRES_PASSWORD: 123456 diff --git a/docker/Dockerfile.agent.alpine.multiarch b/docker/Dockerfile.agent.alpine.multiarch index 8f78b0c1f..3aa076bf8 100644 --- a/docker/Dockerfile.agent.alpine.multiarch +++ b/docker/Dockerfile.agent.alpine.multiarch @@ -1,4 +1,4 @@ -FROM --platform=$BUILDPLATFORM docker.io/golang:1.25 AS build +FROM --platform=$BUILDPLATFORM docker.io/golang:1.26 AS build WORKDIR /src COPY . . diff --git a/docker/Dockerfile.agent.multiarch b/docker/Dockerfile.agent.multiarch index 07d7d49a9..be3be9003 100644 --- a/docker/Dockerfile.agent.multiarch +++ b/docker/Dockerfile.agent.multiarch @@ -1,4 +1,4 @@ -FROM --platform=$BUILDPLATFORM docker.io/golang:1.25 AS build +FROM --platform=$BUILDPLATFORM docker.io/golang:1.26 AS build RUN groupadd -g 1000 woodpecker && \ useradd -u 1000 -g 1000 woodpecker && \ diff --git a/docker/Dockerfile.cli.alpine.multiarch.rootless b/docker/Dockerfile.cli.alpine.multiarch.rootless index 17b8e77ea..257ec8781 100644 --- a/docker/Dockerfile.cli.alpine.multiarch.rootless +++ b/docker/Dockerfile.cli.alpine.multiarch.rootless @@ -1,4 +1,4 @@ -FROM --platform=$BUILDPLATFORM docker.io/golang:1.25 AS build +FROM --platform=$BUILDPLATFORM docker.io/golang:1.26 AS build WORKDIR /src COPY . . diff --git a/docker/Dockerfile.cli.multiarch.rootless b/docker/Dockerfile.cli.multiarch.rootless index e04804d57..53721022c 100644 --- a/docker/Dockerfile.cli.multiarch.rootless +++ b/docker/Dockerfile.cli.multiarch.rootless @@ -1,4 +1,4 @@ -FROM --platform=$BUILDPLATFORM docker.io/golang:1.25 AS build +FROM --platform=$BUILDPLATFORM docker.io/golang:1.26 AS build RUN groupadd -g 1000 woodpecker && \ useradd -u 1000 -g 1000 woodpecker diff --git a/docker/Dockerfile.make b/docker/Dockerfile.make index c2ee5395e..8705fc91d 100644 --- a/docker/Dockerfile.make +++ b/docker/Dockerfile.make @@ -1,5 +1,5 @@ # docker build --rm -f docker/Dockerfile.make -t woodpecker/make:local . -FROM docker.io/golang:1.25-alpine AS golang_image +FROM docker.io/golang:1.26-alpine AS golang_image FROM docker.io/node:24-alpine RUN apk add --no-cache --update make gcc binutils-gold musl-dev && \ diff --git a/docker/Dockerfile.server.multiarch.rootless b/docker/Dockerfile.server.multiarch.rootless index 0b8989b4e..be3d63f96 100644 --- a/docker/Dockerfile.server.multiarch.rootless +++ b/docker/Dockerfile.server.multiarch.rootless @@ -1,4 +1,4 @@ -FROM --platform=$BUILDPLATFORM docker.io/golang:1.25 AS build +FROM --platform=$BUILDPLATFORM docker.io/golang:1.26 AS build RUN groupadd -g 1000 woodpecker && \ useradd -u 1000 -g 1000 woodpecker && \ diff --git a/docs/docs/20-usage/100-troubleshooting.md b/docs/docs/20-usage/100-troubleshooting.md index b961530f4..2885c134d 100644 --- a/docs/docs/20-usage/100-troubleshooting.md +++ b/docs/docs/20-usage/100-troubleshooting.md @@ -35,3 +35,63 @@ git fetch --no-tags origin +refs/heads/branch: ``` (replace the url AND the branch with the correct values, use your username and password as log in values) + +## SELinux Issues + +When running Woodpecker on systems with SELinux enabled (such as RHEL, CentOS, Fedora, or other Enterprise Linux distributions), SELinux may prevent the agent from accessing the Docker socket. + +### Symptoms + +If SELinux is blocking access, you may see errors like: + +```text +permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock +``` + +### Solutions + +There are several ways to resolve this: + +#### Option 1: Set SELinux to Permissive Mode (For Testing Only) + +Set SELinux to permissive mode temporarily to verify it's the issue: + +```bash +setenforce 0 +``` + +To permanently set SELinux to permissive mode: + +```bash +# Edit /etc/selinux/config +SELINUX=permissive +``` + +#### Option 2: Configure SELinux Policy (Recommended) + +Create a custom SELinux policy to allow Woodpecker agent to access Docker: + +```bash +# Generate the policy module +ausearch -c 'docker' -avc | audit2allow -R -o woodpecker-docker.te +# Build the policy module +checkmodule -M -m -o woodpecker-docker.mod woodpecker-docker.te +semodule_package -o woodpecker-docker.pp -m woodpecker-docker.mod +# Load the policy module +semodule -i woodpecker-docker.pp +``` + +#### Option 3: Use Docker Volume with SELinux Options + +When using Docker Compose or Docker, add the `:z` or `:Z` option to volume mounts: + +```yaml +volumes: + - /var/run/docker.sock:/var/run/docker.sock:z +``` + +The `:z` option tells Docker to automatically relabel the volume content for SELinux. Use `:Z` with caution as it relabels the volume exclusively for this container. + +#### Option 4: Use Podman (Alternative) + +If you prefer to avoid SELinux configuration issues, consider using Podman instead of Docker, as it has better SELinux integration. diff --git a/docs/docs/20-usage/60-services.md b/docs/docs/20-usage/60-services.md index 14262855c..fa243f70f 100644 --- a/docs/docs/20-usage/60-services.md +++ b/docs/docs/20-usage/60-services.md @@ -37,6 +37,20 @@ services: - 51820/udp ``` +## Stopping + +Services that are no longer needed receive a **SIGTERM** signal. If they do not respond, they are forcibly terminated with **SIGKILL**. +If there are services that do not shut down properly and this doesn't matter, you can simply ignore the error: + +```diff + services: + - name: database + image: mysql ++ failure: ignore # we don't care how mysql exits + ports: + - 3306 +``` + ## Configuration Service containers generally expose environment variables to customize service startup such as default usernames, passwords and ports. Please see the official image documentation to learn more. @@ -46,8 +60,8 @@ Service containers generally expose environment variables to customize service s - name: database image: mysql + environment: -+ - MYSQL_DATABASE=test -+ - MYSQL_ALLOW_EMPTY_PASSWORD=yes ++ MYSQL_DATABASE: test ++ MYSQL_ALLOW_EMPTY_PASSWORD: yes - name: cache image: redis @@ -102,8 +116,8 @@ services: - name: database image: mysql environment: - - MYSQL_DATABASE=test - - MYSQL_ROOT_PASSWORD=example + MYSQL_DATABASE: test + MYSQL_ROOT_PASSWORD: example steps: - name: get-version image: ubuntu diff --git a/docs/docs/20-usage/72-extensions/40-configuration-extension.md b/docs/docs/20-usage/72-extensions/40-configuration-extension.md index 63d806117..baa27e25d 100644 --- a/docs/docs/20-usage/72-extensions/40-configuration-extension.md +++ b/docs/docs/20-usage/72-extensions/40-configuration-extension.md @@ -23,7 +23,7 @@ As Woodpecker will pass private information like tokens and will execute the ret In addition to the ability to configure the extension per repository, you can also configure a global endpoint in the Woodpecker server configuration. This can be useful if you want to use the extension for all repositories. Be careful if you share your Woodpecker server with others as they will also use your configuration extension. -The global configuration will be called before the repository specific configuration extension if both are configured. +The global configuration will be called before the repository specific configuration extension if both are configured and the repository has not enabled the exclusive setting. ```ini title="Server" WOODPECKER_CONFIG_SERVICE_ENDPOINT=https://example.com/ciconfig @@ -33,6 +33,8 @@ WOODPECKER_CONFIG_SERVICE_ENDPOINT=https://example.com/ciconfig When a pipeline is triggered Woodpecker will fetch the pipeline configuration from the repository, then make a HTTP POST request to the configured extension with a JSON payload containing some data like the repository, pipeline information and the current config files retrieved from the repository. The extension can then send back modified or even new pipeline configurations following Woodpeckers official yaml format that should be used. +You can enable the exclusive setting (both globally and on a per-repo level). Then Woodpecker will only call your extension, but nothing else. This allows you to completely skip the forge. Requests sent to the extension will not have the configuration files added. + ### Request The extension receives an HTTP POST request with the following JSON payload: @@ -43,6 +45,7 @@ class Request { pipeline: Pipeline; netrc: Netrc; configuration: { + // list of configurations. Not send if there was none. name: string; // filename of the configuration file data: string; // content of the configuration file }[]; @@ -123,7 +126,7 @@ Example request: "updated_at": 0, "verified": false }, - "configs": [ + "configuration": [ { "name": ".woodpecker.yaml", "data": "steps:\n - name: backend\n image: alpine\n commands:\n - echo \"Hello there from Repo (.woodpecker.yaml)\"\n" diff --git a/docs/docs/30-administration/05-installation/10-docker-compose.md b/docs/docs/30-administration/05-installation/10-docker-compose.md index 3ac2400e3..7f8fea552 100644 --- a/docs/docs/30-administration/05-installation/10-docker-compose.md +++ b/docs/docs/30-administration/05-installation/10-docker-compose.md @@ -140,3 +140,14 @@ To store values in a docker secret you can use the following command: ```bash echo "my_agent_secret_key" | docker secret create woodpecker-agent-secret - ``` + +## SELinux Considerations + +If you're running Woodpecker on a system with SELinux enabled (RHEL, CentOS, Fedora, etc.), you may need to add the `:z` or `:Z` option to volume mounts. For the Docker socket volume: + +```yaml +volumes: + - /var/run/docker.sock:/var/run/docker.sock:z +``` + +For more details and other SELinux-related solutions, see the [Troubleshooting](../../20-usage/100-troubleshooting.md#selinux-issues) page. diff --git a/docs/docs/30-administration/05-installation/20-helm-chart.md b/docs/docs/30-administration/05-installation/20-helm-chart.md index d421f8959..54a14eddb 100644 --- a/docs/docs/30-administration/05-installation/20-helm-chart.md +++ b/docs/docs/30-administration/05-installation/20-helm-chart.md @@ -3,8 +3,7 @@ Woodpecker provides a [Helm chart](https://github.com/woodpecker-ci/helm) for Kubernetes environments: ```bash -helm repo add woodpecker oci://ghcr.io/woodpecker-ci/helm -helm install woodpecker woodpecker/woodpecker +helm install woodpecker oci://ghcr.io/woodpecker-ci/helm/woodpecker --version ``` ## Metrics diff --git a/docs/docs/30-administration/05-installation/30-packages.md b/docs/docs/30-administration/05-installation/30-packages.md index ca4c55e2f..0b346a9bc 100644 --- a/docs/docs/30-administration/05-installation/30-packages.md +++ b/docs/docs/30-administration/05-installation/30-packages.md @@ -92,6 +92,7 @@ Woodpecker itself is not responsible for creating these packages. Please reach o - [YunoHost](https://apps.yunohost.org/app/woodpecker) - [Cloudron](https://www.cloudron.io/store/org.woodpecker_ci.cloudronapp.html) - [Easypanel](https://easypanel.io/docs/templates/woodpeckerci) +- [Homebrew](https://formulae.brew.sh/formula/woodpecker-cli) (CLI only) ### NixOS diff --git a/docs/docs/30-administration/10-configuration/10-server.md b/docs/docs/30-administration/10-configuration/10-server.md index 61e67b109..8994af44f 100644 --- a/docs/docs/30-administration/10-configuration/10-server.md +++ b/docs/docs/30-administration/10-configuration/10-server.md @@ -402,97 +402,6 @@ woodpecker_waiting_steps 0 woodpecker_worker_count 4 ``` -## External Configuration API - -To provide additional management and preprocessing capabilities for pipeline configurations Woodpecker supports an HTTP API which can be enabled to call an external config service. -Before the run or restart of any pipeline Woodpecker will make a POST request to an external HTTP API sending the current repository, build information and all current config files retrieved from the repository. The external API can then send back new pipeline configurations that will be used immediately or respond with `HTTP 204` to tell the system to use the existing configuration. - -Every request sent by Woodpecker is signed using a [http-signature](https://datatracker.ietf.org/doc/html/rfc9421) by a private key (ed25519) generated on the first start of the Woodpecker server. You can get the public key for the verification of the http-signature from `http(s)://your-woodpecker-server/api/signature/public-key`. - -A simplistic example configuration service can be found here: [https://github.com/woodpecker-ci/example-config-service](https://github.com/woodpecker-ci/example-config-service) - -:::warning -You need to trust the external config service as it is getting secret information about the repository and pipeline and has the ability to change pipeline configs that could run malicious tasks. -::: - -### Configuration - -```ini title="Server" -WOODPECKER_CONFIG_SERVICE_ENDPOINT=https://example.com/ciconfig -``` - -#### Example request made by Woodpecker - -```json -{ - "repo": { - "id": 100, - "uid": "", - "user_id": 0, - "namespace": "", - "name": "woodpecker-test-pipe", - "slug": "", - "scm": "git", - "git_http_url": "", - "git_ssh_url": "", - "link": "", - "default_branch": "", - "private": true, - "visibility": "private", - "active": true, - "config": "", - "trusted": false, - "protected": false, - "ignore_forks": false, - "ignore_pulls": false, - "cancel_pulls": false, - "timeout": 60, - "counter": 0, - "synced": 0, - "created": 0, - "updated": 0, - "version": 0 - }, - "pipeline": { - "author": "myUser", - "author_avatar": "https://myforge.com/avatars/d6b3f7787a685fcdf2a44e2c685c7e03", - "author_email": "my@email.com", - "branch": "main", - "changed_files": ["some-file-name.txt"], - "commit": "2fff90f8d288a4640e90f05049fe30e61a14fd50", - "created_at": 0, - "deploy_to": "", - "enqueued_at": 0, - "error": "", - "event": "push", - "finished_at": 0, - "id": 0, - "link_url": "https://myforge.com/myUser/woodpecker-testpipe/commit/2fff90f8d288a4640e90f05049fe30e61a14fd50", - "message": "test old config\n", - "number": 0, - "parent": 0, - "ref": "refs/heads/main", - "refspec": "", - "clone_url": "", - "reviewed_at": 0, - "reviewed_by": "", - "sender": "myUser", - "signed": false, - "started_at": 0, - "status": "", - "timestamp": 1645962783, - "title": "", - "updated_at": 0, - "verified": false - }, - "netrc": { - "machine": "https://example.com", - "login": "user", - "password": "password" - } -} -``` - #### Example response structure ```json @@ -1067,7 +976,20 @@ Supported variables: - Name: `WOODPECKER_CONFIG_SERVICE_ENDPOINT` - Default: none -Specify a configuration service endpoint, see [Configuration Extension](#external-configuration-api) +Specify a configuration service endpoint, see [Configuration Extension](../../20-usage/72-extensions/40-configuration-extension.md) + +--- + +### CONFIG_SERVICE_EXCLUSIVE + +- Name: `CONFIG_SERVICE_EXCLUSIVE` +- Default: false + +Whether the forge request should be skipped for the global configuration endpoint. + +:::warning +If you enable this, all repos will exclusively use the global config service endpoint. There is no possibility to directly define pipelines in the forge, except the extension handles this case itself as well. +::: --- diff --git a/docs/docs/30-administration/10-configuration/12-forges/30-gitea.md b/docs/docs/30-administration/10-configuration/12-forges/30-gitea.md index ad2f92e62..7631101fa 100644 --- a/docs/docs/30-administration/10-configuration/12-forges/30-gitea.md +++ b/docs/docs/30-administration/10-configuration/12-forges/30-gitea.md @@ -33,8 +33,29 @@ To configure the Docker network if the network's name is `gitea`, configure it l ## Registration +### User OAuth Application + Register your application with Gitea to create your client id and secret. You can find the OAuth applications settings of Gitea at `https://gitea./user/settings/`. It is very important that authorization callback URL matches your http(s) scheme and hostname exactly with `https:///authorize` as the path. +### System-wide OAuth Application + +If you are the administrator of both Gitea and Woodpecker, you may prefer to use a system-wide OAuth application instead of a user-level application. System-wide applications are managed at the Gitea site administrator level and are visible to all users. + +To create a system-wide OAuth application in Gitea: + +1. Navigate to the site administration settings at `https://gitea./admin/settings/applications` +2. Create a new OAuth2 application under the "OAuth2 Applications" section +3. Configure the application with the same settings as above (callback URL, etc.) +4. Use the generated client id and secret for Woodpecker configuration + +System-wide applications are particularly useful for: + +- Shared CI/CD environments where multiple users need Woodpecker access +- Organizations that want centralized control over OAuth applications +- Preventing user-level application quotas from affecting CI/CD operations + +### Local Connections + If you run the Woodpecker CI server on the same host as the Gitea instance, you might also need to allow local connections in Gitea, since version `v1.16`. Otherwise webhooks will fail. Add the following lines to your Gitea configuration (usually at `/etc/gitea/conf/app.ini`). ```ini diff --git a/docs/docs/30-administration/10-configuration/12-forges/35-forgejo.md b/docs/docs/30-administration/10-configuration/12-forges/35-forgejo.md index bd45c2aac..56d64f877 100644 --- a/docs/docs/30-administration/10-configuration/12-forges/35-forgejo.md +++ b/docs/docs/30-administration/10-configuration/12-forges/35-forgejo.md @@ -33,8 +33,29 @@ To configure the Docker network if the network's name is `forgejo`, configure it ## Registration +### User OAuth Application + Register your application with Forgejo to create your client id and secret. You can find the OAuth applications settings of Forgejo at `https://forgejo./user/settings/`. It is very important that authorization callback URL matches your http(s) scheme and hostname exactly with `https:///authorize` as the path. +### System-wide OAuth Application + +If you are the administrator of both Forgejo and Woodpecker, you may prefer to use a system-wide OAuth application instead of a user-level application. System-wide applications are managed at the Forgejo site administrator level and are visible to all users. + +To create a system-wide OAuth application in Forgejo: + +1. Navigate to the site administration settings at `https://forgejo./admin/settings/applications` +2. Create a new OAuth2 application under the "OAuth2 Applications" section +3. Configure the application with the same settings as above (callback URL, etc.) +4. Use the generated client id and secret for Woodpecker configuration + +System-wide applications are particularly useful for: + +- Shared CI/CD environments where multiple users need Woodpecker access +- Organizations that want centralized control over OAuth applications +- Preventing user-level application quotas from affecting CI/CD operations + +### Local Connections + If you run the Woodpecker CI server on the same host as the Forgejo instance, you might also need to allow local connections in Forgejo. Otherwise webhooks will fail. Add the following lines to your Forgejo configuration (usually at `/etc/forgejo/conf/app.ini`). ```ini diff --git a/docs/docs/92-development/01-getting-started.md b/docs/docs/92-development/01-getting-started.md index 89e5d960c..ed8020202 100644 --- a/docs/docs/92-development/01-getting-started.md +++ b/docs/docs/92-development/01-getting-started.md @@ -20,7 +20,7 @@ Start Woodpecker in Gitpod by clicking on the following badge. You can log in wi ### Install Go -Install Golang (>=1.20) as described by [this guide](https://go.dev/doc/install). +Install Golang as described by [this guide](https://go.dev/doc/install). ### Install make @@ -34,7 +34,7 @@ Install make on: ### Install Node.js & `pnpm` -Install [Node.js (>=20)](https://nodejs.org/en/download/package-manager) if you want to build Woodpecker's UI or documentation. +Install [Node.js](https://nodejs.org/en/download/package-manager) if you want to build Woodpecker's UI or documentation. For dependency installation (`node_modules`) of UI and documentation of Woodpecker the package manager pnpm is used. [This guide](https://pnpm.io/installation) describes the installation of `pnpm`. diff --git a/docs/docs/92-development/02-core-ideas.md b/docs/docs/92-development/02-core-ideas.md index 2f9570685..49a276d25 100644 --- a/docs/docs/92-development/02-core-ideas.md +++ b/docs/docs/92-development/02-core-ideas.md @@ -8,7 +8,7 @@ ## Addons and extensions If you are wondering whether your contribution will be accepted to be merged in the Woodpecker core, or whether it's better to write an -[addon](../30-administration/10-configuration/100-addons.md), [extension](../30-administration/10-configuration/10-server.md#external-configuration-api) or an +[addon](../30-administration/10-configuration/100-addons.md), [extension](../20-usage/72-extensions/40-configuration-extension.md) or an [external custom backend](../30-administration/10-configuration/11-backends/50-custom.md), please check these points: - Is your change very specific to your setup and unlikely to be used by anyone else? diff --git a/docs/docs/92-development/05-architecture.md b/docs/docs/92-development/05-architecture.md index 535ec6a80..556c595c9 100644 --- a/docs/docs/92-development/05-architecture.md +++ b/docs/docs/92-development/05-architecture.md @@ -1,8 +1,16 @@ # Architecture -## Package architecture +## Module Interactions -![Woodpecker architecture](./woodpecker-architecture.png) +![Woodpecker architecture](./woodpecker-architecture.svg) + + ## System architecture @@ -11,38 +19,70 @@ | package | meaning | imports | | ------------------ | -------------------------------------------------------------- | ------------------------------------- | | `cmd/**` | parse command-line args & environment to stat server/cli/agent | all other | -| `agent/**` | code only agent (remote worker) will need | `pipeline`, `shared` | +| `agent/**` | code only agent (remote worker) will need | `pipeline`, `rpc`, `shared` | | `cli/**` | code only cli tool does need | `pipeline`, `shared`, `woodpecker-go` | -| `server/**` | code only server will need | `pipeline`, `shared` | +| `server/**` | code only server will need | `pipeline`, `rpc`, `shared` | +| `pipeline/**` | core ci/cd engine from parsing to execution | `shared` | +| `rpc/**` | RPC interface for agent-server communication | `pipeline` | | `shared/**` | code shared for all three main tools (go help utils) | only std and external libs | | `woodpecker-go/**` | go client for server rest api | std | ### Server -| package | meaning | imports | -| -------------------- | ----------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `server/api/**` | handle web requests from `server/router` | `pipeline`, `../badges`, `../ccmenu`, `../logging`, `../model`, `../pubsub`, `../queue`, `../forge`, `../shared`, `../store`, `shared`, (TODO: mv `server/router/middleware/session`) | -| `server/badges/**` | generate svg badges for pipelines | `../model` | -| `server/ccmenu/**` | generate xml ccmenu for pipelines | `../model` | -| `server/grpc/**` | gRPC server agents can connect to | `pipeline/rpc/**`, `../logging`, `../model`, `../pubsub`, `../queue`, `../forge`, `../pipeline`, `../store` | -| `server/logging/**` | logging lib for gPRC server to stream logs while running | std | -| `server/model/**` | structs for store (db) and api (json) | std | -| `server/plugins/**` | plugins for server | `../model`, `../forge` | -| `server/pipeline/**` | orchestrate pipelines | `pipeline`, `../model`, `../pubsub`, `../queue`, `../forge`, `../store`, `../plugins` | -| `server/pubsub/**` | pubsub lib for server to push changes to the WebUI | std | -| `server/queue/**` | queue lib for server where agents pull new pipelines from via gRPC | `server/model` | -| `server/forge/**` | forge lib for server to connect and handle forge specific stuff | `shared`, `server/model` | -| `server/router/**` | handle requests to REST API (and all middleware) and serve UI and WebUI config | `shared`, `../api`, `../model`, `../forge`, `../store`, `../web` | -| `server/store/**` | handle database | `server/model` | -| `server/shared/**` | TODO: move and split [#974](https://github.com/woodpecker-ci/woodpecker/issues/974) | | -| `server/web/**` | server SPA | | +| package | meaning | imports | +| -------------------- | ------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `server/api/**` | handle web requests from `server/router` | `pipeline`, `rpc`, `../badges`, `../ccmenu`, `../logging`, `../model`, `../pubsub`, `../queue`, `../forge`, `../shared`, `../store`, `shared`, (TODO: mv `server/router/middleware/session`) | +| `server/badges/**` | generate svg badges for pipelines | `../model` | +| `server/ccmenu/**` | generate xml ccmenu for pipelines | `../model` | +| `server/rpc/**` | gRPC server agents can connect to | `rpc`, `../logging`, `../model`, `../pubsub`, `../queue`, `../forge`, `../pipeline`, `../store` | +| `server/logging/**` | logging lib for gPRC server to stream logs while running | std | +| `server/model/**` | structs for store (db) and api (json) | std | +| `server/pipeline/**` | orchestrate pipelines (TODO: parts of it should move into /pipeline) | `pipeline`, `../model`, `../pubsub`, `../queue`, `../forge`, `../store`, `../plugins` | +| `server/pubsub/**` | pubsub lib for server to push changes to the WebUI | std | +| `server/queue/**` | queue lib for server where agents pull new pipelines from via gRPC | `server/model` | +| `server/forge/**` | forge lib for server to connect and handle forge specific stuff | `shared`, `server/model` | +| `server/router/**` | handle requests to REST API (and all middleware) and serve UI and WebUI config | `shared`, `../api`, `../model`, `../forge`, `../store`, `../web` | +| `server/store/**` | handle database | `server/model` | +| `server/web/**` | server SPA | | - `../` = `server/` ### Agent -TODO +| package | meaning | imports | +| -------------- | ---------------------------------------------------- | ------------------------------------------------------ | +| `agent/**` | agent implementation that runs workflows | `pipeline`, `rpc`, `shared` | +| `agent/rpc/**` | gRPC client for agent-server communication | `rpc`, `pipeline/backend/types`, std and external libs | +| `cmd/agent/**` | CLI interface for starting and configuring the agent | `agent`, std and external libs | + +The agent is a remote worker that connects to the server via gRPC to receive pipeline execution instructions and report back execution state and logs. +The agent polls the server's queue for new work, executes pipeline steps using the pipeline engine, and streams results back to the server. + +TODO: Review cmd/agent/core to determine if any logic should be moved into the agent package for better separation of concerns. ### CLI -TODO +| package | meaning | imports | +| ------------------------ | ----------------------------------------------------------------------- | -------------------------------------------------------------------------------- | +| `cli/admin/**` | admin commands for server management (users, secrets, registries, etc.) | `../common`, `../internal`, `woodpecker-go` | +| `cli/common/**` | shared utilities and helpers used across all CLI subcommands | `../internal/config`, `../update`, `shared` | +| `cli/context/**` | manage multiple server contexts (connections to different servers) | `../common`, `../internal/config`, `../output` | +| `cli/exec/**` | execute pipelines locally without server orchestration | `pipeline`, `../common`, `../lint`, `shared` | +| `cli/info/**` | display information about the current user | `../common`, `../internal` | +| `cli/internal/**` | internal utilities for HTTP client, auth, and server communication | `../internal/config`, `woodpecker-go`, `shared` | +| `cli/internal/config/**` | configuration file management (load, store, credentials) | std and external libs | +| `cli/lint/**` | validate pipeline configuration files | `pipeline/frontend/yaml`, `pipeline/frontend/yaml/linter`, `../common`, `shared` | +| `cli/org/**` | manage organization-level resources (secrets, registries) | `../common`, `../internal`, `woodpecker-go` | +| `cli/output/**` | formatting utilities for CLI output (tables, etc.) | std and external libs | +| `cli/pipeline/**` | manage pipeline operations (start, stop, approve, logs, etc.) | `../common`, `../internal`, `../output`, `woodpecker-go`, `shared` | +| `cli/repo/**` | manage repository-level resources (repos, crons, secrets, registries) | `../common`, `../internal`, `../output`, `woodpecker-go` | +| `cli/setup/**` | interactive first-time setup wizard for CLI configuration | `../internal/config` | +| `cli/update/**` | self-updater for the CLI binary | std and external libs | +| `cmd/cli/**` | CLI entry point and command structure | `cli/**` | + +The CLI provides a command-line interface for interacting with Woodpecker servers. +Each subcommand is organized into its own package under `cli//`. + +The `cli/exec` subcommand allows local pipeline execution for testing and development by combining pipeline parsing and execution without requiring a running server or agent. + +- `../` = `cli/` diff --git a/docs/docs/92-development/40-deprecations.md b/docs/docs/92-development/40-deprecations.md new file mode 100644 index 000000000..f19f17c8e --- /dev/null +++ b/docs/docs/92-development/40-deprecations.md @@ -0,0 +1,43 @@ +# Deprecation Policy + +## Pipeline Configuration Changes + +Pipeline configuration (YAML syntax) changes follow a strict deprecation process to ensure users have sufficient time to migrate. + +### Process Timeline + +1. **Minor Version N.x - Add Deprecation Warning** + - Linter shows a warning (not an error) + - Old syntax remains functional + - Documentation is updated to reflect the new syntax + - Warning message includes guidance on required changes + +2. **Major Version (N+1).0 - Warning Becomes Error** + - Linter issues an error (pipeline fails) + - Old syntax is no longer supported + - Breaking change is documented in the migration guide + - Users **must** update their configurations + +3. **Minor Version (N+1).x - Code Cleanup** + - Deprecated code paths are removed + - Implementation is simplified/refactored + - Parser no longer recognizes the old syntax + +### Example + +Old syntax: `secrets: [token]` +New syntax: `environment: { TOKEN: { from_secret: token } }` + +- **v2.5.0:** Deprecation warning added in linter; both syntaxes work +- **v2.6-2.9:** Warning persists; both syntaxes remain functional +- **v3.0.0:** Linter error; old syntax fails (breaking change) +- **v3.1.0:** Deprecated code paths removed; parser simplified + +### Implementation Checklist + +When deprecating pipeline configuration syntax, ensure the following: + +- [ ] Add linter warning in `/pipeline/frontend/yaml/linter/` +- [ ] Update JSON schema in `/pipeline/frontend/yaml/linter/schema` +- [ ] Add test cases for deprecated syntax +- [ ] Update documentation to reflect the new syntax diff --git a/docs/docs/92-development/woodpecker-architecture.dot b/docs/docs/92-development/woodpecker-architecture.dot new file mode 100644 index 000000000..e72bede01 --- /dev/null +++ b/docs/docs/92-development/woodpecker-architecture.dot @@ -0,0 +1,157 @@ +digraph WoodpeckerArchitecture { + graph [ + rankdir=TB, + splines=ortho, + nodesep=0.5, + ranksep=0.8, + fontname="Helvetica" + ] + + node [ + shape=box, + style="rounded,filled", + fillcolor="#2b2b2b", + fontcolor="white", + fontname="Helvetica" + ] + + edge [ + color="#bdbdbd", + arrowsize=0.7 + ] + + /* ===================== UI ===================== */ + subgraph cluster_ui { + label="UI" + fillcolor="#c7efe9" + fontcolor="black" + style="rounded,filled" + + ui_web [label="web/"] + } + + /* ===================== SDK ===================== */ + subgraph cluster_sdk { + label="SDK (woodpecker-go)" + fillcolor="#e8f5e9" + fontcolor="black" + style="rounded,filled" + + sdk [label="woodpecker-go"] + } + + /* ===================== CLI ===================== */ + subgraph cluster_cli { + label="woodpecker-cli" + fillcolor="#bfe9e0" + fontcolor="black" + style="rounded,filled" + + cli_cmd [label="cmd/cli/"] + cli_core [label="cli/"] + } + + /* ===================== Agent ===================== */ + subgraph cluster_agent { + label="woodpecker-agent" + fillcolor="#ffe0c7" + fontcolor="black" + style="rounded,filled" + + agent_cmd [label="cmd/agent/"] + agent_core [label="agent/"] + } + + /* ===================== Pipelines ===================== */ + subgraph cluster_pipelines { + label="Pipelines" + fillcolor="#ffe8d6" + fontcolor="black" + style="rounded,filled" + + pipe_core [label="pipeline/"] + pipe_frontend [label="pipeline/frontend/\n(yaml)"] + pipe_backend [label="pipeline/backend/\n(exec engines)"] + } + + /* ===================== Server ===================== */ + subgraph cluster_server { + label="woodpecker-server" + fillcolor="#dbe9ff" + fontcolor="black" + style="rounded,filled" + + srv_cmd [label="cmd/server/"] + srv_router [label="server/router/"] + srv_api [label="server/api/"] + srv_grpc [label="server/rpc/"] + srv_queue [label="server/queue/"] + srv_pubsub [label="server/pubsub/"] + srv_store [label="server/store/"] + srv_model [label="server/model/"] + srv_forge [label="server/forge/"] + } + + /* ===================== Shared Libs ===================== */ + subgraph cluster_shared { + label="Shared Libs" + fillcolor="#eeeeee" + fontcolor="black" + style="rounded,filled" + + shared_util [label="shared/util/"] + shared_token [label="shared/token/"] + shared_http [label="shared/httputil/"] + shared_log [label="shared/logger/"] + } + + /* ===================== External ===================== */ + subgraph cluster_external { + label="External Systems" + style="rounded,dashed" + fontcolor="white" + + ext_scm [label="SCM Providers", shape=cloud] + ext_db [label="Database", shape=cylinder] + } + + /* ===================== Runtime Interactions ===================== */ + + /* UI */ + ui_web -> srv_router [xlabel="HTTP"] + ui_web -> srv_api [xlabel="REST API"] + + /* CLI */ + cli_cmd -> cli_core + cli_core -> sdk + sdk -> srv_api [xlabel="REST API"] + + /* Agent */ + agent_cmd -> agent_core + agent_core -> srv_grpc [xlabel="gRPC connect"] + agent_core -> srv_queue [xlabel="poll work"] + agent_core -> pipe_backend [xlabel="execute steps"] + + /* Pipelines */ + pipe_frontend -> pipe_core + pipe_core -> pipe_backend + + /* Server internal flow */ + srv_cmd -> srv_router + srv_router -> srv_api + srv_api -> srv_store + srv_api -> srv_pubsub + srv_api -> srv_queue + srv_grpc -> srv_queue + srv_store -> srv_model + + /* External integrations */ + srv_forge -> ext_scm [xlabel="SCM API"] + srv_store -> ext_db [xlabel="SQL"] + + /* Shared libs usage (consumer -> library) */ + srv_router -> shared_token + srv_api -> shared_http + srv_grpc -> shared_log + pipe_core -> shared_util +} diff --git a/docs/docs/92-development/woodpecker-architecture.svg b/docs/docs/92-development/woodpecker-architecture.svg new file mode 100644 index 000000000..5bb308a59 --- /dev/null +++ b/docs/docs/92-development/woodpecker-architecture.svg @@ -0,0 +1,352 @@ + + + + + + +WoodpeckerArchitecture + + +cluster_ui + +UI + + +cluster_sdk + +SDK (woodpecker-go) + + +cluster_cli + +woodpecker-cli + + +cluster_agent + +woodpecker-agent + + +cluster_pipelines + +Pipelines + + +cluster_server + +woodpecker-server + + +cluster_shared + +Shared Libs + + +cluster_external + +External Systems + + + +ui_web + +web/ + + + +srv_router + +server/router/ + + + +ui_web->srv_router + + +HTTP + + + +srv_api + +server/api/ + + + +ui_web->srv_api + + +REST API + + + +sdk + +woodpecker-go + + + +sdk->srv_api + + +REST API + + + +cli_cmd + +cmd/cli/ + + + +cli_core + +cli/ + + + +cli_cmd->cli_core + + + + + +cli_core->sdk + + + + + +agent_cmd + +cmd/agent/ + + + +agent_core + +agent/ + + + +agent_cmd->agent_core + + + + + +pipe_backend + +pipeline/backend/ +(exec engines) + + + +agent_core->pipe_backend + + +execute steps + + + +srv_grpc + +server/rpc/ + + + +agent_core->srv_grpc + + +gRPC connect + + + +srv_queue + +server/queue/ + + + +agent_core->srv_queue + + +poll work + + + +pipe_core + +pipeline/ + + + +pipe_core->pipe_backend + + + + + +shared_util + +shared/util/ + + + +pipe_core->shared_util + + + + + +pipe_frontend + +pipeline/frontend/ +(yaml) + + + +pipe_frontend->pipe_core + + + + + +srv_cmd + +cmd/server/ + + + +srv_cmd->srv_router + + + + + +srv_router->srv_api + + + + + +shared_token + +shared/token/ + + + +srv_router->shared_token + + + + + +srv_api->srv_queue + + + + + +srv_pubsub + +server/pubsub/ + + + +srv_api->srv_pubsub + + + + + +srv_store + +server/store/ + + + +srv_api->srv_store + + + + + +shared_http + +shared/httputil/ + + + +srv_api->shared_http + + + + + +srv_grpc->srv_queue + + + + + +shared_log + +shared/logger/ + + + +srv_grpc->shared_log + + + + + +srv_model + +server/model/ + + + +srv_store->srv_model + + + + + +ext_db + + +Database + + + +srv_store->ext_db + + +SQL + + + +srv_forge + +server/forge/ + + + +ext_scm + +SCM Providers + + + +srv_forge->ext_scm + + +SCM API + + + diff --git a/docs/docusaurus.config.ts b/docs/docusaurus.config.ts index 6bd180962..416efb58d 100644 --- a/docs/docusaurus.config.ts +++ b/docs/docusaurus.config.ts @@ -32,7 +32,6 @@ const config = { url: 'https://woodpecker-ci.org', baseUrl: '/', onBrokenLinks: 'throw', - onBrokenMarkdownLinks: 'throw', onBrokenAnchors: 'throw', onDuplicateRoutes: 'throw', organizationName: 'woodpecker-ci', @@ -319,6 +318,10 @@ const config = { ], markdown: { format: 'detect', + hooks: { + onBrokenMarkdownLinks: 'throw', + onBrokenMarkdownImages: 'throw', + }, }, future: { experimental_faster: true, diff --git a/docs/package.json b/docs/package.json index 638eb4b7b..cde5f67e5 100644 --- a/docs/package.json +++ b/docs/package.json @@ -16,15 +16,15 @@ "format:check": "prettier -c ." }, "dependencies": { - "@docusaurus/core": "^3.9.1", - "@docusaurus/faster": "^3.9.1", - "@docusaurus/plugin-content-blog": "^3.9.1", - "@docusaurus/preset-classic": "^3.9.1", - "@easyops-cn/docusaurus-search-local": "^0.52.1", + "@docusaurus/core": "^3.9.2", + "@docusaurus/faster": "^3.9.2", + "@docusaurus/plugin-content-blog": "^3.9.2", + "@docusaurus/preset-classic": "^3.9.2", + "@easyops-cn/docusaurus-search-local": "^0.55.0", "clsx": "^2.1.1", "prism-react-renderer": "^2.4.1", - "react": "^19.2.0", - "react-dom": "^19.2.0", + "react": "^19.2.4", + "react-dom": "^19.2.4", "redocusaurus": "^2.5.0" }, "browserslist": { @@ -40,15 +40,23 @@ ] }, "devDependencies": { - "@docusaurus/module-type-aliases": "^3.9.1", + "@docusaurus/module-type-aliases": "^3.9.2", "@docusaurus/tsconfig": "3.9.2", - "@docusaurus/types": "^3.9.1", + "@docusaurus/types": "^3.9.2", "@ianvs/prettier-plugin-sort-imports": "^4.7.0", - "@types/node": "^24.0.0", - "@types/react": "^19.2.0", + "@types/node": "^25.1.0", + "@types/react": "^19.2.10", "@types/react-helmet": "^6.1.11", "@types/react-router-dom": "^5.3.3", - "prettier": "^3.6.2", + "prettier": "^3.8.1", "typescript": "^5.9.3" + }, + "pnpm": { + "overrides": { + "lodash": "^4.17.23", + "fast-xml-parser": "^5.3.4", + "ajv": "^6.14.0", + "minimatch": "^10.2.1" + } } } diff --git a/docs/plugins/woodpecker-plugins/package.json b/docs/plugins/woodpecker-plugins/package.json index 33e77dc02..5ab25773a 100644 --- a/docs/plugins/woodpecker-plugins/package.json +++ b/docs/plugins/woodpecker-plugins/package.json @@ -10,25 +10,25 @@ "style": "mkdir -p dist/theme/ && cp src/theme/style.css dist/theme/style.css" }, "devDependencies": { - "@docusaurus/module-type-aliases": "^3.7.0", - "@docusaurus/theme-classic": "^3.7.0", - "@docusaurus/types": "^3.7.0", - "@tsconfig/docusaurus": "^2.0.3", - "@types/node": "^24.0.0", - "axios": "^1.7.9", - "concurrently": "^9.1.2", - "isomorphic-dompurify": "^2.19.0", - "marked": "^17.0.0", + "@docusaurus/module-type-aliases": "^3.9.2", + "@docusaurus/theme-classic": "^3.9.2", + "@docusaurus/types": "^3.9.2", + "@tsconfig/docusaurus": "^2.0.7", + "@types/node": "^24.10.9", + "axios": "^1.13.4", + "concurrently": "^9.2.1", + "isomorphic-dompurify": "^3.0.0", + "marked": "^17.0.1", "slugify": "^1.6.6", "tslib": "^2.8.1", - "typescript": "^5.7.2" + "typescript": "^5.9.3" }, "peerDependencies": { "react": "^17.0.2 || ^18.0.0 || ^19.0.0", "react-dom": "^17.0.2 || ^18.0.0 || ^19.0.0" }, "dependencies": { - "fuse.js": "^7.0.0", - "yaml": "^2.7.0" + "fuse.js": "^7.1.0", + "yaml": "^2.8.2" } } diff --git a/docs/plugins/woodpecker-plugins/plugins.json b/docs/plugins/woodpecker-plugins/plugins.json index 9b43db1eb..e715dfd5f 100644 --- a/docs/plugins/woodpecker-plugins/plugins.json +++ b/docs/plugins/woodpecker-plugins/plugins.json @@ -299,6 +299,16 @@ "name": "Github Comment", "docs": "https://raw.githubusercontent.com/yyewolf/woodpecker-plugins/refs/heads/main/github-comment/docs.md", "verified": false + }, + { + "name": "BunnyCDN Cache Purge", + "docs": "https://codeberg.org/bentasker/woodpecker-ci-bunnycdn-cache-flush/raw/branch/main/docs.md", + "verified": false + }, + { + "name": "Buildah", + "docs": "https://raw.githubusercontent.com/404systems/plugin-buildah/refs/heads/main/docs.md", + "verified": false } ] } diff --git a/docs/pnpm-lock.yaml b/docs/pnpm-lock.yaml index 12826b378..5cf6d4276 100644 --- a/docs/pnpm-lock.yaml +++ b/docs/pnpm-lock.yaml @@ -5,61 +5,64 @@ settings: excludeLinksFromLockfile: false overrides: - webpack-dev-server@<=5.2.0: '>=5.2.1' + lodash: ^4.17.23 + fast-xml-parser: ^5.3.4 + ajv: ^6.14.0 + minimatch: ^10.2.1 importers: .: dependencies: '@docusaurus/core': - specifier: ^3.9.1 - version: 3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3))(@rspack/core@1.6.7)(@swc/core@1.15.4)(debug@4.4.3)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3) + specifier: ^3.9.2 + version: 3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.4))(@rspack/core@1.7.6)(@swc/core@1.15.11)(debug@4.4.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) '@docusaurus/faster': - specifier: ^3.9.1 - version: 3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)) + specifier: ^3.9.2 + version: 3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)) '@docusaurus/plugin-content-blog': - specifier: ^3.9.1 - version: 3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@docusaurus/plugin-content-docs@3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3))(@rspack/core@1.6.7)(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3))(@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3))(@rspack/core@1.6.7)(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3) + specifier: ^3.9.2 + version: 3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@docusaurus/plugin-content-docs@3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.4))(@rspack/core@1.7.6)(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.4))(@rspack/core@1.7.6)(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) '@docusaurus/preset-classic': - specifier: ^3.9.1 - version: 3.9.2(@algolia/client-search@5.46.0)(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3))(@rspack/core@1.6.7)(@swc/core@1.15.4)(@types/react@19.2.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(search-insights@2.17.3)(typescript@5.9.3) + specifier: ^3.9.2 + version: 3.9.2(@algolia/client-search@5.49.0)(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.4))(@rspack/core@1.7.6)(@swc/core@1.15.11)(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(search-insights@2.17.3)(typescript@5.9.3) '@easyops-cn/docusaurus-search-local': - specifier: ^0.52.1 - version: 0.52.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@docusaurus/theme-common@3.9.2(@docusaurus/plugin-content-docs@3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3))(@rspack/core@1.6.7)(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3))(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3))(@rspack/core@1.6.7)(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3) + specifier: ^0.55.0 + version: 0.55.0(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@docusaurus/theme-common@3.9.2(@docusaurus/plugin-content-docs@3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.4))(@rspack/core@1.7.6)(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.4))(@rspack/core@1.7.6)(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) clsx: specifier: ^2.1.1 version: 2.1.1 prism-react-renderer: specifier: ^2.4.1 - version: 2.4.1(react@19.2.3) + version: 2.4.1(react@19.2.4) react: - specifier: ^19.2.0 - version: 19.2.3 + specifier: ^19.2.4 + version: 19.2.4 react-dom: - specifier: ^19.2.0 - version: 19.2.3(react@19.2.3) + specifier: ^19.2.4 + version: 19.2.4(react@19.2.4) redocusaurus: specifier: ^2.5.0 - version: 2.5.0(@docusaurus/theme-common@3.9.2(@docusaurus/plugin-content-docs@3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3))(@rspack/core@1.6.7)(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3))(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(@docusaurus/utils@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(core-js@3.47.0)(mobx@6.15.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(styled-components@6.1.19(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(webpack@5.103.0(@swc/core@1.15.4)) + version: 2.5.0(@docusaurus/theme-common@3.9.2(@docusaurus/plugin-content-docs@3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.4))(@rspack/core@1.7.6)(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@docusaurus/utils@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(core-js@3.48.0)(mobx@6.15.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(styled-components@6.3.11(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(webpack@5.105.2(@swc/core@1.15.11)) devDependencies: '@docusaurus/module-type-aliases': - specifier: ^3.9.1 - version: 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + specifier: ^3.9.2 + version: 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@docusaurus/tsconfig': specifier: 3.9.2 version: 3.9.2 '@docusaurus/types': - specifier: ^3.9.1 - version: 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + specifier: ^3.9.2 + version: 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@ianvs/prettier-plugin-sort-imports': specifier: ^4.7.0 - version: 4.7.0(prettier@3.7.4) + version: 4.7.1(prettier@3.8.1) '@types/node': - specifier: ^24.0.0 - version: 24.10.4 + specifier: ^25.1.0 + version: 25.3.0 '@types/react': - specifier: ^19.2.0 - version: 19.2.7 + specifier: ^19.2.10 + version: 19.2.14 '@types/react-helmet': specifier: ^6.1.11 version: 6.1.11 @@ -67,8 +70,8 @@ importers: specifier: ^5.3.3 version: 5.3.3 prettier: - specifier: ^3.6.2 - version: 3.7.4 + specifier: ^3.8.1 + version: 3.8.1 typescript: specifier: ^5.9.3 version: 5.9.3 @@ -76,45 +79,45 @@ importers: plugins/woodpecker-plugins: dependencies: fuse.js: - specifier: ^7.0.0 + specifier: ^7.1.0 version: 7.1.0 react: specifier: ^17.0.2 || ^18.0.0 || ^19.0.0 - version: 19.2.3 + version: 19.2.4 react-dom: specifier: ^17.0.2 || ^18.0.0 || ^19.0.0 - version: 19.2.3(react@19.2.3) + version: 19.2.4(react@19.2.4) yaml: - specifier: ^2.7.0 + specifier: ^2.8.2 version: 2.8.2 devDependencies: '@docusaurus/module-type-aliases': - specifier: ^3.7.0 - version: 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + specifier: ^3.9.2 + version: 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@docusaurus/theme-classic': - specifier: ^3.7.0 - version: 3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@rspack/core@1.6.7)(@swc/core@1.15.4)(@types/react@19.2.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3) + specifier: ^3.9.2 + version: 3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@rspack/core@1.7.6)(@swc/core@1.15.11)(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) '@docusaurus/types': - specifier: ^3.7.0 - version: 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + specifier: ^3.9.2 + version: 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@tsconfig/docusaurus': - specifier: ^2.0.3 - version: 2.0.7 + specifier: ^2.0.7 + version: 2.0.9 '@types/node': - specifier: ^24.0.0 - version: 24.10.4 + specifier: ^24.10.9 + version: 24.10.13 axios: - specifier: ^1.7.9 - version: 1.13.2 + specifier: ^1.13.4 + version: 1.13.5 concurrently: - specifier: ^9.1.2 + specifier: ^9.2.1 version: 9.2.1 isomorphic-dompurify: - specifier: ^2.19.0 - version: 2.34.0(postcss@8.5.6) + specifier: ^3.0.0 + version: 3.0.0 marked: - specifier: ^17.0.0 - version: 17.0.1 + specifier: ^17.0.1 + version: 17.0.3 slugify: specifier: ^1.6.6 version: 1.6.6 @@ -122,42 +125,16 @@ importers: specifier: ^2.8.1 version: 2.8.1 typescript: - specifier: ^5.7.2 + specifier: ^5.9.3 version: 5.9.3 packages: - '@acemir/cssom@0.9.29': - resolution: {integrity: sha512-G90x0VW+9nW4dFajtjCoT+NM0scAfH9Mb08IcjgFHYbfiL/lU04dTF9JuVOi3/OH+DJCQdcIseSXkdCB9Ky6JA==} + '@acemir/cssom@0.9.31': + resolution: {integrity: sha512-ZnR3GSaH+/vJ0YlHau21FjfLYjMpYVIzTD8M8vIEQvIGxeOXyXdzCI140rrCY862p/C/BbzWsjc1dgnM9mkoTA==} - '@ai-sdk/gateway@2.0.21': - resolution: {integrity: sha512-BwV7DU/lAm3Xn6iyyvZdWgVxgLu3SNXzl5y57gMvkW4nGhAOV5269IrJzQwGt03bb107sa6H6uJwWxc77zXoGA==} - engines: {node: '>=18'} - peerDependencies: - zod: ^3.25.76 || ^4.1.8 - - '@ai-sdk/provider-utils@3.0.19': - resolution: {integrity: sha512-W41Wc9/jbUVXVwCN/7bWa4IKe8MtxO3EyA0Hfhx6grnmiYlCvpI8neSYWFE0zScXJkgA/YK3BRybzgyiXuu6JA==} - engines: {node: '>=18'} - peerDependencies: - zod: ^3.25.76 || ^4.1.8 - - '@ai-sdk/provider@2.0.0': - resolution: {integrity: sha512-6o7Y2SeO9vFKB8lArHXehNuusnpddKPk7xqL7T2/b+OvXMRIXUO1rR4wcv1hAFUAT9avGZshty3Wlua/XA7TvA==} - engines: {node: '>=18'} - - '@ai-sdk/react@2.0.115': - resolution: {integrity: sha512-Etu7gWSEi2dmXss1PoR5CAZGwGShXsF9+Pon1eRO6EmatjYaBMhq1CfHPyYhGzWrint8jJIK2VaAhiMef29qZw==} - engines: {node: '>=18'} - peerDependencies: - react: ^18 || ~19.0.1 || ~19.1.2 || ^19.2.1 - zod: ^3.25.76 || ^4.1.8 - peerDependenciesMeta: - zod: - optional: true - - '@algolia/abtesting@1.12.0': - resolution: {integrity: sha512-EfW0bfxjPs+C7ANkJDw2TATntfBKsFiy7APh+KO0pQ8A6HYa5I0NjFuCGCXWfzzzLXNZta3QUl3n5Kmm6aJo9Q==} + '@algolia/abtesting@1.15.0': + resolution: {integrity: sha512-D1QZ8dQx5zC9yrxNao9ER9bojmmzUdL1i2P9waIRiwnZ5fI26YswcCd6VHR/Q4W3PASfVf2My4YQ2FhGGDewTQ==} engines: {node: '>= 14.0.0'} '@algolia/autocomplete-core@1.19.2': @@ -174,96 +151,97 @@ packages: '@algolia/client-search': '>= 4.9.1 < 6' algoliasearch: '>= 4.9.1 < 6' - '@algolia/client-abtesting@5.46.0': - resolution: {integrity: sha512-eG5xV8rujK4ZIHXrRshvv9O13NmU/k42Rnd3w43iKH5RaQ2zWuZO6Q7XjaoJjAFVCsJWqRbXzbYyPGrbF3wGNg==} + '@algolia/client-abtesting@5.49.0': + resolution: {integrity: sha512-Q1MSRhh4Du9WeLIl1S9O+BDUMaL01uuQtmzCyEzOBtu1xBDr3wvqrTJtfEceEkA5/Nw1BdGSHa6sDT3xTAF90A==} engines: {node: '>= 14.0.0'} - '@algolia/client-analytics@5.46.0': - resolution: {integrity: sha512-AYh2uL8IUW9eZrbbT+wZElyb7QkkeV3US2NEKY7doqMlyPWE8lErNfkVN1NvZdVcY4/SVic5GDbeDz2ft8YIiQ==} + '@algolia/client-analytics@5.49.0': + resolution: {integrity: sha512-v50elhC80oyQw+8o8BwM+VvPuOo36+3W8VCfR4hsHoafQtGbMtP63U5eNcUydbVsM0py3JLoBaL1yKBK4L01sg==} engines: {node: '>= 14.0.0'} - '@algolia/client-common@5.46.0': - resolution: {integrity: sha512-0emZTaYOeI9WzJi0TcNd2k3SxiN6DZfdWc2x2gHt855Jl9jPUOzfVTL6gTvCCrOlT4McvpDGg5nGO+9doEjjig==} + '@algolia/client-common@5.49.0': + resolution: {integrity: sha512-BDmVDtpDvymfLE5YQ2cPnfWJUVTDJqwpJa03Fsb7yJFJmbeKsUOGsnRkYsTbdzf0FfcvyvBB5zdcbrAIL249bg==} engines: {node: '>= 14.0.0'} - '@algolia/client-insights@5.46.0': - resolution: {integrity: sha512-wrBJ8fE+M0TDG1As4DDmwPn2TXajrvmvAN72Qwpuv8e2JOKNohF7+JxBoF70ZLlvP1A1EiH8DBu+JpfhBbNphQ==} + '@algolia/client-insights@5.49.0': + resolution: {integrity: sha512-lDCXsnZDx7zQ5GzSi1EL3l07EbksjrdpMgixFRCdi2QqeBe42HIQJfPPqdWtwrAXjORRopsPx2z+gGYJP/79Uw==} engines: {node: '>= 14.0.0'} - '@algolia/client-personalization@5.46.0': - resolution: {integrity: sha512-LnkeX4p0ENt0DoftDJJDzQQJig/sFQmD1eQifl/iSjhUOGUIKC/7VTeXRcKtQB78naS8njUAwpzFvxy1CDDXDQ==} + '@algolia/client-personalization@5.49.0': + resolution: {integrity: sha512-5k/KB+DsnesNKvMUEwTKSzExOf5zYbiPg7DVO7g1Y/+bhMb3wmxp9RFwfqwPfmoRTjptqvwhR6a0593tWVkmAw==} engines: {node: '>= 14.0.0'} - '@algolia/client-query-suggestions@5.46.0': - resolution: {integrity: sha512-aF9tc4ex/smypXw+W3lBPB1jjKoaGHpZezTqofvDOI/oK1dR2sdTpFpK2Ru+7IRzYgwtRqHF3znmTlyoNs9dpA==} + '@algolia/client-query-suggestions@5.49.0': + resolution: {integrity: sha512-pjHNcrdjn7p3RQ5Ql1Baiwfdn9bkS+z4gqONJJP8kuZFqYP8Olthy4G7fl5bCB29UjdUj5EWlaElQKCtPluCtQ==} engines: {node: '>= 14.0.0'} - '@algolia/client-search@5.46.0': - resolution: {integrity: sha512-22SHEEVNjZfFWkFks3P6HilkR3rS7a6GjnCIqR22Zz4HNxdfT0FG+RE7efTcFVfLUkTTMQQybvaUcwMrHXYa7Q==} + '@algolia/client-search@5.49.0': + resolution: {integrity: sha512-uGv2P3lcviuaZy8ZOAyN60cZdhOVyjXwaDC27a1qdp3Pb5Azn+lLSJwkHU4TNRpphHmIei9HZuUxwQroujdPjw==} engines: {node: '>= 14.0.0'} '@algolia/events@4.0.1': resolution: {integrity: sha512-FQzvOCgoFXAbf5Y6mYozw2aj5KCJoA3m4heImceldzPSMbdyS4atVjJzXKMsfX3wnZTFYwkkt8/z8UesLHlSBQ==} - '@algolia/ingestion@1.46.0': - resolution: {integrity: sha512-2LT0/Z+/sFwEpZLH6V17WSZ81JX2uPjgvv5eNlxgU7rPyup4NXXfuMbtCJ+6uc4RO/LQpEJd3Li59ke3wtyAsA==} + '@algolia/ingestion@1.49.0': + resolution: {integrity: sha512-sH10mftYlmvfGbvAgTtHYbCIstmNUdiAkX//0NAyBcJRB6NnZmNsdLxdFGbE8ZqlGXzoe0zcUIau+DxKpXtqCw==} engines: {node: '>= 14.0.0'} - '@algolia/monitoring@1.46.0': - resolution: {integrity: sha512-uivZ9wSWZ8mz2ZU0dgDvQwvVZV8XBv6lYBXf8UtkQF3u7WeTqBPeU8ZoeTyLpf0jAXCYOvc1mAVmK0xPLuEwOQ==} + '@algolia/monitoring@1.49.0': + resolution: {integrity: sha512-RqhGcVVxLpK+lA0GZKywlQIXsI704flc12nv/hOdrwiuk/Uyhxs46KLM4ngip7wutU+7t0PYZWiVayrqBPN/ZQ==} engines: {node: '>= 14.0.0'} - '@algolia/recommend@5.46.0': - resolution: {integrity: sha512-O2BB8DuySuddgOAbhyH4jsGbL+KyDGpzJRtkDZkv091OMomqIA78emhhMhX9d/nIRrzS1wNLWB/ix7Hb2eV5rg==} + '@algolia/recommend@5.49.0': + resolution: {integrity: sha512-kg8omGRvmIPhhqtUqSIpS3regFKWuoWh3WqyUhGk27N4T7q8I++8TsDYsV8vK7oBEzw706m2vUBtN5fw2fDjmw==} engines: {node: '>= 14.0.0'} - '@algolia/requester-browser-xhr@5.46.0': - resolution: {integrity: sha512-eW6xyHCyYrJD0Kjk9Mz33gQ40LfWiEA51JJTVfJy3yeoRSw/NXhAL81Pljpa0qslTs6+LO/5DYPZddct6HvISQ==} + '@algolia/requester-browser-xhr@5.49.0': + resolution: {integrity: sha512-BaZ6NTI9VdSbDcsMucdKhTuFFxv6B+3dAZZBozX12fKopYsELh7dBLfZwm8evDCIicmNjIjobi4VNnNshrCSuw==} engines: {node: '>= 14.0.0'} - '@algolia/requester-fetch@5.46.0': - resolution: {integrity: sha512-Vn2+TukMGHy4PIxmdvP667tN/MhS7MPT8EEvEhS6JyFLPx3weLcxSa1F9gVvrfHWCUJhLWoMVJVB2PT8YfRGcw==} + '@algolia/requester-fetch@5.49.0': + resolution: {integrity: sha512-2nxISxS5xO5DLAj6QzMImgJv6CqpZhJVkhcTFULESR/k4IpbkJTEHmViVTxw9MlrU8B5GfwHevFd7vKL3a7MXQ==} engines: {node: '>= 14.0.0'} - '@algolia/requester-node-http@5.46.0': - resolution: {integrity: sha512-xaqXyna5yBZ+r1SJ9my/DM6vfTqJg9FJgVydRJ0lnO+D5NhqGW/qaRG/iBGKr/d4fho34el6WakV7BqJvrl/HQ==} + '@algolia/requester-node-http@5.49.0': + resolution: {integrity: sha512-S/B94C6piEUXGpN3y5ysmNKMEqdfNVAXYY+FxivEAV5IGJjbEuLZfT8zPPZUWGw9vh6lgP80Hye2G5aVBNIa8Q==} engines: {node: '>= 14.0.0'} - '@asamuzakjp/css-color@4.1.0': - resolution: {integrity: sha512-9xiBAtLn4aNsa4mDnpovJvBn72tNEIACyvlqaNJ+ADemR+yeMJWnBudOi2qGDviJa7SwcDOU/TRh5dnET7qk0w==} + '@asamuzakjp/css-color@5.0.0': + resolution: {integrity: sha512-SYGMdSLugOBvpa6ciOp9DptcoyluCo0IJln5v47NtadGbSfkhvANzFozKNsuJ0A7ElOuXeIVQcPAd0TMQ1ZCkg==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} - '@asamuzakjp/dom-selector@6.7.6': - resolution: {integrity: sha512-hBaJER6A9MpdG3WgdlOolHmbOYvSk46y7IQN/1+iqiCuUu6iWdQrs9DGKF8ocqsEqWujWf/V7b7vaDgiUmIvUg==} + '@asamuzakjp/dom-selector@6.8.1': + resolution: {integrity: sha512-MvRz1nCqW0fsy8Qz4dnLIvhOlMzqDVBabZx6lH+YywFDdjXhMY37SmpV1XFX3JzG5GWHn63j6HX6QPr3lZXHvQ==} '@asamuzakjp/nwsapi@2.3.9': resolution: {integrity: sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==} - '@babel/code-frame@7.27.1': - resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} + '@babel/code-frame@7.29.0': + resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} engines: {node: '>=6.9.0'} - '@babel/compat-data@7.28.5': - resolution: {integrity: sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==} + '@babel/compat-data@7.29.0': + resolution: {integrity: sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==} engines: {node: '>=6.9.0'} - '@babel/core@7.28.5': - resolution: {integrity: sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==} + '@babel/core@7.29.0': + resolution: {integrity: sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==} engines: {node: '>=6.9.0'} - '@babel/generator@7.28.5': - resolution: {integrity: sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==} + '@babel/generator@7.29.1': + resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==} engines: {node: '>=6.9.0'} '@babel/helper-annotate-as-pure@7.27.3': resolution: {integrity: sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==} engines: {node: '>=6.9.0'} - '@babel/helper-compilation-targets@7.27.2': - resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==} + '@babel/helper-compilation-targets@7.28.6': + resolution: {integrity: sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==} engines: {node: '>=6.9.0'} - '@babel/helper-create-class-features-plugin@7.28.5': - resolution: {integrity: sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ==} + '@babel/helper-create-class-features-plugin@7.28.6': + resolution: {integrity: sha512-dTOdvsjnG3xNT9Y0AUg1wAl38y+4Rl4sf9caSQZOXdNqVn+H+HbbJ4IyyHaIqNR6SW9oJpA/RuRjsjCw2IdIow==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 @@ -274,8 +252,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0 - '@babel/helper-define-polyfill-provider@0.6.5': - resolution: {integrity: sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg==} + '@babel/helper-define-polyfill-provider@0.6.6': + resolution: {integrity: sha512-mOAsxeeKkUKayvZR3HeTYD/fICpCPLJrU5ZjelT/PA6WHtNDBOE436YiaEUvHN454bRM3CebhDsIpieCc4texA==} peerDependencies: '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 @@ -287,12 +265,12 @@ packages: resolution: {integrity: sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==} engines: {node: '>=6.9.0'} - '@babel/helper-module-imports@7.27.1': - resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==} + '@babel/helper-module-imports@7.28.6': + resolution: {integrity: sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==} engines: {node: '>=6.9.0'} - '@babel/helper-module-transforms@7.28.3': - resolution: {integrity: sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==} + '@babel/helper-module-transforms@7.28.6': + resolution: {integrity: sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 @@ -301,8 +279,8 @@ packages: resolution: {integrity: sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==} engines: {node: '>=6.9.0'} - '@babel/helper-plugin-utils@7.27.1': - resolution: {integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==} + '@babel/helper-plugin-utils@7.28.6': + resolution: {integrity: sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==} engines: {node: '>=6.9.0'} '@babel/helper-remap-async-to-generator@7.27.1': @@ -311,8 +289,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0 - '@babel/helper-replace-supers@7.27.1': - resolution: {integrity: sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==} + '@babel/helper-replace-supers@7.28.6': + resolution: {integrity: sha512-mq8e+laIk94/yFec3DxSjCRD2Z0TAjhVbEJY3UQrlwVo15Lmt7C2wAUbK4bjnTs4APkwsYLTahXRraQXhb1WCg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 @@ -333,16 +311,16 @@ packages: resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} engines: {node: '>=6.9.0'} - '@babel/helper-wrap-function@7.28.3': - resolution: {integrity: sha512-zdf983tNfLZFletc0RRXYrHrucBEg95NIFMkn6K9dbeMYnsgHaSBGcQqdsCSStG2PYwRre0Qc2NNSCXbG+xc6g==} + '@babel/helper-wrap-function@7.28.6': + resolution: {integrity: sha512-z+PwLziMNBeSQJonizz2AGnndLsP2DeGHIxDAn+wdHOGuo4Fo1x1HBPPXeE9TAOPHNNWQKCSlA2VZyYyyibDnQ==} engines: {node: '>=6.9.0'} - '@babel/helpers@7.28.4': - resolution: {integrity: sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==} + '@babel/helpers@7.28.6': + resolution: {integrity: sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==} engines: {node: '>=6.9.0'} - '@babel/parser@7.28.5': - resolution: {integrity: sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==} + '@babel/parser@7.29.0': + resolution: {integrity: sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==} engines: {node: '>=6.0.0'} hasBin: true @@ -370,8 +348,8 @@ packages: peerDependencies: '@babel/core': ^7.13.0 - '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.28.3': - resolution: {integrity: sha512-b6YTX108evsvE4YgWyQ921ZAFFQm3Bn+CA3+ZXlNVnPhx+UfsVURoPjfGAPCjBgrqo30yX/C2nZGX96DxvR9Iw==} + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.28.6': + resolution: {integrity: sha512-a0aBScVTlNaiUe35UtfxAN7A/tehvvG4/ByO6+46VPKTRSlfnAFsgKy0FUh+qAkQrDTmhDkT+IBOKlOoMUxQ0g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 @@ -387,26 +365,26 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-import-assertions@7.27.1': - resolution: {integrity: sha512-UT/Jrhw57xg4ILHLFnzFpPDlMbcdEicaAtjPQpbj9wa8T4r5KVWCimHcL/460g8Ht0DMxDyjsLgiWSkVjnwPFg==} + '@babel/plugin-syntax-import-assertions@7.28.6': + resolution: {integrity: sha512-pSJUpFHdx9z5nqTSirOCMtYVP2wFgoWhP0p3g8ONK/4IHhLIBd0B9NYqAvIUAhq+OkhO4VM1tENCt0cjlsNShw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-import-attributes@7.27.1': - resolution: {integrity: sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==} + '@babel/plugin-syntax-import-attributes@7.28.6': + resolution: {integrity: sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-jsx@7.27.1': - resolution: {integrity: sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==} + '@babel/plugin-syntax-jsx@7.28.6': + resolution: {integrity: sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-typescript@7.27.1': - resolution: {integrity: sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==} + '@babel/plugin-syntax-typescript@7.28.6': + resolution: {integrity: sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -423,14 +401,14 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-async-generator-functions@7.28.0': - resolution: {integrity: sha512-BEOdvX4+M765icNPZeidyADIvQ1m1gmunXufXxvRESy/jNNyfovIqUyE7MVgGBjWktCoJlzvFA1To2O4ymIO3Q==} + '@babel/plugin-transform-async-generator-functions@7.29.0': + resolution: {integrity: sha512-va0VdWro4zlBr2JsXC+ofCPB2iG12wPtVGTWFx2WLDOM3nYQZZIGP82qku2eW/JR83sD+k2k+CsNtyEbUqhU6w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-async-to-generator@7.27.1': - resolution: {integrity: sha512-NREkZsZVJS4xmTr8qzE5y8AfIPqsdQfRuUiLRTEzb7Qii8iFWCyDKaUV2c0rCuh4ljDZ98ALHP/PetiBV2nddA==} + '@babel/plugin-transform-async-to-generator@7.28.6': + resolution: {integrity: sha512-ilTRcmbuXjsMmcZ3HASTe4caH5Tpo93PkTxF9oG2VZsSWsahydmcEHhix9Ik122RcTnZnUzPbmux4wh1swfv7g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -441,32 +419,32 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-block-scoping@7.28.5': - resolution: {integrity: sha512-45DmULpySVvmq9Pj3X9B+62Xe+DJGov27QravQJU1LLcapR6/10i+gYVAucGGJpHBp5mYxIMK4nDAT/QDLr47g==} + '@babel/plugin-transform-block-scoping@7.28.6': + resolution: {integrity: sha512-tt/7wOtBmwHPNMPu7ax4pdPz6shjFrmHDghvNC+FG9Qvj7D6mJcoRQIF5dy4njmxR941l6rgtvfSB2zX3VlUIw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-class-properties@7.27.1': - resolution: {integrity: sha512-D0VcalChDMtuRvJIu3U/fwWjf8ZMykz5iZsg77Nuj821vCKI3zCyRLwRdWbsuJ/uRwZhZ002QtCqIkwC/ZkvbA==} + '@babel/plugin-transform-class-properties@7.28.6': + resolution: {integrity: sha512-dY2wS3I2G7D697VHndN91TJr8/AAfXQNt5ynCTI/MpxMsSzHp+52uNivYT5wCPax3whc47DR8Ba7cmlQMg24bw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-class-static-block@7.28.3': - resolution: {integrity: sha512-LtPXlBbRoc4Njl/oh1CeD/3jC+atytbnf/UqLoqTDcEYGUPj022+rvfkbDYieUrSj3CaV4yHDByPE+T2HwfsJg==} + '@babel/plugin-transform-class-static-block@7.28.6': + resolution: {integrity: sha512-rfQ++ghVwTWTqQ7w8qyDxL1XGihjBss4CmTgGRCTAC9RIbhVpyp4fOeZtta0Lbf+dTNIVJer6ych2ibHwkZqsQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.12.0 - '@babel/plugin-transform-classes@7.28.4': - resolution: {integrity: sha512-cFOlhIYPBv/iBoc+KS3M6et2XPtbT2HiCRfBXWtfpc9OAyostldxIf9YAYB6ypURBBbx+Qv6nyrLzASfJe+hBA==} + '@babel/plugin-transform-classes@7.28.6': + resolution: {integrity: sha512-EF5KONAqC5zAqT783iMGuM2ZtmEBy+mJMOKl2BCvPZ2lVrwvXnB6o+OBWCS+CoeCCpVRF2sA2RBKUxvT8tQT5Q==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-computed-properties@7.27.1': - resolution: {integrity: sha512-lj9PGWvMTVksbWiDT2tW68zGS/cyo4AkZ/QTp0sQT0mjPopCmrSkzxeXkznjqBxzDI6TclZhOJbBmbBLjuOZUw==} + '@babel/plugin-transform-computed-properties@7.28.6': + resolution: {integrity: sha512-bcc3k0ijhHbc2lEfpFHgx7eYw9KNXqOerKWfzbxEHUGKnS3sz9C4CNL9OiFN1297bDNfUiSO7DaLzbvHQQQ1BQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -477,8 +455,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-dotall-regex@7.27.1': - resolution: {integrity: sha512-gEbkDVGRvjj7+T1ivxrfgygpT7GUd4vmODtYpbs0gZATdkX8/iSnOtZSxiZnsgm1YjTgjI6VKBGSJJevkrclzw==} + '@babel/plugin-transform-dotall-regex@7.28.6': + resolution: {integrity: sha512-SljjowuNKB7q5Oayv4FoPzeB74g3QgLt8IVJw9ADvWy3QnUb/01aw8I4AVv8wYnPvQz2GDDZ/g3GhcNyDBI4Bg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -489,8 +467,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.27.1': - resolution: {integrity: sha512-hkGcueTEzuhB30B3eJCbCYeCaaEQOmQR0AdvzpD4LoN0GXMWzzGSuRrxR2xTnCrvNbVwK9N6/jQ92GSLfiZWoQ==} + '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.29.0': + resolution: {integrity: sha512-zBPcW2lFGxdiD8PUnPwJjag2J9otbcLQzvbiOzDxpYXyCuYX9agOwMPGn1prVH0a4qzhCKu24rlH4c1f7yA8rw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 @@ -501,14 +479,14 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-explicit-resource-management@7.28.0': - resolution: {integrity: sha512-K8nhUcn3f6iB+P3gwCv/no7OdzOZQcKchW6N389V6PD8NUWKZHzndOd9sPDVbMoBsbmjMqlB4L9fm+fEFNVlwQ==} + '@babel/plugin-transform-explicit-resource-management@7.28.6': + resolution: {integrity: sha512-Iao5Konzx2b6g7EPqTy40UZbcdXE126tTxVFr/nAIj+WItNxjKSYTEw3RC+A2/ZetmdJsgueL1KhaMCQHkLPIg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-exponentiation-operator@7.28.5': - resolution: {integrity: sha512-D4WIMaFtwa2NizOp+dnoFjRez/ClKiC2BqqImwKd1X28nqBtZEyCYJ2ozQrrzlxAFrcrjxo39S6khe9RNDlGzw==} + '@babel/plugin-transform-exponentiation-operator@7.28.6': + resolution: {integrity: sha512-WitabqiGjV/vJ0aPOLSFfNY1u9U3R7W36B03r5I2KoNix+a3sOhJ3pKFB3R5It9/UiK78NiO0KE9P21cMhlPkw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -531,8 +509,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-json-strings@7.27.1': - resolution: {integrity: sha512-6WVLVJiTjqcQauBhn1LkICsR2H+zm62I3h9faTDKt1qP4jn2o72tSvqMwtGFKGTpojce0gJs+76eZ2uCHRZh0Q==} + '@babel/plugin-transform-json-strings@7.28.6': + resolution: {integrity: sha512-Nr+hEN+0geQkzhbdgQVPoqr47lZbm+5fCUmO70722xJZd0Mvb59+33QLImGj6F+DkK3xgDi1YVysP8whD6FQAw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -543,8 +521,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-logical-assignment-operators@7.28.5': - resolution: {integrity: sha512-axUuqnUTBuXyHGcJEVVh9pORaN6wC5bYfE7FGzPiaWa3syib9m7g+/IT/4VgCOe2Upef43PHzeAvcrVek6QuuA==} + '@babel/plugin-transform-logical-assignment-operators@7.28.6': + resolution: {integrity: sha512-+anKKair6gpi8VsM/95kmomGNMD0eLz1NQ8+Pfw5sAwWH9fGYXT50E55ZpV0pHUHWf6IUTWPM+f/7AAff+wr9A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -561,14 +539,14 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-modules-commonjs@7.27.1': - resolution: {integrity: sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw==} + '@babel/plugin-transform-modules-commonjs@7.28.6': + resolution: {integrity: sha512-jppVbf8IV9iWWwWTQIxJMAJCWBuuKx71475wHwYytrRGQ2CWiDvYlADQno3tcYpS/T2UUWFQp3nVtYfK/YBQrA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-modules-systemjs@7.28.5': - resolution: {integrity: sha512-vn5Jma98LCOeBy/KpeQhXcV2WZgaRUtjwQmjoBuLNlOmkg0fB5pdvYVeWRYI69wWKwK2cD1QbMiUQnoujWvrew==} + '@babel/plugin-transform-modules-systemjs@7.29.0': + resolution: {integrity: sha512-PrujnVFbOdUpw4UHiVwKvKRLMMic8+eC0CuNlxjsyZUiBjhFdPsewdXCkveh2KqBA9/waD0W1b4hXSOBQJezpQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -579,8 +557,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-named-capturing-groups-regex@7.27.1': - resolution: {integrity: sha512-SstR5JYy8ddZvD6MhV0tM/j16Qds4mIpJTOd1Yu9J9pJjH93bxHECF7pgtc28XvkzTD6Pxcm/0Z73Hvk7kb3Ng==} + '@babel/plugin-transform-named-capturing-groups-regex@7.29.0': + resolution: {integrity: sha512-1CZQA5KNAD6ZYQLPw7oi5ewtDNxH/2vuCh+6SmvgDfhumForvs8a1o9n0UrEoBD8HU4djO2yWngTQlXl1NDVEQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 @@ -591,20 +569,20 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-nullish-coalescing-operator@7.27.1': - resolution: {integrity: sha512-aGZh6xMo6q9vq1JGcw58lZ1Z0+i0xB2x0XaauNIUXd6O1xXc3RwoWEBlsTQrY4KQ9Jf0s5rgD6SiNkaUdJegTA==} + '@babel/plugin-transform-nullish-coalescing-operator@7.28.6': + resolution: {integrity: sha512-3wKbRgmzYbw24mDJXT7N+ADXw8BC/imU9yo9c9X9NKaLF1fW+e5H1U5QjMUBe4Qo4Ox/o++IyUkl1sVCLgevKg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-numeric-separator@7.27.1': - resolution: {integrity: sha512-fdPKAcujuvEChxDBJ5c+0BTaS6revLV7CJL08e4m3de8qJfNIuCc2nc7XJYOjBoTMJeqSmwXJ0ypE14RCjLwaw==} + '@babel/plugin-transform-numeric-separator@7.28.6': + resolution: {integrity: sha512-SJR8hPynj8outz+SlStQSwvziMN4+Bq99it4tMIf5/Caq+3iOc0JtKyse8puvyXkk3eFRIA5ID/XfunGgO5i6w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-object-rest-spread@7.28.4': - resolution: {integrity: sha512-373KA2HQzKhQCYiRVIRr+3MjpCObqzDlyrM6u4I201wL8Mp2wHf7uB8GhDwis03k2ti8Zr65Zyyqs1xOxUF/Ew==} + '@babel/plugin-transform-object-rest-spread@7.28.6': + resolution: {integrity: sha512-5rh+JR4JBC4pGkXLAcYdLHZjXudVxWMXbB6u6+E9lRL5TrGVbHt1TjxGbZ8CkmYw9zjkB7jutzOROArsqtncEA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -615,14 +593,14 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-optional-catch-binding@7.27.1': - resolution: {integrity: sha512-txEAEKzYrHEX4xSZN4kJ+OfKXFVSWKB2ZxM9dpcE3wT7smwkNmXo5ORRlVzMVdJbD+Q8ILTgSD7959uj+3Dm3Q==} + '@babel/plugin-transform-optional-catch-binding@7.28.6': + resolution: {integrity: sha512-R8ja/Pyrv0OGAvAXQhSTmWyPJPml+0TMqXlO5w+AsMEiwb2fg3WkOvob7UxFSL3OIttFSGSRFKQsOhJ/X6HQdQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-optional-chaining@7.28.5': - resolution: {integrity: sha512-N6fut9IZlPnjPwgiQkXNhb+cT8wQKFlJNqcZkWlcTqkcqx6/kU4ynGmLFoa4LViBSirn05YAwk+sQBbPfxtYzQ==} + '@babel/plugin-transform-optional-chaining@7.28.6': + resolution: {integrity: sha512-A4zobikRGJTsX9uqVFdafzGkqD30t26ck2LmOzAuLL8b2x6k3TIqRiT2xVvA9fNmFeTX484VpsdgmKNA0bS23w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -633,14 +611,14 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-private-methods@7.27.1': - resolution: {integrity: sha512-10FVt+X55AjRAYI9BrdISN9/AQWHqldOeZDUoLyif1Kn05a56xVBXb8ZouL8pZ9jem8QpXaOt8TS7RHUIS+GPA==} + '@babel/plugin-transform-private-methods@7.28.6': + resolution: {integrity: sha512-piiuapX9CRv7+0st8lmuUlRSmX6mBcVeNQ1b4AYzJxfCMuBfB0vBXDiGSmm03pKJw1v6cZ8KSeM+oUnM6yAExg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-private-property-in-object@7.27.1': - resolution: {integrity: sha512-5J+IhqTi1XPa0DXF83jYOaARrX+41gOewWbkPyjMNRDqgOCqdffGh8L3f/Ek5utaEBZExjSAzcyjmV9SSAWObQ==} + '@babel/plugin-transform-private-property-in-object@7.28.6': + resolution: {integrity: sha512-b97jvNSOb5+ehyQmBpmhOCiUC5oVK4PMnpRvO7+ymFBoqYjeDHIU9jnrNUuwHOiL9RpGDoKBpSViarV+BU+eVA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -669,8 +647,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-react-jsx@7.27.1': - resolution: {integrity: sha512-2KH4LWGSrJIkVf5tSiBFYuXDAoWRq2MMwgivCf+93dd0GQi8RXLjKA/0EvRnVV5G0hrHczsquXuD01L8s6dmBw==} + '@babel/plugin-transform-react-jsx@7.28.6': + resolution: {integrity: sha512-61bxqhiRfAACulXSLd/GxqmAedUSrRZIu/cbaT18T1CetkTmtDN15it7i80ru4DVqRK1WMxQhXs+Lf9kajm5Ow==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -681,14 +659,14 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-regenerator@7.28.4': - resolution: {integrity: sha512-+ZEdQlBoRg9m2NnzvEeLgtvBMO4tkFBw5SQIUgLICgTrumLoU7lr+Oghi6km2PFj+dbUt2u1oby2w3BDO9YQnA==} + '@babel/plugin-transform-regenerator@7.29.0': + resolution: {integrity: sha512-FijqlqMA7DmRdg/aINBSs04y8XNTYw/lr1gJ2WsmBnnaNw1iS43EPkJW+zK7z65auG3AWRFXWj+NcTQwYptUog==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-regexp-modifiers@7.27.1': - resolution: {integrity: sha512-TtEciroaiODtXvLZv4rmfMhkCv8jx3wgKpL68PuiPh2M4fvz5jhsA7697N1gMvkvr/JTF13DrFYyEbY9U7cVPA==} + '@babel/plugin-transform-regexp-modifiers@7.28.6': + resolution: {integrity: sha512-QGWAepm9qxpaIs7UM9FvUSnCGlb8Ua1RhyM4/veAxLwt3gMat/LSGrZixyuj4I6+Kn9iwvqCyPTtbdxanYoWYg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 @@ -699,8 +677,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-runtime@7.28.5': - resolution: {integrity: sha512-20NUVgOrinudkIBzQ2bNxP08YpKprUkRTiRSd2/Z5GOdPImJGkoN4Z7IQe1T5AdyKI1i5L6RBmluqdSzvaq9/w==} + '@babel/plugin-transform-runtime@7.29.0': + resolution: {integrity: sha512-jlaRT5dJtMaMCV6fAuLbsQMSwz/QkvaHOHOSXRitGGwSpR1blCY4KUKoyP2tYO8vJcqYe8cEj96cqSztv3uF9w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -711,8 +689,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-spread@7.27.1': - resolution: {integrity: sha512-kpb3HUqaILBJcRFVhFUs6Trdd4mkrzcGXss+6/mxUd273PfbWqSDHRzMT2234gIg2QYfAjvXLSquP1xECSg09Q==} + '@babel/plugin-transform-spread@7.28.6': + resolution: {integrity: sha512-9U4QObUC0FtJl05AsUcodau/RWDytrU6uKgkxu09mLR9HLDAtUMoPuuskm5huQsoktmsYpI+bGmq+iapDcriKA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -735,8 +713,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-typescript@7.28.5': - resolution: {integrity: sha512-x2Qa+v/CuEoX7Dr31iAfr0IhInrVOWZU/2vJMJ00FOR/2nM0BcBEclpaf9sWCDc+v5e9dMrhSH8/atq/kX7+bA==} + '@babel/plugin-transform-typescript@7.28.6': + resolution: {integrity: sha512-0YWL2RFxOqEm9Efk5PvreamxPME8OyY0wM5wh5lHjF+VtVhdneCWGzZeSqzOfiobVqQaNCd2z0tQvnI9DaPWPw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -747,8 +725,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-unicode-property-regex@7.27.1': - resolution: {integrity: sha512-uW20S39PnaTImxp39O5qFlHLS9LJEmANjMG7SxIhap8rCHqu0Ik+tLEPX5DKmHn6CsWQ7j3lix2tFOa5YtL12Q==} + '@babel/plugin-transform-unicode-property-regex@7.28.6': + resolution: {integrity: sha512-4Wlbdl/sIZjzi/8St0evF0gEZrgOswVO6aOzqxh1kDZOl9WmLrHq2HtGhnOJZmHZYKP8WZ1MDLCt5DAWwRo57A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -759,14 +737,14 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-unicode-sets-regex@7.27.1': - resolution: {integrity: sha512-EtkOujbc4cgvb0mlpQefi4NTPBzhSIevblFevACNLUspmrALgmEBdL/XfnyyITfd8fKBZrZys92zOWcik7j9Tw==} + '@babel/plugin-transform-unicode-sets-regex@7.28.6': + resolution: {integrity: sha512-/wHc/paTUmsDYN7SZkpWxogTOBNnlx7nBQYfy6JJlCT7G3mVhltk3e++N7zV0XfgGsrqBxd4rJQt9H16I21Y1Q==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/preset-env@7.28.5': - resolution: {integrity: sha512-S36mOoi1Sb6Fz98fBfE+UZSpYw5mJm0NUHtIKrOuNcqeFauy1J6dIvXm2KRVKobOSaGq4t/hBXdN4HGU3wL9Wg==} + '@babel/preset-env@7.29.0': + resolution: {integrity: sha512-fNEdfc0yi16lt6IZo2Qxk3knHVdfMYX33czNb4v8yWhemoBhibCpQK/uYHtSKIiO+p/zd3+8fYVXhQdOVV608w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -788,26 +766,30 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/runtime-corejs3@7.28.4': - resolution: {integrity: sha512-h7iEYiW4HebClDEhtvFObtPmIvrd1SSfpI9EhOeKk4CtIK/ngBWFpuhCzhdmRKtg71ylcue+9I6dv54XYO1epQ==} + '@babel/runtime-corejs3@7.29.0': + resolution: {integrity: sha512-TgUkdp71C9pIbBcHudc+gXZnihEDOjUAmXO1VO4HHGES7QLZcShR0stfKIxLSNIYx2fqhmJChOjm/wkF8wv4gA==} engines: {node: '>=6.9.0'} - '@babel/runtime@7.28.4': - resolution: {integrity: sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==} + '@babel/runtime@7.28.6': + resolution: {integrity: sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==} engines: {node: '>=6.9.0'} - '@babel/template@7.27.2': - resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} + '@babel/template@7.28.6': + resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} engines: {node: '>=6.9.0'} - '@babel/traverse@7.28.5': - resolution: {integrity: sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==} + '@babel/traverse@7.29.0': + resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==} engines: {node: '>=6.9.0'} - '@babel/types@7.28.5': - resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==} + '@babel/types@7.29.0': + resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} engines: {node: '>=6.9.0'} + '@bramus/specificity@2.4.2': + resolution: {integrity: sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==} + hasBin: true + '@colors/colors@1.5.0': resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} engines: {node: '>=0.1.90'} @@ -823,6 +805,10 @@ packages: resolution: {integrity: sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==} engines: {node: '>=18'} + '@csstools/color-helpers@6.0.2': + resolution: {integrity: sha512-LMGQLS9EuADloEFkcTBR3BwV/CGHV7zyDxVRtVDTwdI2Ca4it0CCVTT9wCkxSgokjE5Ho41hEPgb8OEUwoXr6Q==} + engines: {node: '>=20.19.0'} + '@csstools/css-calc@2.1.4': resolution: {integrity: sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==} engines: {node: '>=18'} @@ -830,6 +816,13 @@ packages: '@csstools/css-parser-algorithms': ^3.0.5 '@csstools/css-tokenizer': ^3.0.4 + '@csstools/css-calc@3.1.1': + resolution: {integrity: sha512-HJ26Z/vmsZQqs/o3a6bgKslXGFAungXGbinULZO3eMsOyNJHeBBZfup5FiZInOghgoM4Hwnmw+OgbJCNg1wwUQ==} + engines: {node: '>=20.19.0'} + peerDependencies: + '@csstools/css-parser-algorithms': ^4.0.0 + '@csstools/css-tokenizer': ^4.0.0 + '@csstools/css-color-parser@3.1.0': resolution: {integrity: sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==} engines: {node: '>=18'} @@ -837,22 +830,36 @@ packages: '@csstools/css-parser-algorithms': ^3.0.5 '@csstools/css-tokenizer': ^3.0.4 + '@csstools/css-color-parser@4.0.2': + resolution: {integrity: sha512-0GEfbBLmTFf0dJlpsNU7zwxRIH0/BGEMuXLTCvFYxuL1tNhqzTbtnFICyJLTNK4a+RechKP75e7w42ClXSnJQw==} + engines: {node: '>=20.19.0'} + peerDependencies: + '@csstools/css-parser-algorithms': ^4.0.0 + '@csstools/css-tokenizer': ^4.0.0 + '@csstools/css-parser-algorithms@3.0.5': resolution: {integrity: sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==} engines: {node: '>=18'} peerDependencies: '@csstools/css-tokenizer': ^3.0.4 - '@csstools/css-syntax-patches-for-csstree@1.0.14': - resolution: {integrity: sha512-zSlIxa20WvMojjpCSy8WrNpcZ61RqfTfX3XTaOeVlGJrt/8HF3YbzgFZa01yTbT4GWQLwfTcC3EB8i3XnB647Q==} - engines: {node: '>=18'} + '@csstools/css-parser-algorithms@4.0.0': + resolution: {integrity: sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==} + engines: {node: '>=20.19.0'} peerDependencies: - postcss: ^8.4 + '@csstools/css-tokenizer': ^4.0.0 + + '@csstools/css-syntax-patches-for-csstree@1.0.28': + resolution: {integrity: sha512-1NRf1CUBjnr3K7hu8BLxjQrKCxEe8FP/xmPTenAxCRZWVLbmGotkFvG9mfNpjA6k7Bw1bw4BilZq9cu19RA5pg==} '@csstools/css-tokenizer@3.0.4': resolution: {integrity: sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==} engines: {node: '>=18'} + '@csstools/css-tokenizer@4.0.0': + resolution: {integrity: sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==} + engines: {node: '>=20.19.0'} + '@csstools/media-query-list-parser@4.0.3': resolution: {integrity: sha512-HAYH7d3TLRHDOUQK4mZKf9k9Ph/m8Akstg66ywKR4SFAigjs3yBiUeZtFxywiTm5moZMAp/5W/ZuFnNXXYLuuQ==} engines: {node: '>=18'} @@ -1010,8 +1017,8 @@ packages: peerDependencies: postcss: ^8.4 - '@csstools/postcss-normalize-display-values@4.0.0': - resolution: {integrity: sha512-HlEoG0IDRoHXzXnkV4in47dzsxdsjdz6+j7MLjaACABX2NfvjFS6XVAnpaDyGesz9gK2SC7MbNwdCHusObKJ9Q==} + '@csstools/postcss-normalize-display-values@4.0.1': + resolution: {integrity: sha512-TQUGBuRvxdc7TgNSTevYqrL8oItxiwPDixk20qCB5me/W8uF7BPbhRrAvFuhEoywQp/woRsUZ6SJ+sU5idZAIA==} engines: {node: '>=18'} peerDependencies: postcss: ^8.4 @@ -1034,6 +1041,12 @@ packages: peerDependencies: postcss: ^8.4 + '@csstools/postcss-property-rule-prelude-list@1.0.0': + resolution: {integrity: sha512-IxuQjUXq19fobgmSSvUDO7fVwijDJaZMvWQugxfEUxmjBeDCVaDuMpsZ31MsTm5xbnhA+ElDi0+rQ7sQQGisFA==} + engines: {node: '>=18'} + peerDependencies: + postcss: ^8.4 + '@csstools/postcss-random-function@2.0.1': resolution: {integrity: sha512-q+FQaNiRBhnoSNo+GzqGOIBKoHQ43lYz0ICrV+UudfWnEF6ksS6DsBIJSISKQT2Bvu3g4k6r7t0zYrk5pDlo8w==} engines: {node: '>=18'} @@ -1064,6 +1077,12 @@ packages: peerDependencies: postcss: ^8.4 + '@csstools/postcss-syntax-descriptor-syntax-production@1.0.1': + resolution: {integrity: sha512-GneqQWefjM//f4hJ/Kbox0C6f2T7+pi4/fqTqOFGTL3EjnvOReTqO1qUQ30CaUjkwjYq9qZ41hzarrAxCc4gow==} + engines: {node: '>=18'} + peerDependencies: + postcss: ^8.4 + '@csstools/postcss-system-ui-font-family@1.0.0': resolution: {integrity: sha512-s3xdBvfWYfoPSBsikDXbuorcMG1nN1M6GdU0qBsGfcmNR0A/qhloQZpTxjA3Xsyrk1VJvwb2pOfiOT3at/DuIQ==} engines: {node: '>=18'} @@ -1110,8 +1129,8 @@ packages: resolution: {integrity: sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==} engines: {node: '>=10.0.0'} - '@docsearch/core@4.3.1': - resolution: {integrity: sha512-ktVbkePE+2h9RwqCUMbWXOoebFyDOxHqImAqfs+lC8yOU+XwEW4jgvHGJK079deTeHtdhUNj0PXHSnhJINvHzQ==} + '@docsearch/core@4.6.0': + resolution: {integrity: sha512-IqG3oSd529jVRQ4dWZQKwZwQLVd//bWJTz2HiL0LkiHrI4U/vLrBasKB7lwQB/69nBAcCgs3TmudxTZSLH/ZQg==} peerDependencies: '@types/react': '>= 16.8.0 < 20.0.0' react: '>= 16.8.0 < 20.0.0' @@ -1124,11 +1143,11 @@ packages: react-dom: optional: true - '@docsearch/css@4.3.2': - resolution: {integrity: sha512-K3Yhay9MgkBjJJ0WEL5MxnACModX9xuNt3UlQQkDEDZJZ0+aeWKtOkxHNndMRkMBnHdYvQjxkm6mdlneOtU1IQ==} + '@docsearch/css@4.6.0': + resolution: {integrity: sha512-YlcAimkXclvqta47g47efzCM5CFxDwv2ClkDfEs/fC/Ak0OxPH2b3czwa4o8O1TRBf+ujFF2RiUwszz2fPVNJQ==} - '@docsearch/react@4.3.2': - resolution: {integrity: sha512-74SFD6WluwvgsOPqifYOviEEVwDxslxfhakTlra+JviaNcs7KK/rjsPj89kVEoQc9FUxRkAofaJnHIR7pb4TSQ==} + '@docsearch/react@4.6.0': + resolution: {integrity: sha512-j8H5B4ArGxBPBWvw3X0J0Rm/Pjv2JDa2rV5OE0DLTp5oiBCptIJ/YlNOhZxuzbO2nwge+o3Z52nJRi3hryK9cA==} peerDependencies: '@types/react': '>= 16.8.0 < 20.0.0' react: '>= 16.8.0 < 20.0.0' @@ -1323,31 +1342,44 @@ packages: '@easyops-cn/autocomplete.js@0.38.1': resolution: {integrity: sha512-drg76jS6syilOUmVNkyo1c7ZEBPcPuK+aJA7AksM5ZIIbV57DMHCywiCr+uHyv8BE5jUTU98j/H7gVrkHrWW3Q==} - '@easyops-cn/docusaurus-search-local@0.52.2': - resolution: {integrity: sha512-oEHkHe/OWHFcJxOhicS5UqohDOyPieREH+oNoImL/VcdrPzDxT2LB5Scov6WMOpOyDcSMJ6QCvjj63PEhhU8Nw==} + '@easyops-cn/docusaurus-search-local@0.55.0': + resolution: {integrity: sha512-pmyG+e9KZmo4wrufsneeoE2KG2zH9tbRGi0crJFY0kPxOTGSLeuU5w058Qzgpz8vZNui6i59lKjrlQtnXNBgog==} engines: {node: '>=12'} peerDependencies: '@docusaurus/theme-common': ^2 || ^3 + open-ask-ai: ^0.7.3 react: ^16.14.0 || ^17 || ^18 || ^19 react-dom: ^16.14.0 || 17 || ^18 || ^19 + peerDependenciesMeta: + open-ask-ai: + optional: true - '@emnapi/core@1.7.1': - resolution: {integrity: sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg==} + '@emnapi/core@1.8.1': + resolution: {integrity: sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg==} - '@emnapi/runtime@1.7.1': - resolution: {integrity: sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==} + '@emnapi/runtime@1.8.1': + resolution: {integrity: sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==} '@emnapi/wasi-threads@1.1.0': resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==} - '@emotion/is-prop-valid@1.2.2': - resolution: {integrity: sha512-uNsoYd37AFmaCdXlg6EYD1KaPOaRWRByMCYzbKUX4+hhMfrxdVSelShywL4JVaAeM/eHUOSprYBQls+/neX3pw==} + '@emotion/is-prop-valid@1.4.0': + resolution: {integrity: sha512-QgD4fyscGcbbKwJmqNvUMSE02OsHUa+lAWKdEUIJKgqe5IwRSKd7+KhibEWdaKwgjLj0DRSHA9biAIqGBk05lw==} - '@emotion/memoize@0.8.1': - resolution: {integrity: sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==} + '@emotion/memoize@0.9.0': + resolution: {integrity: sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==} - '@emotion/unitless@0.8.1': - resolution: {integrity: sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==} + '@emotion/unitless@0.10.0': + resolution: {integrity: sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==} + + '@exodus/bytes@1.14.1': + resolution: {integrity: sha512-OhkBFWI6GcRMUroChZiopRiSp2iAMvEBK47NhJooDqz1RERO4QuZIZnjP63TXX8GAiLABkYmX+fuQsdJ1dd2QQ==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + peerDependencies: + '@noble/hashes': ^1.8.0 || ^2.0.0 + peerDependenciesMeta: + '@noble/hashes': + optional: true '@exodus/schemasafe@1.3.0': resolution: {integrity: sha512-5Aap/GaRupgNx/feGBwLLTVv8OQFfv3pq2lPRzPg9R+IOBnDgghTGW7l7EuVXOvg5cc/xSAlRW8rBrjIC3Nvqw==} @@ -1358,10 +1390,10 @@ packages: '@hapi/topo@5.1.0': resolution: {integrity: sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==} - '@ianvs/prettier-plugin-sort-imports@4.7.0': - resolution: {integrity: sha512-soa2bPUJAFruLL4z/CnMfSEKGznm5ebz29fIa9PxYtu8HHyLKNE1NXAs6dylfw1jn/ilEIfO2oLLN6uAafb7DA==} + '@ianvs/prettier-plugin-sort-imports@4.7.1': + resolution: {integrity: sha512-jmTNYGlg95tlsoG3JLCcuC4BrFELJtLirLAkQW/71lXSyOhVt/Xj7xWbbGcuVbNq1gwWgSyMrPjJc9Z30hynVw==} peerDependencies: - '@prettier/plugin-oxc': ^0.0.4 + '@prettier/plugin-oxc': ^0.0.4 || ^0.1.0 '@vue/compiler-sfc': 2.7.x || 3.x content-tag: ^4.0.0 prettier: 2 || 3 || ^4.0.0-0 @@ -1409,36 +1441,120 @@ packages: peerDependencies: tslib: '2' + '@jsonjoy.com/base64@17.67.0': + resolution: {integrity: sha512-5SEsJGsm15aP8TQGkDfJvz9axgPwAEm98S5DxOuYe8e1EbfajcDmgeXXzccEjh+mLnjqEKrkBdjHWS5vFNwDdw==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + '@jsonjoy.com/buffers@1.2.1': resolution: {integrity: sha512-12cdlDwX4RUM3QxmUbVJWqZ/mrK6dFQH4Zxq6+r1YXKXYBNgZXndx2qbCJwh3+WWkCSn67IjnlG3XYTvmvYtgA==} engines: {node: '>=10.0'} peerDependencies: tslib: '2' + '@jsonjoy.com/buffers@17.67.0': + resolution: {integrity: sha512-tfExRpYxBvi32vPs9ZHaTjSP4fHAfzSmcahOfNxtvGHcyJel+aibkPlGeBB+7AoC6hL7lXIE++8okecBxx7lcw==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + '@jsonjoy.com/codegen@1.0.0': resolution: {integrity: sha512-E8Oy+08cmCf0EK/NMxpaJZmOxPqM+6iSe2S4nlSBrPZOORoDJILxtbSUEDKQyTamm/BVAhIGllOBNU79/dwf0g==} engines: {node: '>=10.0'} peerDependencies: tslib: '2' + '@jsonjoy.com/codegen@17.67.0': + resolution: {integrity: sha512-idnkUplROpdBOV0HMcwhsCUS5TRUi9poagdGs70A6S4ux9+/aPuKbh8+UYRTLYQHtXvAdNfQWXDqZEx5k4Dj2Q==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + '@jsonjoy.com/fs-core@4.56.10': + resolution: {integrity: sha512-PyAEA/3cnHhsGcdY+AmIU+ZPqTuZkDhCXQ2wkXypdLitSpd6d5Ivxhnq4wa2ETRWFVJGabYynBWxIijOswSmOw==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + '@jsonjoy.com/fs-fsa@4.56.10': + resolution: {integrity: sha512-/FVK63ysNzTPOnCCcPoPHt77TOmachdMS422txM4KhxddLdbW1fIbFMYH0AM0ow/YchCyS5gqEjKLNyv71j/5Q==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + '@jsonjoy.com/fs-node-builtins@4.56.10': + resolution: {integrity: sha512-uUnKz8R0YJyKq5jXpZtkGV9U0pJDt8hmYcLRrPjROheIfjMXsz82kXMgAA/qNg0wrZ1Kv+hrg7azqEZx6XZCVw==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + '@jsonjoy.com/fs-node-to-fsa@4.56.10': + resolution: {integrity: sha512-oH+O6Y4lhn9NyG6aEoFwIBNKZeYy66toP5LJcDOMBgL99BKQMUf/zWJspdRhMdn/3hbzQsZ8EHHsuekbFLGUWw==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + '@jsonjoy.com/fs-node-utils@4.56.10': + resolution: {integrity: sha512-8EuPBgVI2aDPwFdaNQeNpHsyqPi3rr+85tMNG/lHvQLiVjzoZsvxA//Xd8aB567LUhy4QS03ptT+unkD/DIsNg==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + '@jsonjoy.com/fs-node@4.56.10': + resolution: {integrity: sha512-7R4Gv3tkUdW3dXfXiOkqxkElxKNVdd8BDOWC0/dbERd0pXpPY+s2s1Mino+aTvkGrFPiY+mmVxA7zhskm4Ue4Q==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + '@jsonjoy.com/fs-print@4.56.10': + resolution: {integrity: sha512-JW4fp5mAYepzFsSGrQ48ep8FXxpg4niFWHdF78wDrFGof7F3tKDJln72QFDEn/27M1yHd4v7sKHHVPh78aWcEw==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + '@jsonjoy.com/fs-snapshot@4.56.10': + resolution: {integrity: sha512-DkR6l5fj7+qj0+fVKm/OOXMGfDFCGXLfyHkORH3DF8hxkpDgIHbhf/DwncBMs2igu/ST7OEkexn1gIqoU6Y+9g==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + '@jsonjoy.com/json-pack@1.21.0': resolution: {integrity: sha512-+AKG+R2cfZMShzrF2uQw34v3zbeDYUqnQ+jg7ORic3BGtfw9p/+N6RJbq/kkV8JmYZaINknaEQ2m0/f693ZPpg==} engines: {node: '>=10.0'} peerDependencies: tslib: '2' + '@jsonjoy.com/json-pack@17.67.0': + resolution: {integrity: sha512-t0ejURcGaZsn1ClbJ/3kFqSOjlryd92eQY465IYrezsXmPcfHPE/av4twRSxf6WE+TkZgLY+71vCZbiIiFKA/w==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + '@jsonjoy.com/json-pointer@1.0.2': resolution: {integrity: sha512-Fsn6wM2zlDzY1U+v4Nc8bo3bVqgfNTGcn6dMgs6FjrEnt4ZCe60o6ByKRjOGlI2gow0aE/Q41QOigdTqkyK5fg==} engines: {node: '>=10.0'} peerDependencies: tslib: '2' + '@jsonjoy.com/json-pointer@17.67.0': + resolution: {integrity: sha512-+iqOFInH+QZGmSuaybBUNdh7yvNrXvqR+h3wjXm0N/3JK1EyyFAeGJvqnmQL61d1ARLlk/wJdFKSL+LHJ1eaUA==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + '@jsonjoy.com/util@1.9.0': resolution: {integrity: sha512-pLuQo+VPRnN8hfPqUTLTHk126wuYdXVxE6aDmjSeV4NCAgyxWbiOIeNJVtID3h1Vzpoi9m4jXezf73I6LgabgQ==} engines: {node: '>=10.0'} peerDependencies: tslib: '2' + '@jsonjoy.com/util@17.67.0': + resolution: {integrity: sha512-6+8xBaz1rLSohlGh68D1pdw3AwDi9xydm8QNlAFkvnavCJYSze+pxoW2VKP8p308jtlMRLs5NTHfPlZLd4w7ew==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + '@leichtgewicht/ip-codec@2.0.5': resolution: {integrity: sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==} @@ -1451,23 +1567,23 @@ packages: '@types/react': '>=16' react: '>=16' - '@module-federation/error-codes@0.21.6': - resolution: {integrity: sha512-MLJUCQ05KnoVl8xd6xs9a5g2/8U+eWmVxg7xiBMeR0+7OjdWUbHwcwgVFatRIwSZvFgKHfWEiI7wsU1q1XbTRQ==} + '@module-federation/error-codes@0.22.0': + resolution: {integrity: sha512-xF9SjnEy7vTdx+xekjPCV5cIHOGCkdn3pIxo9vU7gEZMIw0SvAEdsy6Uh17xaCpm8V0FWvR0SZoK9Ik6jGOaug==} - '@module-federation/runtime-core@0.21.6': - resolution: {integrity: sha512-5Hd1Y5qp5lU/aTiK66lidMlM/4ji2gr3EXAtJdreJzkY+bKcI5+21GRcliZ4RAkICmvdxQU5PHPL71XmNc7Lsw==} + '@module-federation/runtime-core@0.22.0': + resolution: {integrity: sha512-GR1TcD6/s7zqItfhC87zAp30PqzvceoeDGYTgF3Vx2TXvsfDrhP6Qw9T4vudDQL3uJRne6t7CzdT29YyVxlgIA==} - '@module-federation/runtime-tools@0.21.6': - resolution: {integrity: sha512-fnP+ZOZTFeBGiTAnxve+axGmiYn2D60h86nUISXjXClK3LUY1krUfPgf6MaD4YDJ4i51OGXZWPekeMe16pkd8Q==} + '@module-federation/runtime-tools@0.22.0': + resolution: {integrity: sha512-4ScUJ/aUfEernb+4PbLdhM/c60VHl698Gn1gY21m9vyC1Ucn69fPCA1y2EwcCB7IItseRMoNhdcWQnzt/OPCNA==} - '@module-federation/runtime@0.21.6': - resolution: {integrity: sha512-+caXwaQqwTNh+CQqyb4mZmXq7iEemRDrTZQGD+zyeH454JAYnJ3s/3oDFizdH6245pk+NiqDyOOkHzzFQorKhQ==} + '@module-federation/runtime@0.22.0': + resolution: {integrity: sha512-38g5iPju2tPC3KHMPxRKmy4k4onNp6ypFPS1eKGsNLUkXgHsPMBFqAjDw96iEcjri91BrahG4XcdyKi97xZzlA==} - '@module-federation/sdk@0.21.6': - resolution: {integrity: sha512-x6hARETb8iqHVhEsQBysuWpznNZViUh84qV2yE7AD+g7uIzHKiYdoWqj10posbo5XKf/147qgWDzKZoKoEP2dw==} + '@module-federation/sdk@0.22.0': + resolution: {integrity: sha512-x4aFNBKn2KVQRuNVC5A7SnrSCSqyfIWmm1DvubjbO9iKFe7ith5niw8dqSFBekYBg2Fwy+eMg4sEFNVvCAdo6g==} - '@module-federation/webpack-bundler-runtime@0.21.6': - resolution: {integrity: sha512-7zIp3LrcWbhGuFDTUMLJ2FJvcwjlddqhWGxi/MW3ur1a+HaO8v5tF2nl+vElKmbG1DFLU/52l3PElVcWf/YcsQ==} + '@module-federation/webpack-bundler-runtime@0.22.0': + resolution: {integrity: sha512-aM8gCqXu+/4wBmJtVeMeeMN5guw3chf+2i6HajKtQv7SJfxV/f4IyNQJUeUQu9HfiAZHjqtMV5Lvq/Lvh8LdyA==} '@napi-rs/wasm-runtime@0.2.12': resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} @@ -1475,6 +1591,10 @@ packages: '@napi-rs/wasm-runtime@1.0.7': resolution: {integrity: sha512-SeDnOO0Tk7Okiq6DbXmmBODgOAb9dp9gjlphokTUxmt8U3liIP1ZsozBahH69j/RJv+Rfs6IwUKHTgQYJ/HBAw==} + '@noble/hashes@1.4.0': + resolution: {integrity: sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==} + engines: {node: '>= 16'} + '@node-rs/jieba-android-arm-eabi@1.10.4': resolution: {integrity: sha512-MhyvW5N3Fwcp385d0rxbCWH42kqDBatQTyP8XbnYbju2+0BO/eTeCCLYj7Agws4pwxn2LtdldXRSKavT7WdzNA==} engines: {node: '>= 10'} @@ -1516,24 +1636,28 @@ packages: engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [glibc] '@node-rs/jieba-linux-arm64-musl@1.10.4': resolution: {integrity: sha512-Y/tiJ1+HeS5nnmLbZOE+66LbsPOHZ/PUckAYVeLlQfpygLEpLYdlh0aPpS5uiaWMjAXYZYdFkpZHhxDmSLpwpw==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [musl] '@node-rs/jieba-linux-x64-gnu@1.10.4': resolution: {integrity: sha512-WZO8ykRJpWGE9MHuZpy1lu3nJluPoeB+fIJJn5CWZ9YTVhNDWoCF4i/7nxz1ntulINYGQ8VVuCU9LD86Mek97g==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [glibc] '@node-rs/jieba-linux-x64-musl@1.10.4': resolution: {integrity: sha512-uBBD4S1rGKcgCyAk6VCKatEVQb6EDD5I40v/DxODi5CuZVCANi9m5oee/MQbAoaX7RydA2f0OSCE9/tcwXEwUg==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [musl] '@node-rs/jieba-wasm32-wasi@1.10.4': resolution: {integrity: sha512-Y2umiKHjuIJy0uulNDz9SDYHdfq5Hmy7jY5nORO99B4pySKkcrMjpeVrmWXJLIsEKLJwcCXHxz8tjwU5/uhz0A==} @@ -1574,9 +1698,39 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} - '@opentelemetry/api@1.9.0': - resolution: {integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==} - engines: {node: '>=8.0.0'} + '@peculiar/asn1-cms@2.6.1': + resolution: {integrity: sha512-vdG4fBF6Lkirkcl53q6eOdn3XYKt+kJTG59edgRZORlg/3atWWEReRCx5rYE1ZzTTX6vLK5zDMjHh7vbrcXGtw==} + + '@peculiar/asn1-csr@2.6.1': + resolution: {integrity: sha512-WRWnKfIocHyzFYQTka8O/tXCiBquAPSrRjXbOkHbO4qdmS6loffCEGs+rby6WxxGdJCuunnhS2duHURhjyio6w==} + + '@peculiar/asn1-ecc@2.6.1': + resolution: {integrity: sha512-+Vqw8WFxrtDIN5ehUdvlN2m73exS2JVG0UAyfVB31gIfor3zWEAQPD+K9ydCxaj3MLen9k0JhKpu9LqviuCE1g==} + + '@peculiar/asn1-pfx@2.6.1': + resolution: {integrity: sha512-nB5jVQy3MAAWvq0KY0R2JUZG8bO/bTLpnwyOzXyEh/e54ynGTatAR+csOnXkkVD9AFZ2uL8Z7EV918+qB1qDvw==} + + '@peculiar/asn1-pkcs8@2.6.1': + resolution: {integrity: sha512-JB5iQ9Izn5yGMw3ZG4Nw3Xn/hb/G38GYF3lf7WmJb8JZUydhVGEjK/ZlFSWhnlB7K/4oqEs8HnfFIKklhR58Tw==} + + '@peculiar/asn1-pkcs9@2.6.1': + resolution: {integrity: sha512-5EV8nZoMSxeWmcxWmmcolg22ojZRgJg+Y9MX2fnE2bGRo5KQLqV5IL9kdSQDZxlHz95tHvIq9F//bvL1OeNILw==} + + '@peculiar/asn1-rsa@2.6.1': + resolution: {integrity: sha512-1nVMEh46SElUt5CB3RUTV4EG/z7iYc7EoaDY5ECwganibQPkZ/Y2eMsTKB/LeyrUJ+W/tKoD9WUqIy8vB+CEdA==} + + '@peculiar/asn1-schema@2.6.0': + resolution: {integrity: sha512-xNLYLBFTBKkCzEZIw842BxytQQATQv+lDTCEMZ8C196iJcJJMBUZxrhSTxLaohMyKK8QlzRNTRkUmanucnDSqg==} + + '@peculiar/asn1-x509-attr@2.6.1': + resolution: {integrity: sha512-tlW6cxoHwgcQghnJwv3YS+9OO1737zgPogZ+CgWRUK4roEwIPzRH4JEiG770xe5HX2ATfCpmX60gurfWIF9dcQ==} + + '@peculiar/asn1-x509@2.6.1': + resolution: {integrity: sha512-O9jT5F1A2+t3r7C4VT7LYGXqkGLK7Kj1xFpz7U0isPrubwU5PbDoyYtx6MiGst29yq7pXN5vZbQFKRCP+lLZlA==} + + '@peculiar/x509@1.14.3': + resolution: {integrity: sha512-C2Xj8FZ0uHWeCXXqX5B4/gVFQmtSkiuOolzAgutjTfseNOHT3pUjljDZsTSxXFGgio54bCzVFqmEOUrIVk8RDA==} + engines: {node: '>=20.0.0'} '@pnpm/config.env-replace@1.1.0': resolution: {integrity: sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==} @@ -1586,15 +1740,15 @@ packages: resolution: {integrity: sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==} engines: {node: '>=12.22.0'} - '@pnpm/npm-conf@2.3.1': - resolution: {integrity: sha512-c83qWb22rNRuB0UaVCI0uRPNRr8Z0FWnEIvT47jiHAmOIUHbBOg5XvV7pM5x+rKn9HRpjxquDbXYSXr3fAKFcw==} + '@pnpm/npm-conf@3.0.2': + resolution: {integrity: sha512-h104Kh26rR8tm+a3Qkc5S4VLYint3FE48as7+/5oCEcKR2idC/pF1G6AhIXKI+eHPJa/3J9i5z0Al47IeGHPkA==} engines: {node: '>=12'} '@polka/url@1.0.0-next.29': resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==} - '@redocly/ajv@8.17.1': - resolution: {integrity: sha512-EDtsGZS964mf9zAUXAl9Ew16eYbeyAFWhsPr0fX6oaJxgd8rApYlPBf0joyhnUHz88WxrigyFtTaqqzXNzPgqw==} + '@redocly/ajv@8.17.4': + resolution: {integrity: sha512-BieiCML/IgP6x99HZByJSt7fJE4ipgzO7KAFss92Bs+PEI35BhY7vGIysFXLT+YmS7nHtQjZjhOQyPPEf7xGHA==} '@redocly/config@0.6.3': resolution: {integrity: sha512-hGWJgCsXRw0Ow4rplqRlUQifZvoSwZipkYnt11e3SeH1Eb23VUIDBcRuaQOUqy1wn0eevXkU2GzzQ8fbKdQ7Mg==} @@ -1603,60 +1757,64 @@ packages: resolution: {integrity: sha512-z06h+svyqbUcdAaePq8LPSwTPlm6Ig7j2VlL8skPBYnJvyaQ2IN7x/JkOvRL4ta+wcOCBdAex5JWnZbKaNktJg==} engines: {node: '>=14.19.0', npm: '>=7.0.0'} - '@rspack/binding-darwin-arm64@1.6.7': - resolution: {integrity: sha512-QiIAP8JTAtht0j8/xZZEQTJRB9e+KrOm9c7JJm73CewVg55rDWRrwopiVfBNlTu1coem1ztUHJYdQhg2uXfqww==} + '@rspack/binding-darwin-arm64@1.7.6': + resolution: {integrity: sha512-NZ9AWtB1COLUX1tA9HQQvWpTy07NSFfKBU8A6ylWd5KH8AePZztpNgLLAVPTuNO4CZXYpwcoclf8jG/luJcQdQ==} cpu: [arm64] os: [darwin] - '@rspack/binding-darwin-x64@1.6.7': - resolution: {integrity: sha512-DpQRxxTXkMMNPmBXeJBaAB8HmWKxH2IfvHv7vU+kBhJ3xdPtXU4/xBv1W3biluoNRG11gc1WLIgjzeGgaLCxmw==} + '@rspack/binding-darwin-x64@1.7.6': + resolution: {integrity: sha512-J2g6xk8ZS7uc024dNTGTHxoFzFovAZIRixUG7PiciLKTMP78svbSSWrmW6N8oAsAkzYfJWwQpVgWfFNRHvYxSw==} cpu: [x64] os: [darwin] - '@rspack/binding-linux-arm64-gnu@1.6.7': - resolution: {integrity: sha512-211/XoBiooGGgUo/NxNpsrzGUXtH1d7g/4+UTtjYtfc8QHwu7ZMHcsqg0wss53fXzn/yyxd0DZ56vBHq52BiFw==} + '@rspack/binding-linux-arm64-gnu@1.7.6': + resolution: {integrity: sha512-eQfcsaxhFrv5FmtaA7+O1F9/2yFDNIoPZzV/ZvqvFz5bBXVc4FAm/1fVpBg8Po/kX1h0chBc7Xkpry3cabFW8w==} cpu: [arm64] os: [linux] + libc: [glibc] - '@rspack/binding-linux-arm64-musl@1.6.7': - resolution: {integrity: sha512-0WnqAWz3WPDsXGvOOA++or7cHpoidVsH3FlqNaAfRu6ni6n7ig/s0/jKUB+C5FtXOgmGjAGkZHfFgNHsvZ0FWw==} + '@rspack/binding-linux-arm64-musl@1.7.6': + resolution: {integrity: sha512-DfQXKiyPIl7i1yECHy4eAkSmlUzzsSAbOjgMuKn7pudsWf483jg0UUYutNgXSlBjc/QSUp7906Cg8oty9OfwPA==} cpu: [arm64] os: [linux] + libc: [musl] - '@rspack/binding-linux-x64-gnu@1.6.7': - resolution: {integrity: sha512-iMrE0Q4IuYpkE0MjpaOVaUDYbQFiCRI9D3EPoXzlXJj4kJSdNheODpHTBVRlWt8Xp7UAoWuIFXCvKFKcSMm3aQ==} + '@rspack/binding-linux-x64-gnu@1.7.6': + resolution: {integrity: sha512-NdA+2X3lk2GGrMMnTGyYTzM3pn+zNjaqXqlgKmFBXvjfZqzSsKq3pdD1KHZCd5QHN+Fwvoszj0JFsquEVhE1og==} cpu: [x64] os: [linux] + libc: [glibc] - '@rspack/binding-linux-x64-musl@1.6.7': - resolution: {integrity: sha512-e7gKFxpdEQwYGk7lTC/hukTgNtaoAstBXehnZNk4k3kuU6+86WDrkn18Cd949iNqfIPtIG/wIsFNGbkHsH69hQ==} + '@rspack/binding-linux-x64-musl@1.7.6': + resolution: {integrity: sha512-rEy6MHKob02t/77YNgr6dREyJ0e0tv1X6Xsg8Z5E7rPXead06zefUbfazj4RELYySWnM38ovZyJAkPx/gOn3VA==} cpu: [x64] os: [linux] + libc: [musl] - '@rspack/binding-wasm32-wasi@1.6.7': - resolution: {integrity: sha512-yx88EFdE9RP3hh7VhjjW6uc6wGU0KcpOcZp8T8E/a+X8L98fX0aVrtM1IDbndhmdluIMqGbfJNap2+QqOCY9Mw==} + '@rspack/binding-wasm32-wasi@1.7.6': + resolution: {integrity: sha512-YupOrz0daSG+YBbCIgpDgzfMM38YpChv+afZpaxx5Ml7xPeAZIIdgWmLHnQ2rts73N2M1NspAiBwV00Xx0N4Vg==} cpu: [wasm32] - '@rspack/binding-win32-arm64-msvc@1.6.7': - resolution: {integrity: sha512-vgxVYpFK8P5ulSXQQA+EbX78R/SUU+WIf0JIY+LoUoP89gZOsise/lKAJMAybzpeTJ1t0ndLchFznDYnzq+l4Q==} + '@rspack/binding-win32-arm64-msvc@1.7.6': + resolution: {integrity: sha512-INj7aVXjBvlZ84kEhSK4kJ484ub0i+BzgnjDWOWM1K+eFYDZjLdAsQSS3fGGXwVc3qKbPIssFfnftATDMTEJHQ==} cpu: [arm64] os: [win32] - '@rspack/binding-win32-ia32-msvc@1.6.7': - resolution: {integrity: sha512-bV5RTW0Va0UQKJm9HWLt7fWNBPaBBBxCJOA2pJT3nGGm6CCXKnZSyEiVbFUk4jI/uiwBfqenlLkzaGoMRbeDhA==} + '@rspack/binding-win32-ia32-msvc@1.7.6': + resolution: {integrity: sha512-lXGvC+z67UMcw58In12h8zCa9IyYRmuptUBMItQJzu+M278aMuD1nETyGLL7e4+OZ2lvrnnBIcjXN1hfw2yRzw==} cpu: [ia32] os: [win32] - '@rspack/binding-win32-x64-msvc@1.6.7': - resolution: {integrity: sha512-8xlbuJQtYktlBjZupOHlO8FeZqSIhsV3ih7xBSiOYar6LI6uQzA7XiO3I5kaPSDirBMMMKv1Z4rKCxWx10a3TQ==} + '@rspack/binding-win32-x64-msvc@1.7.6': + resolution: {integrity: sha512-zeUxEc0ZaPpmaYlCeWcjSJUPuRRySiSHN23oJ2Xyw0jsQ01Qm4OScPdr0RhEOFuK/UE+ANyRtDo4zJsY52Hadw==} cpu: [x64] os: [win32] - '@rspack/binding@1.6.7': - resolution: {integrity: sha512-7ICabuBN3gHc6PPN52+m1kruz3ogiJjg1C0gSWdLRk18m/4jlcM2aAy6wfXjgODJdB0Yh2ro/lIpBbj+AYWUGA==} + '@rspack/binding@1.7.6': + resolution: {integrity: sha512-/NrEcfo8Gx22hLGysanrV6gHMuqZSxToSci/3M4kzEQtF5cPjfOv5pqeLK/+B6cr56ul/OmE96cCdWcXeVnFjQ==} - '@rspack/core@1.6.7': - resolution: {integrity: sha512-tkd4nSzTf+pDa9OAE4INi/JEa93HNszjWy5C9+trf4ZCXLLHsHxHQFbzoreuz4Vv2PlCWajgvAdiPMV1vGIkuw==} + '@rspack/core@1.7.6': + resolution: {integrity: sha512-Iax6UhrfZqJajA778c1d5DBFbSIqPOSrI34kpNIiNpWd8Jq7mFIa+Z60SQb5ZQDZuUxcCZikjz5BxinFjTkg7Q==} engines: {node: '>=18.12.0'} peerDependencies: '@swc/helpers': '>=0.5.1' @@ -1676,8 +1834,8 @@ packages: '@sideway/pinpoint@2.0.0': resolution: {integrity: sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==} - '@sinclair/typebox@0.27.8': - resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} + '@sinclair/typebox@0.27.10': + resolution: {integrity: sha512-MTBk/3jGLNB2tVxv6uLlFh1iu64iYOQ2PbdOSK3NW8JZsmlaOh2q6sdtKowBhfw8QFLmYNzTW4/oK4uATIi6ZA==} '@sindresorhus/is@4.6.0': resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==} @@ -1696,9 +1854,6 @@ packages: '@slorber/remark-comment@1.0.0': resolution: {integrity: sha512-RCE24n7jsOj1M0UPvIQCHTe7fI0sFL4S2nwKVWwHyVr/wI/H8GosgsJGyhnsZoGFnD/P2hLf1mSbrrgSLN93NA==} - '@standard-schema/spec@1.0.0': - resolution: {integrity: sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==} - '@svgr/babel-plugin-add-jsx-attribute@8.0.0': resolution: {integrity: sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g==} engines: {node: '>=14'} @@ -1777,68 +1932,72 @@ packages: resolution: {integrity: sha512-LnhVjMWyMQV9ZmeEy26maJk+8HTIbd59cH4F2MJ439k9DqejRisfFNGAPvRYlKETuh9LrImlS8aKsBgKjMA8WA==} engines: {node: '>=14'} - '@swc/core-darwin-arm64@1.15.4': - resolution: {integrity: sha512-NU/Of+ShFGG/i0lXKsF6GaGeTBNsr9iD8uUzdXxFfGbEjTeuKNXc5CWn3/Uo4Gr4LMAGD3hsRwG2Jq5iBDMalw==} + '@swc/core-darwin-arm64@1.15.11': + resolution: {integrity: sha512-QoIupRWVH8AF1TgxYyeA5nS18dtqMuxNwchjBIwJo3RdwLEFiJq6onOx9JAxHtuPwUkIVuU2Xbp+jCJ7Vzmgtg==} engines: {node: '>=10'} cpu: [arm64] os: [darwin] - '@swc/core-darwin-x64@1.15.4': - resolution: {integrity: sha512-9oWYMZHiEfHLqjjRGrXL17I8HdAOpWK/Rps34RKQ74O+eliygi1Iyq1TDUzYqUXcNvqN2K5fHgoMLRIni41ClQ==} + '@swc/core-darwin-x64@1.15.11': + resolution: {integrity: sha512-S52Gu1QtPSfBYDiejlcfp9GlN+NjTZBRRNsz8PNwBgSE626/FUf2PcllVUix7jqkoMC+t0rS8t+2/aSWlMuQtA==} engines: {node: '>=10'} cpu: [x64] os: [darwin] - '@swc/core-linux-arm-gnueabihf@1.15.4': - resolution: {integrity: sha512-I1dPxXli3N1Vr71JXogUTLcspM5ICgCYaA16RE+JKchj3XKKmxLlYjwAHAA4lh/Cy486ikzACaG6pIBcegoGkg==} + '@swc/core-linux-arm-gnueabihf@1.15.11': + resolution: {integrity: sha512-lXJs8oXo6Z4yCpimpQ8vPeCjkgoHu5NoMvmJZ8qxDyU99KVdg6KwU9H79vzrmB+HfH+dCZ7JGMqMF//f8Cfvdg==} engines: {node: '>=10'} cpu: [arm] os: [linux] - '@swc/core-linux-arm64-gnu@1.15.4': - resolution: {integrity: sha512-iGpuS/2PDZ68ioAlhkxiN5M4+pB9uDJolTKk4mZ0JM29uFf9YIkiyk7Bbr2y1QtmD82rF0tDHhoG9jtnV8mZMg==} + '@swc/core-linux-arm64-gnu@1.15.11': + resolution: {integrity: sha512-chRsz1K52/vj8Mfq/QOugVphlKPWlMh10V99qfH41hbGvwAU6xSPd681upO4bKiOr9+mRIZZW+EfJqY42ZzRyA==} engines: {node: '>=10'} cpu: [arm64] os: [linux] + libc: [glibc] - '@swc/core-linux-arm64-musl@1.15.4': - resolution: {integrity: sha512-Ly95wc+VXDhl08pjAoPUhVu5vNbuPMbURknRZa5QOZuiizJ6DkaSI0/zsEc26PpC6HTc4prNLY3ARVwZ7j/IJQ==} + '@swc/core-linux-arm64-musl@1.15.11': + resolution: {integrity: sha512-PYftgsTaGnfDK4m6/dty9ryK1FbLk+LosDJ/RJR2nkXGc8rd+WenXIlvHjWULiBVnS1RsjHHOXmTS4nDhe0v0w==} engines: {node: '>=10'} cpu: [arm64] os: [linux] + libc: [musl] - '@swc/core-linux-x64-gnu@1.15.4': - resolution: {integrity: sha512-7pIG0BnaMn4zTpHeColPwyrWoTY9Drr+ISZQIgYHUKh3oaPtNCrXb289ScGbPPPjLsSfcGTeOy2pXmNczMC+yg==} + '@swc/core-linux-x64-gnu@1.15.11': + resolution: {integrity: sha512-DKtnJKIHiZdARyTKiX7zdRjiDS1KihkQWatQiCHMv+zc2sfwb4Glrodx2VLOX4rsa92NLR0Sw8WLcPEMFY1szQ==} engines: {node: '>=10'} cpu: [x64] os: [linux] + libc: [glibc] - '@swc/core-linux-x64-musl@1.15.4': - resolution: {integrity: sha512-oaqTV25V9H+PpSkvTcK25q6Q56FvXc6d2xBu486dv9LAPCHWgeAworE8WpBLV26g8rubcN5nGhO5HwSunXA7Ww==} + '@swc/core-linux-x64-musl@1.15.11': + resolution: {integrity: sha512-mUjjntHj4+8WBaiDe5UwRNHuEzLjIWBTSGTw0JT9+C9/Yyuh4KQqlcEQ3ro6GkHmBGXBFpGIj/o5VMyRWfVfWw==} engines: {node: '>=10'} cpu: [x64] os: [linux] + libc: [musl] - '@swc/core-win32-arm64-msvc@1.15.4': - resolution: {integrity: sha512-VcPuUJw27YbGo1HcOaAriI50dpM3ZZeDW3x2cMnJW6vtkeyzUFk1TADmTwFax0Fn+yicCxhaWjnFE3eAzGAxIQ==} + '@swc/core-win32-arm64-msvc@1.15.11': + resolution: {integrity: sha512-ZkNNG5zL49YpaFzfl6fskNOSxtcZ5uOYmWBkY4wVAvgbSAQzLRVBp+xArGWh2oXlY/WgL99zQSGTv7RI5E6nzA==} engines: {node: '>=10'} cpu: [arm64] os: [win32] - '@swc/core-win32-ia32-msvc@1.15.4': - resolution: {integrity: sha512-dREjghAZEuKAK9nQzJETAiCSihSpAVS6Vk9+y2ElaoeTj68tNB1txV/m1RTPPD/+Kgbz6ITPNyXRWxPdkP5aXw==} + '@swc/core-win32-ia32-msvc@1.15.11': + resolution: {integrity: sha512-6XnzORkZCQzvTQ6cPrU7iaT9+i145oLwnin8JrfsLG41wl26+5cNQ2XV3zcbrnFEV6esjOceom9YO1w9mGJByw==} engines: {node: '>=10'} cpu: [ia32] os: [win32] - '@swc/core-win32-x64-msvc@1.15.4': - resolution: {integrity: sha512-o/odIBuQkoxKbRweJWOMI9LeRSOenFKN2zgPeaaNQ/cyuVk2r6DCAobKMOodvDdZWlMn6N1xJrldeCRSTZIgiQ==} + '@swc/core-win32-x64-msvc@1.15.11': + resolution: {integrity: sha512-IQ2n6af7XKLL6P1gIeZACskSxK8jWtoKpJWLZmdXTDj1MGzktUy4i+FvpdtxFmJWNavRWH1VmTr6kAubRDHeKw==} engines: {node: '>=10'} cpu: [x64] os: [win32] - '@swc/core@1.15.4': - resolution: {integrity: sha512-fH81BPo6EiJ7BUb6Qa5SY/NLWIRVambqU3740g0XPFPEz5KFPnzRYpR6zodQNOcEb9XUtZzRO1Y0WyIJP7iBxQ==} + '@swc/core@1.15.11': + resolution: {integrity: sha512-iLmLTodbYxU39HhMPaMUooPwO/zqJWvsqkrXv1ZI38rMb048p6N7qtAtTp37sw9NzSrvH6oli8EdDygo09IZ/w==} engines: {node: '>=10'} peerDependencies: '@swc/helpers': '>=0.5.17' @@ -1849,68 +2008,72 @@ packages: '@swc/counter@0.1.3': resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} - '@swc/html-darwin-arm64@1.15.4': - resolution: {integrity: sha512-NWSzDDUF2Dh+HLFjHmXu7o1uwTU31eQpxr53lrteWaKFPgHm6/LBFkuyYGVEBTFaxu2wBkZB+AZDCCyQwLf5AA==} + '@swc/html-darwin-arm64@1.15.11': + resolution: {integrity: sha512-FTa0ypbMbUXiwXIIT76HMFQYewEdTsPKOQGDqI6/kUTzU+lCIqIJequdoh6gqQvMq2BtBu/15dkTYYIlp4JoJw==} engines: {node: '>=10'} cpu: [arm64] os: [darwin] - '@swc/html-darwin-x64@1.15.4': - resolution: {integrity: sha512-w6I695Ve5mJwcEdkJ/n5vVDKkRVRBiSW7GlrTWaZowAP7T4Bv/QHj2Rf1C5134fYVlPmjSwkow+tmOpGtAdZsA==} + '@swc/html-darwin-x64@1.15.11': + resolution: {integrity: sha512-U+WFUFqbqS2WsLVCt40MuBGJ7mxDJi/T8RocBvQkoRwU3juOmeM2V/Od/QLBZxTFZTLQ3RCHJTkLXSDnxUWUuw==} engines: {node: '>=10'} cpu: [x64] os: [darwin] - '@swc/html-linux-arm-gnueabihf@1.15.4': - resolution: {integrity: sha512-Cpcsh0dukxiunqi9DJWoyWNB0o42Fa/otQ3ETYztuj4G/KdeJVAmTPEaXawAS8qYKOvFSfiiHxyij30cThF8tw==} + '@swc/html-linux-arm-gnueabihf@1.15.11': + resolution: {integrity: sha512-Cid64465sEkAiTh8KLFCbQbsIbgDzPeGdA5ZYB8w5AXmYAGPJ0xbeRHEFq3iq469Dj2rxYvExrLCXNhn8rHbww==} engines: {node: '>=10'} cpu: [arm] os: [linux] - '@swc/html-linux-arm64-gnu@1.15.4': - resolution: {integrity: sha512-8JaBctlvREo+zyppZmFR8Avh/VtxcTshdtcvqU8wz1TY9H7kZTi/n1FJeWIOZwf79yyEevlra7SMQaWNYSTD+Q==} + '@swc/html-linux-arm64-gnu@1.15.11': + resolution: {integrity: sha512-sxKdt0QJIR2x/6pAmDPK0tjfGVwsSZsfeY1BM8ODTm7h18ApE7KVNN+ZtsDbl4n5ejfXG7fOWNmMPUvj8qSMSA==} engines: {node: '>=10'} cpu: [arm64] os: [linux] + libc: [glibc] - '@swc/html-linux-arm64-musl@1.15.4': - resolution: {integrity: sha512-9QvKrM+GPc/dMUoOEJNGwOjT7FNBOc2XIhMhWxYhm9taMzJAbZvbpHN0beB9nqfQVCPxIK8LsCYU9xQV4VnDcQ==} + '@swc/html-linux-arm64-musl@1.15.11': + resolution: {integrity: sha512-aNACh2/HPy52VbKPqHieVRDeKzkO66DQdlhiVUi+fggdn8khvllni6Xr52INeAMjYFASrTTth/3vKXMv215t3A==} engines: {node: '>=10'} cpu: [arm64] os: [linux] + libc: [musl] - '@swc/html-linux-x64-gnu@1.15.4': - resolution: {integrity: sha512-y9TwMoPrBeonRW1sn4ncs7IflE4F7fDD7Vx8OPYVYA+KHyB1pm5edO/hPTsf4CNQ6Z4iWRgNK/Ec35FtwHAfbA==} + '@swc/html-linux-x64-gnu@1.15.11': + resolution: {integrity: sha512-8YOar0XeRLBzA+UMMW5smGpsQamoZLtaQ5RKGfap21FxOUUXqkPhkDTRr+kBVCYb47yz3NokjTPaDGTWOYNyww==} engines: {node: '>=10'} cpu: [x64] os: [linux] + libc: [glibc] - '@swc/html-linux-x64-musl@1.15.4': - resolution: {integrity: sha512-vweZgQl+RdZ6mq2ON+7CSqKLyx0J3jLCUrWu1jWdUp3T7LtJv1GLs1PkDFmom15tmhLzXsbduyr06vFWflY4sg==} + '@swc/html-linux-x64-musl@1.15.11': + resolution: {integrity: sha512-em2Ur0uGFA/nw2JbMclXu9mLuUC7q/1J06i8FZTRHqZzNGt9Q0UMdgH9T8HkGLT5e7dZ6ROJoq1H4st6B8N3uw==} engines: {node: '>=10'} cpu: [x64] os: [linux] + libc: [musl] - '@swc/html-win32-arm64-msvc@1.15.4': - resolution: {integrity: sha512-rdWwvBbl7QRHQd+Dw3QBMTmvPkHQMiRtBX0LPyb0dfEDZLiERXdOwjxACcvOLQ17E6q86SlWwG4HFodDn6dwkg==} + '@swc/html-win32-arm64-msvc@1.15.11': + resolution: {integrity: sha512-Xf9Vd4UsYTs4ejBwS+j9zShkyp3KQ+qfn/ZKVMKDygWjuOjU6FFXWYm93/PdTmS5qD0c58FhmoqTv+uFEZ4nxQ==} engines: {node: '>=10'} cpu: [arm64] os: [win32] - '@swc/html-win32-ia32-msvc@1.15.4': - resolution: {integrity: sha512-SG8vj/kmU2UuJM8XRK4T9XsoLb74FKAeRDYKuQ7DG6r9M/J4pDqlQhggZzftgMxTv9E253fEjlTbh/lsBTA0Kw==} + '@swc/html-win32-ia32-msvc@1.15.11': + resolution: {integrity: sha512-+YNzKR81UqH+xOZPU8XEIy5L6E63UUGSSEu1Wv3D85GVMQkZ8X9LZkZ5hq4vvqmCTV1zeHIPfzNrrVElqK198g==} engines: {node: '>=10'} cpu: [ia32] os: [win32] - '@swc/html-win32-x64-msvc@1.15.4': - resolution: {integrity: sha512-OXYoTyupJZTai3qfLn4RLou57TrECPGkLQ4y22vHR2VjOmUHJ37OcoNi0Myxa3QOL5HKx6T1llBfBY3VSqGu6g==} + '@swc/html-win32-x64-msvc@1.15.11': + resolution: {integrity: sha512-Y3Xj62eA+pjadhgiVNFUBgIN9Wa1gYrB3N1l6NmSLeApVE2qkBww3WrVXhRDfqUXiWz7eRHPDakZSRQREyMv5A==} engines: {node: '>=10'} cpu: [x64] os: [win32] - '@swc/html@1.15.4': - resolution: {integrity: sha512-7Pz445iqGZmASSprADrWi9tZ8pmeFAsLv7crYJ3zy316Ns2Vd0pYqimLggptz57+V2EmsNDGiqJew8v8TA1Oeg==} + '@swc/html@1.15.11': + resolution: {integrity: sha512-JOO48SCxyR3KbH9iiLMSWRDm7+Xl6lgvOBe5di54W8PsumdeP0Imatq8cunkRAUR7br8xAjlpB16bX6iJeyeMw==} engines: {node: '>=14'} '@swc/types@0.1.25': @@ -1924,8 +2087,8 @@ packages: resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==} engines: {node: '>=10.13.0'} - '@tsconfig/docusaurus@2.0.7': - resolution: {integrity: sha512-sDDxcltg2pcV0U3sQf5EMaX4/ER+x3IXmUc5EXuz4JnFDyxfGhTG7zGKJ8cLLZzjZALgdTK2LSKQbFLSKuGvQQ==} + '@tsconfig/docusaurus@2.0.9': + resolution: {integrity: sha512-0jVxZCgy2v7TnJrW9kVNikNwJHeiWb68Zhiiw2vHw4tzBFSP5vS2zn3O5EY2oPEVz5dXZRkK7MnWG3Ay5q0mIg==} '@tybys/wasm-util@0.10.1': resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} @@ -1957,8 +2120,8 @@ packages: '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} - '@types/express-serve-static-core@4.19.7': - resolution: {integrity: sha512-FvPtiIf1LfhzsaIXhv/PHan/2FeQBbtBDtfX2QfvPxdUelMDEckK08SM6nqo1MIZY3RUlfA+HV8+hFUSio78qg==} + '@types/express-serve-static-core@4.19.8': + resolution: {integrity: sha512-02S5fmqeoKzVZCHPZid4b8JH2eM5HzQLZWN2FohQEy/0eXTq8VXZfSN6Pcr3F6N9R/vNrj7cpgbhjie6m/1tCA==} '@types/express@4.17.25': resolution: {integrity: sha512-dVd04UKsfpINUnK0yBoYHDF3xu7xVH4BuDotC/xGuycx4CgbP48X/KF/586bcObxT0HENHXEU8Nqtu6NR+eKhw==} @@ -1975,8 +2138,8 @@ packages: '@types/html-minifier-terser@6.1.0': resolution: {integrity: sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==} - '@types/http-cache-semantics@4.0.4': - resolution: {integrity: sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==} + '@types/http-cache-semantics@4.2.0': + resolution: {integrity: sha512-L3LgimLHXtGkWikKnsPg0/VFx9OGZaC+eN1u4r+OB1XRqH3meBIAVC2zr1WdMH+RHmnRkqliQAOHNJ/E0j/e0Q==} '@types/http-errors@2.0.5': resolution: {integrity: sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==} @@ -2008,17 +2171,17 @@ packages: '@types/ms@2.1.0': resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} - '@types/node-forge@1.3.14': - resolution: {integrity: sha512-mhVF2BnD4BO+jtOp7z1CdzaK4mbuK0LLQYAvdOLqHTavxFNq4zA1EmYkpnFjP8HOUzedfQkRnp0E2ulSAYSzAw==} - '@types/node@17.0.45': resolution: {integrity: sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==} - '@types/node@24.10.4': - resolution: {integrity: sha512-vnDVpYPMzs4wunl27jHrfmwojOGKya0xyM3sH+UE5iv5uPS6vX7UIoh6m+vQc5LGBq52HBKPIn/zcSZVzeDEZg==} + '@types/node@24.10.13': + resolution: {integrity: sha512-oH72nZRfDv9lADUBSo104Aq7gPHpQZc4BTx38r9xf9pg5LfP6EzSyH2n7qFmmxRQXh7YlUXODcYsg6PuTDSxGg==} - '@types/prismjs@1.26.5': - resolution: {integrity: sha512-AUZTa7hQ2KY5L7AmtSiqxlhWxb4ina0yd8hNbl4TWuqnv/pFP0nDMb3YrfSBf4hJVGLh2YEIBfKaBW/9UEl6IQ==} + '@types/node@25.3.0': + resolution: {integrity: sha512-4K3bqJpXpqfg2XKGK9bpDTc6xO/xoUP/RBWS7AtRMug6zZFaRekiLzjVtAoZMquxoAbzBvy5nxQ7veS5eYzf8A==} + + '@types/prismjs@1.26.6': + resolution: {integrity: sha512-vqlvI7qlMvcCBbVe0AKAb4f97//Hy0EBTaiW8AalRnG/xAN5zOiWWyrNqNXeq8+KAuvRewjCVY1+IPxk4RdNYw==} '@types/qs@6.14.0': resolution: {integrity: sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==} @@ -2038,8 +2201,8 @@ packages: '@types/react-router@5.1.20': resolution: {integrity: sha512-jGjmu/ZqS7FjSH6owMcD5qpq19+1RS9DeVRqfl1FeBMxTDQAGwlMWOcs52NDoXaNKyG3d1cYQFMs9rCrb88o9Q==} - '@types/react@19.2.7': - resolution: {integrity: sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==} + '@types/react@19.2.14': + resolution: {integrity: sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==} '@types/retry@0.12.2': resolution: {integrity: sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow==} @@ -2062,8 +2225,8 @@ packages: '@types/sockjs@0.3.36': resolution: {integrity: sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==} - '@types/stylis@4.2.5': - resolution: {integrity: sha512-1Xve+NMN7FWjY14vLoY5tL3BVEQ/n42YLwaqJIPYhotZ9uBHt87VceMwWQpzmdEt2TNXIorIFG+YeCUUW7RInw==} + '@types/stylis@4.2.7': + resolution: {integrity: sha512-VgDNokpBoKF+wrdvhAAfS55OMQpL6QRglwTwNC3kIgBrzZxA4WsFj+2eLfEA/uMUDzBcEhYmjSbwQakn/i3ajA==} '@types/trusted-types@2.0.7': resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} @@ -2086,10 +2249,6 @@ packages: '@ungap/structured-clone@1.3.0': resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} - '@vercel/oidc@3.0.5': - resolution: {integrity: sha512-fnYhv671l+eTTp48gB4zEsTW/YtRgRPnkI2nT7x6qw5rkI1Lq2hTmQIpHPgyThI0znLK+vX2n9XxKdXZ7BUbbw==} - engines: {node: '>= 20'} - '@webassemblyjs/ast@1.14.1': resolution: {integrity: sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==} @@ -2156,12 +2315,12 @@ packages: peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - acorn-walk@8.3.4: - resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==} + acorn-walk@8.3.5: + resolution: {integrity: sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw==} engines: {node: '>=0.4.0'} - acorn@8.15.0: - resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} + acorn@8.16.0: + resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} engines: {node: '>=0.4.0'} hasBin: true @@ -2177,16 +2336,10 @@ packages: resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} engines: {node: '>=8'} - ai@5.0.113: - resolution: {integrity: sha512-26vivpSO/mzZj0k1Si2IpsFspp26ttQICHRySQiMrtWcRd5mnJMX2a8sG28vmZ38C+JUn1cWmfZrsLMxkSMw9g==} - engines: {node: '>=18'} - peerDependencies: - zod: ^3.25.76 || ^4.1.8 - ajv-formats@2.1.1: resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==} peerDependencies: - ajv: ^8.0.0 + ajv: ^6.14.0 peerDependenciesMeta: ajv: optional: true @@ -2194,26 +2347,23 @@ packages: ajv-keywords@3.5.2: resolution: {integrity: sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==} peerDependencies: - ajv: ^6.9.1 + ajv: ^6.14.0 ajv-keywords@5.1.0: resolution: {integrity: sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==} peerDependencies: - ajv: ^8.8.2 + ajv: ^6.14.0 - ajv@6.12.6: - resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + ajv@6.14.0: + resolution: {integrity: sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==} - ajv@8.17.1: - resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} - - algoliasearch-helper@3.26.1: - resolution: {integrity: sha512-CAlCxm4fYBXtvc5MamDzP6Svu8rW4z9me4DCBY1rQ2UDJ0u0flWmusQ8M3nOExZsLLRcUwUPoRAPMrhzOG3erw==} + algoliasearch-helper@3.27.1: + resolution: {integrity: sha512-XXGr02Cz285vLbqM6vPfb39xqV1ptpFr1xn9mqaW+nUvYTvFTdKgYTC/Cg1VzgRTQqNkq9+LlUVv8cfCeOoKig==} peerDependencies: algoliasearch: '>= 3.1 < 6' - algoliasearch@5.46.0: - resolution: {integrity: sha512-7ML6fa2K93FIfifG3GMWhDEwT5qQzPTmoHKCTvhzGEwdbQ4n0yYUWZlLYT75WllTGJCJtNUI0C1ybN4BCegqvg==} + algoliasearch@5.49.0: + resolution: {integrity: sha512-Tse7vx7WOvbU+kpq/L3BrBhSWTPbtMa59zIEhMn+Z2NoxZlpcCRUDCRxQ7kDFs1T3CHxDgvb+mDuILiBBpBaAA==} engines: {node: '>= 14.0.0'} ansi-align@3.0.1: @@ -2264,6 +2414,10 @@ packages: resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} engines: {node: '>=8'} + asn1js@3.0.7: + resolution: {integrity: sha512-uLvq6KJu04qoQM6gvBfKFjlh6Gl0vOKQuR5cJMDHQkmwfMOQeN3F3SHCv9SNYSL+CRoHvOGFfllDlVz03GQjvQ==} + engines: {node: '>=12.0.0'} + astring@1.9.0: resolution: {integrity: sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==} hasBin: true @@ -2271,15 +2425,15 @@ packages: asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} - autoprefixer@10.4.23: - resolution: {integrity: sha512-YYTXSFulfwytnjAPlw8QHncHJmlvFKtczb8InXaAx9Q0LbfDnfEYDE55omerIJKihhmU61Ft+cAOSzQVaBUmeA==} + autoprefixer@10.4.24: + resolution: {integrity: sha512-uHZg7N9ULTVbutaIsDRoUkoS8/h3bdsmVJYZ5l3wv8Cp/6UIIoRDm90hZ+BwxUj/hGBEzLxdHNSKuFpn8WOyZw==} engines: {node: ^10 || ^12 || >=14} hasBin: true peerDependencies: postcss: ^8.1.0 - axios@1.13.2: - resolution: {integrity: sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==} + axios@1.13.5: + resolution: {integrity: sha512-cz4ur7Vb0xS4/KUN0tPWe44eqxrIu31me+fbang3ijiNscE129POzipJJA6zniq2C/Z6sJCjMimjS8Lc/GAs8Q==} babel-loader@9.2.1: resolution: {integrity: sha512-fqe8naHt46e0yIdkjUZYqddSXfej3AHajX+CSO5X7oy0EmPc6o5Xh+RClNoHjnieWz9AW4kZxW9yyFMhVB1QLA==} @@ -2291,8 +2445,8 @@ packages: babel-plugin-dynamic-import-node@2.3.3: resolution: {integrity: sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==} - babel-plugin-polyfill-corejs2@0.4.14: - resolution: {integrity: sha512-Co2Y9wX854ts6U8gAAPXfn0GmAyctHuK8n0Yhfjd6t30g7yvKjspvvOo9yG+z52PZRgFErt7Ka2pYnXCjLKEpg==} + babel-plugin-polyfill-corejs2@0.4.15: + resolution: {integrity: sha512-hR3GwrRwHUfYwGfrisXPIDP3JcYfBrW7wKE7+Au6wDYl7fm/ka1NEII6kORzxNU556JjfidZeBsO10kYvtV1aw==} peerDependencies: '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 @@ -2301,19 +2455,26 @@ packages: peerDependencies: '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 - babel-plugin-polyfill-regenerator@0.6.5: - resolution: {integrity: sha512-ISqQ2frbiNU9vIJkzg7dlPpznPZ4jOiUQ1uSmB0fEHeowtN3COYRsXr/xexn64NpU13P06jc/L5TgiJXOgrbEg==} + babel-plugin-polyfill-corejs3@0.14.0: + resolution: {integrity: sha512-AvDcMxJ34W4Wgy4KBIIePQTAOP1Ie2WFwkQp3dB7FQ/f0lI5+nM96zUnYEOE1P9sEg0es5VCP0HxiWu5fUHZAQ==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + + babel-plugin-polyfill-regenerator@0.6.6: + resolution: {integrity: sha512-hYm+XLYRMvupxiQzrvXUj7YyvFFVfv5gI0R71AJzudg1g2AI2vyCPPIFEBjk162/wFzti3inBHo7isWFuEVS/A==} peerDependencies: '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 bail@2.0.2: resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} - balanced-match@1.0.2: - resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + balanced-match@4.0.4: + resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} + engines: {node: 18 || 20 || >=22} - baseline-browser-mapping@2.9.7: - resolution: {integrity: sha512-k9xFKplee6KIio3IDbwj+uaCLpqzOwakOgmqzPezM0sFJlFKcg30vk2wOiAJtkTSfx0SSQDSe8q+mWA/fSH5Zg==} + baseline-browser-mapping@2.10.0: + resolution: {integrity: sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA==} + engines: {node: '>=6.0.0'} hasBin: true batch@0.6.1: @@ -2347,11 +2508,9 @@ packages: resolution: {integrity: sha512-2hCgjEmP8YLWQ130n2FerGv7rYpfBmnmp9Uy2Le1vge6X3gZIfSmEzP5QTDElFxcvVcXlEn8Aq6MU/PZygIOog==} engines: {node: '>=14.16'} - brace-expansion@1.1.12: - resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} - - brace-expansion@2.0.2: - resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} + brace-expansion@5.0.3: + resolution: {integrity: sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==} + engines: {node: 18 || 20 || >=22} braces@3.0.3: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} @@ -2377,6 +2536,10 @@ packages: resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} engines: {node: '>= 0.8'} + bytestreamjs@2.0.1: + resolution: {integrity: sha512-U1Z/ob71V/bXfVABvNr/Kumf5VyeQRBEm6Txb0PQ6S7V5GpBM3w4Cbqz/xPDicR5tN0uvDifng8C+5qECeGwyQ==} + engines: {node: '>=6.0.0'} + cacheable-lookup@7.0.0: resolution: {integrity: sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==} engines: {node: '>=14.16'} @@ -2421,8 +2584,8 @@ packages: caniuse-api@3.0.0: resolution: {integrity: sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==} - caniuse-lite@1.0.30001760: - resolution: {integrity: sha512-7AAMPcueWELt1p3mi13HR/LHH0TJLT11cnwDJEs3xA4+CK/PLKeO9Kl1oru24htkyUKtkGCvAx4ohB0Ttry8Dw==} + caniuse-lite@1.0.30001772: + resolution: {integrity: sha512-mIwLZICj+ntVTw4BT2zfp+yu/AqV6GMKfJVJMx3MwPxs+uk/uj2GLl2dH8LQbjiLDX66amCga5nKFyDgRR43kg==} ccount@2.0.1: resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} @@ -2458,8 +2621,8 @@ packages: resolution: {integrity: sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==} engines: {node: '>= 6'} - cheerio@1.1.2: - resolution: {integrity: sha512-IkxPpb5rS/d1IiLbHMgfPuS0FgiWTtFIm/Nj+2woXDLTZ7fOT2eqzgYbdMlLweqlHbsZjxEChoVK+7iph7jyQg==} + cheerio@1.2.0: + resolution: {integrity: sha512-WDrybc/gKFpTYQutKIK6UvfcuxijIZfMfXaYm8NMsPQxSYvf+13fXUJ4rztGGbJcBQ/GF55gvrZ0Bc0bj/mqvg==} engines: {node: '>=20.18.1'} chokidar@3.6.0: @@ -2572,9 +2735,6 @@ packages: resolution: {integrity: sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==} engines: {node: '>= 0.8.0'} - concat-map@0.0.1: - resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - concurrently@9.2.1: resolution: {integrity: sha512-fsfrO0MxV64Znoy8/l1vVIjjHa29SZyyqPgQBwhiDcaW8wJc2W3XWVOGx4M3oJBnv/zdUZIIp1gDeS98GzP8Ng==} engines: {node: '>=18'} @@ -2623,14 +2783,14 @@ packages: peerDependencies: webpack: ^5.1.0 - core-js-compat@3.47.0: - resolution: {integrity: sha512-IGfuznZ/n7Kp9+nypamBhvwdwLsW6KC8IOaURw2doAK5e98AG3acVLdh0woOnEqCfUtS+Vu882JE4k/DAm3ItQ==} + core-js-compat@3.48.0: + resolution: {integrity: sha512-OM4cAF3D6VtH/WkLtWvyNC56EZVXsZdU3iqaMG2B4WvYrlqU831pc4UtG5yp0sE9z8Y02wVN7PjW5Zf9Gt0f1Q==} - core-js-pure@3.47.0: - resolution: {integrity: sha512-BcxeDbzUrRnXGYIVAGFtcGQVNpFcUhVjr6W7F8XktvQW2iJP9e66GP6xdKotCRFlrxBvNIBrhwKteRXqMV86Nw==} + core-js-pure@3.48.0: + resolution: {integrity: sha512-1slJgk89tWC51HQ1AEqG+s2VuwpTRr8ocu4n20QUcH1v9lAN0RXen0Q0AABa/DK1I7RrNWLucplOHMx8hfTGTw==} - core-js@3.47.0: - resolution: {integrity: sha512-c3Q2VVkGAUyupsjRnaNX6u8Dq2vAdzm9iuPj5FW0fRxzlxgq9Q39MDq10IvmQSpLgHQNyQzQmOo6bgGHmH3NNg==} + core-js@3.48.0: + resolution: {integrity: sha512-zpEHTy1fjTMZCKLHUZoVeylt9XrzaIN2rbPXEt0k+q7JE5CkCZdo6bNq55bn24a69CH7ErAVLKijxJja4fw+UQ==} core-util-is@1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} @@ -2662,8 +2822,8 @@ packages: resolution: {integrity: sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==} engines: {node: '>=4'} - css-declaration-sorter@7.3.0: - resolution: {integrity: sha512-LQF6N/3vkAMYF4xoHLJfG718HRJh34Z8BnNhd6bosOMIVjMlhuZK5++oZa3uYAgrI5+7x2o27gUqTR2U/KjUOQ==} + css-declaration-sorter@7.3.1: + resolution: {integrity: sha512-gz6x+KkgNCjxq3Var03pRYLhyNfwhkKF1g/yoLgDNtFvVu0/fOLV9C8fFEZRjACp/XQLumjAYo7JVjzH3wLbxA==} engines: {node: ^14 || ^16 || >=18} peerDependencies: postcss: ^8.0.9 @@ -2742,8 +2902,8 @@ packages: resolution: {integrity: sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==} engines: {node: '>= 6'} - cssdb@8.5.2: - resolution: {integrity: sha512-Pmoj9RmD8RIoIzA2EQWO4D4RMeDts0tgAH0VXdlNdxjuBGI3a9wMOIcUwaPNmD4r2qtIa06gqkIf7sECl+cBCg==} + cssdb@8.8.0: + resolution: {integrity: sha512-QbLeyz2Bgso1iRlh7IpWk6OKa3lLNGXsujVjDMPl9rOZpxKeiG69icLpbLCFxeURwmcdIfZqQyhlooKJYM4f8Q==} cssesc@3.0.0: resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} @@ -2778,19 +2938,16 @@ packages: resolution: {integrity: sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==} engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} - cssstyle@5.3.4: - resolution: {integrity: sha512-KyOS/kJMEq5O9GdPnaf82noigg5X5DYn0kZPJTaAsCUaBizp6Xa1y9D4Qoqf/JazEXWuruErHgVXwjN5391ZJw==} + cssstyle@6.1.0: + resolution: {integrity: sha512-Ml4fP2UT2K3CUBQnVlbdV/8aFDdlY69E+YnwJM+3VUWl08S3J8c8aRuJqCkD9Py8DHZ7zNNvsfKl8psocHZEFg==} engines: {node: '>=20'} - csstype@3.1.3: - resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} - csstype@3.2.3: resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} - data-urls@6.0.0: - resolution: {integrity: sha512-BnBS08aLUM+DKamupXs3w2tJJoqU+AkaE/+6vQxi/G/DPmIZFJJp9Dkb1kM03AZx8ADehDUZgsNxju3mPXZYIA==} - engines: {node: '>=20'} + data-urls@7.0.0: + resolution: {integrity: sha512-23XHcCF+coGYevirZceTVD7NdJOqVn+49IHyxgszm+JIiHLoB2TkmPtsYkNWT1pvRSGkc35L6NHs0yHkN2SumA==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} debounce@1.2.1: resolution: {integrity: sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==} @@ -2818,8 +2975,8 @@ packages: decko@1.2.0: resolution: {integrity: sha512-m8FnyHXV1QX+S1cl+KPFDIl6NMkxtKsy6+U/aYyjrOqWMuwAwYWu7ePqrsUHtDR5Y8Yk2pi/KIDSgF+vT4cPOQ==} - decode-named-character-reference@1.2.0: - resolution: {integrity: sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q==} + decode-named-character-reference@1.3.0: + resolution: {integrity: sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==} decompress-response@6.0.0: resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} @@ -2837,8 +2994,8 @@ packages: resolution: {integrity: sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==} engines: {node: '>=18'} - default-browser@5.4.0: - resolution: {integrity: sha512-XDuvSq38Hr1MdN47EDvYtx3U0MTqpCEn+F6ft8z2vYDzMrvQhVp0ui9oQdqW3MvK3vqUETglt1tVGgjLuJ5izg==} + default-browser@5.5.0: + resolution: {integrity: sha512-H9LMLr5zwIbSxrmvikGuI/5KGhZ8E2zH3stkMgM5LpOWDutGM2JZaj460Udnf1a+946zc7YBgrqEWwbk7zHvGw==} engines: {node: '>=18'} defer-to-connect@2.0.1: @@ -2966,8 +3123,8 @@ packages: ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} - electron-to-chromium@1.5.267: - resolution: {integrity: sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==} + electron-to-chromium@1.5.302: + resolution: {integrity: sha512-sM6HAN2LyK82IyPBpznDRqlTQAtuSaO+ShzFiWTvoMJLHyZ+Y39r8VMfHzwbU8MVBzQ4Wdn85+wlZl2TLGIlwg==} emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} @@ -2985,10 +3142,6 @@ packages: emoticon@4.1.0: resolution: {integrity: sha512-VWZfnxqwNcc51hIy/sbOdEem6D+cVtpPzEEtVAFdaas30+1dgkyaOQ4sQ6Bp0tOMqWO1v+HQfYaoodOkdhK6SQ==} - encodeurl@1.0.2: - resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} - engines: {node: '>= 0.8'} - encodeurl@2.0.0: resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} engines: {node: '>= 0.8'} @@ -2996,8 +3149,8 @@ packages: encoding-sniffer@0.2.1: resolution: {integrity: sha512-5gvq20T6vfpekVtqrYQsSCFZ1wEg5+wW0/QaZMWkFr6BqD3NfKs0rLCx4rrVlSWJeZb5NBJgVLswK/w2MWU+Gw==} - enhanced-resolve@5.18.4: - resolution: {integrity: sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q==} + enhanced-resolve@5.19.0: + resolution: {integrity: sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg==} engines: {node: '>=10.13.0'} entities@2.2.0: @@ -3011,6 +3164,10 @@ packages: resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} engines: {node: '>=0.12'} + entities@7.0.1: + resolution: {integrity: sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==} + engines: {node: '>=0.12'} + error-ex@1.3.4: resolution: {integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==} @@ -3022,8 +3179,8 @@ packages: resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} engines: {node: '>= 0.4'} - es-module-lexer@1.7.0: - resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} + es-module-lexer@2.0.0: + resolution: {integrity: sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==} es-object-atoms@1.1.1: resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} @@ -3129,17 +3286,13 @@ packages: eventemitter3@4.0.7: resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==} - eventemitter3@5.0.1: - resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} + eventemitter3@5.0.4: + resolution: {integrity: sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==} events@3.3.0: resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} engines: {node: '>=0.8.x'} - eventsource-parser@3.0.6: - resolution: {integrity: sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==} - engines: {node: '>=18.0.0'} - execa@5.1.1: resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} engines: {node: '>=10'} @@ -3171,12 +3324,12 @@ packages: fast-uri@3.1.0: resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} - fast-xml-parser@4.5.3: - resolution: {integrity: sha512-RKihhV+SHsIUGXObeVy9AXiBbFwkVk7Syp8XgwN5U3JV416+Gwp/GO9i0JYKmikykgz/UHRrrV4ROuZEo/T0ig==} + fast-xml-parser@5.3.7: + resolution: {integrity: sha512-JzVLro9NQv92pOM/jTCR6mHlJh2FGwtomH8ZQjhFj/R29P2Fnj38OgPJVtcvYw6SuKClhgYuwUZf5b3rd8u2mA==} hasBin: true - fastq@1.19.1: - resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==} + fastq@1.20.1: + resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} fault@2.0.1: resolution: {integrity: sha512-WtySTkS4OKev5JtpHXnib4Gxiurzh5NCGvWrFaZ34m6JehfTUhKZvn9njTfw48t6JumVQOmrKqpmGcdwxnhqBQ==} @@ -3258,8 +3411,8 @@ packages: resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} engines: {node: '>=12'} - fs-extra@11.3.2: - resolution: {integrity: sha512-Xr9F6z6up6Ws+NjzMCZc6WXg2YFRlrLP9NQDO3VQrWrfiojdhS56TzueT88ze0uBdCTwEIhQ3ptnmKeWGFAe0A==} + fs-extra@11.3.3: + resolution: {integrity: sha512-VWSRii4t0AFm6ixFFmLLx1t7wS1gh+ckoa84aOeapGum0h+EZd1EhEumSB+ZdDLnEPuucsVB9oB7cxJHap6Afg==} engines: {node: '>=14.14'} fsevents@2.3.3: @@ -3414,9 +3567,9 @@ packages: hpack.js@2.1.6: resolution: {integrity: sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==} - html-encoding-sniffer@4.0.0: - resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==} - engines: {node: '>=18'} + html-encoding-sniffer@6.0.0: + resolution: {integrity: sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} html-escaper@2.0.2: resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} @@ -3438,8 +3591,8 @@ packages: html-void-elements@3.0.0: resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==} - html-webpack-plugin@5.6.5: - resolution: {integrity: sha512-4xynFbKNNk+WlzXeQQ+6YYsH2g7mpfPszQZUi3ovKlj+pDmngQ7vRXjrrmGROabmKwyQkcgcX5hqfOwHbFmK5g==} + html-webpack-plugin@5.6.6: + resolution: {integrity: sha512-bLjW01UTrvoWTJQL5LsMRo1SypHW80FTm12OJRSnr3v6YHNhfe+1r0MYUZJMACxnCHURVnBWRwAsWs2yPU9Ezw==} engines: {node: '>=10.13.0'} peerDependencies: '@rspack/core': 0.x || 1.x @@ -3450,8 +3603,8 @@ packages: webpack: optional: true - htmlparser2@10.0.0: - resolution: {integrity: sha512-TwAZM+zE5Tq3lrEHvOlvwgj1XLWQCtaaibSN11Q+gGBAS7Y1uZSWwXXRe4iF6OXnaq1riyQAPFOBtYc77Mxq0g==} + htmlparser2@10.1.0: + resolution: {integrity: sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==} htmlparser2@6.1.0: resolution: {integrity: sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==} @@ -3465,14 +3618,10 @@ packages: http-deceiver@1.2.7: resolution: {integrity: sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==} - http-errors@1.6.3: - resolution: {integrity: sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==} + http-errors@1.8.1: + resolution: {integrity: sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==} engines: {node: '>= 0.6'} - http-errors@2.0.0: - resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} - engines: {node: '>= 0.8'} - http-errors@2.0.1: resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} engines: {node: '>= 0.8'} @@ -3562,9 +3711,6 @@ packages: resolution: {integrity: sha512-uyH0zfr1erU1OohLk0fT4Rrb94AOhguWNOcD9uGrSpRvNB+6gZXUoJX5J0NtvzBO10YZ9PgvA4NFgt+fYg8ojw==} engines: {node: '>=12'} - inherits@2.0.3: - resolution: {integrity: sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==} - inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} @@ -3705,8 +3851,8 @@ packages: resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} engines: {node: '>=8'} - is-wsl@3.1.0: - resolution: {integrity: sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==} + is-wsl@3.1.1: + resolution: {integrity: sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==} engines: {node: '>=16'} is-yarn-global@0.4.1: @@ -3726,9 +3872,9 @@ packages: resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==} engines: {node: '>=0.10.0'} - isomorphic-dompurify@2.34.0: - resolution: {integrity: sha512-7VeB/tDBQ8jt1+syT563hmmejY01nuwizpUIFPfM1aw3iTgLLiVP4/Nh+PKhNoa1V/H+E6ZlNcowsXLbChPCpw==} - engines: {node: '>=20.19.5'} + isomorphic-dompurify@3.0.0: + resolution: {integrity: sha512-5K+MYP7Nrg74+Bi+QmQGzQ/FgEOyVHWsN8MuJy5wYQxxBRxPnWsD25Tjjt5FWYhan3OQ+vNLubyNJH9dfG03lQ==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} jest-util@29.7.0: resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==} @@ -3764,8 +3910,8 @@ packages: resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} hasBin: true - jsdom@27.3.0: - resolution: {integrity: sha512-GtldT42B8+jefDUC4yUKAvsaOrH7PDHmZxZXNgF2xMmymjUbRYJvpAybZAKEmXDGTM0mCsz8duOa4vTm5AY2Kg==} + jsdom@28.1.0: + resolution: {integrity: sha512-0+MoQNYyr2rBHqO1xilltfDjV9G7ymYGlAUazgcDLQaUf8JDHbuGwsxN6U9qWaElZ4w1B2r7yEGIL3GdeW3Rug==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} peerDependencies: canvas: ^3.0.0 @@ -3793,9 +3939,6 @@ packages: json-schema-traverse@1.0.0: resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} - json-schema@0.4.0: - resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==} - json5@2.2.3: resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} engines: {node: '>=6'} @@ -3822,81 +3965,85 @@ packages: resolution: {integrity: sha512-KvNT4XqAMzdcL6ka6Tl3i2lYeFDgXNCuIX+xNx6ZMVR1dFq+idXd9FLKNMOIx0t9mJ9/HudyX4oZWXZQ0UJHeg==} engines: {node: '>=14.16'} - launch-editor@2.12.0: - resolution: {integrity: sha512-giOHXoOtifjdHqUamwKq6c49GzBdLjvxrd2D+Q4V6uOHopJv7p9VJxikDsQ/CBXZbEITgUqSVHXLTG3VhPP1Dg==} + launch-editor@2.13.0: + resolution: {integrity: sha512-u+9asUHMJ99lA15VRMXw5XKfySFR9dGXwgsgS14YTbUq3GITP58mIM32At90P5fZ+MUId5Yw+IwI/yKub7jnCQ==} leven@3.1.0: resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} engines: {node: '>=6'} - lightningcss-android-arm64@1.30.2: - resolution: {integrity: sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==} + lightningcss-android-arm64@1.31.1: + resolution: {integrity: sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [android] - lightningcss-darwin-arm64@1.30.2: - resolution: {integrity: sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==} + lightningcss-darwin-arm64@1.31.1: + resolution: {integrity: sha512-02uTEqf3vIfNMq3h/z2cJfcOXnQ0GRwQrkmPafhueLb2h7mqEidiCzkE4gBMEH65abHRiQvhdcQ+aP0D0g67sg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [darwin] - lightningcss-darwin-x64@1.30.2: - resolution: {integrity: sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==} + lightningcss-darwin-x64@1.31.1: + resolution: {integrity: sha512-1ObhyoCY+tGxtsz1lSx5NXCj3nirk0Y0kB/g8B8DT+sSx4G9djitg9ejFnjb3gJNWo7qXH4DIy2SUHvpoFwfTA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [darwin] - lightningcss-freebsd-x64@1.30.2: - resolution: {integrity: sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==} + lightningcss-freebsd-x64@1.31.1: + resolution: {integrity: sha512-1RINmQKAItO6ISxYgPwszQE1BrsVU5aB45ho6O42mu96UiZBxEXsuQ7cJW4zs4CEodPUioj/QrXW1r9pLUM74A==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [freebsd] - lightningcss-linux-arm-gnueabihf@1.30.2: - resolution: {integrity: sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==} + lightningcss-linux-arm-gnueabihf@1.31.1: + resolution: {integrity: sha512-OOCm2//MZJ87CdDK62rZIu+aw9gBv4azMJuA8/KB74wmfS3lnC4yoPHm0uXZ/dvNNHmnZnB8XLAZzObeG0nS1g==} engines: {node: '>= 12.0.0'} cpu: [arm] os: [linux] - lightningcss-linux-arm64-gnu@1.30.2: - resolution: {integrity: sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==} + lightningcss-linux-arm64-gnu@1.31.1: + resolution: {integrity: sha512-WKyLWztD71rTnou4xAD5kQT+982wvca7E6QoLpoawZ1gP9JM0GJj4Tp5jMUh9B3AitHbRZ2/H3W5xQmdEOUlLg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [glibc] - lightningcss-linux-arm64-musl@1.30.2: - resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==} + lightningcss-linux-arm64-musl@1.31.1: + resolution: {integrity: sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [musl] - lightningcss-linux-x64-gnu@1.30.2: - resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==} + lightningcss-linux-x64-gnu@1.31.1: + resolution: {integrity: sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [glibc] - lightningcss-linux-x64-musl@1.30.2: - resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==} + lightningcss-linux-x64-musl@1.31.1: + resolution: {integrity: sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [musl] - lightningcss-win32-arm64-msvc@1.30.2: - resolution: {integrity: sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==} + lightningcss-win32-arm64-msvc@1.31.1: + resolution: {integrity: sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [win32] - lightningcss-win32-x64-msvc@1.30.2: - resolution: {integrity: sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==} + lightningcss-win32-x64-msvc@1.31.1: + resolution: {integrity: sha512-I9aiFrbd7oYHwlnQDqr1Roz+fTz61oDDJX7n9tYF9FJymH1cIN1DtKw3iYt6b8WZgEjoNwVSncwF4wx/ZedMhw==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [win32] - lightningcss@1.30.2: - resolution: {integrity: sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==} + lightningcss@1.31.1: + resolution: {integrity: sha512-l51N2r93WmGUye3WuFoN5k10zyvrVs0qfKBhyC5ogUQ6Ew6JUSswh78mbSO+IU3nTWsyOArqPCcShdQSadghBQ==} engines: {node: '>= 12.0.0'} lilconfig@3.1.3: @@ -3931,8 +4078,8 @@ packages: lodash.uniq@4.5.0: resolution: {integrity: sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==} - lodash@4.17.21: - resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + lodash@4.17.23: + resolution: {integrity: sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==} longest-streak@3.1.0: resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} @@ -3948,8 +4095,8 @@ packages: resolution: {integrity: sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - lru-cache@11.2.4: - resolution: {integrity: sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==} + lru-cache@11.2.6: + resolution: {integrity: sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==} engines: {node: 20 || >=22} lru-cache@5.1.1: @@ -3974,13 +4121,8 @@ packages: markdown-table@3.0.4: resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==} - marked@16.4.2: - resolution: {integrity: sha512-TI3V8YYWvkVf3KJe1dRkpnjs68JUPyEa5vjKrp1XEEJUAOaQc+Qj+L1qWbPd0SJuAdQkFU0h73sXXqwDYxsiDA==} - engines: {node: '>= 20'} - hasBin: true - - marked@17.0.1: - resolution: {integrity: sha512-boeBdiS0ghpWcSwoNm/jJBwdpFaMnZWRzjA6SkUMYb40SVaN1x7mmfGKp0jvexGcx+7y2La5zRZsYFZI6Qpypg==} + marked@17.0.3: + resolution: {integrity: sha512-jt1v2ObpyOKR8p4XaUJVk3YWRJ5n+i4+rjQopxvV32rSndTJXvIzuUdWWIy/1pFQMkQmvTXawzDNqOH/CUmx6A==} engines: {node: '>= 20'} hasBin: true @@ -3999,8 +4141,8 @@ packages: mdast-util-find-and-replace@3.0.2: resolution: {integrity: sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==} - mdast-util-from-markdown@2.0.2: - resolution: {integrity: sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==} + mdast-util-from-markdown@2.0.3: + resolution: {integrity: sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q==} mdast-util-frontmatter@2.0.1: resolution: {integrity: sha512-LRqI9+wdgC25P0URIJY9vwocIzCcksduHQ9OF2joxQoyTNVduwLAFUzjoopuRJbJAReaKrNQKAZKL3uCMugWJA==} @@ -4060,8 +4202,10 @@ packages: resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} engines: {node: '>= 0.6'} - memfs@4.51.1: - resolution: {integrity: sha512-Eyt3XrufitN2ZL9c/uIRMyDwXanLI88h/L3MoWqNY747ha3dMR9dWqp8cRT5ntjZ0U1TNuq4U91ZXK0sMBjYOQ==} + memfs@4.56.10: + resolution: {integrity: sha512-eLvzyrwqLHnLYalJP7YZ3wBe79MXktMdfQbvMrVD80K+NhrIukCVBvgP30zTJYEEDh9hZ/ep9z0KOdD7FSHo7w==} + peerDependencies: + tslib: '2' merge-descriptors@1.0.3: resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==} @@ -4245,8 +4389,8 @@ packages: resolution: {integrity: sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - mini-css-extract-plugin@2.9.4: - resolution: {integrity: sha512-ZWYT7ln73Hptxqxk2DxPU9MmapXRhxkJD6tkSR04dnQxm8BGu2hzgKLugK5yySD97u/8yy7Ma7E76k9ZdvtjkQ==} + mini-css-extract-plugin@2.10.0: + resolution: {integrity: sha512-540P2c5dYnJlyJxTaSloliZexv8rji6rY8FhQN+WF/82iHQfA23j/xtJx97L+mXOML27EqksSek/g4eK7jaL3g==} engines: {node: '>= 12.13.0'} peerDependencies: webpack: ^5.0.0 @@ -4254,12 +4398,9 @@ packages: minimalistic-assert@1.0.1: resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==} - minimatch@3.1.2: - resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} - - minimatch@5.1.6: - resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} - engines: {node: '>=10'} + minimatch@10.2.2: + resolution: {integrity: sha512-+G4CpNBxa5MprY+04MbgOw1v7So6n5JY166pFi9KfYwT78fxScCeSNQSNzp6dpPSW2rONOps6Ocam1wFhCgoVw==} + engines: {node: 18 || 20 || >=22} minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} @@ -4343,10 +4484,6 @@ packages: encoding: optional: true - node-forge@1.3.3: - resolution: {integrity: sha512-rLvcdSyRCyouf6jcOIPe/BgwG/d7hKjzMKOas33/pHEr6gbq18IK9zV7DiPvzsz0oBJPme6qr6H6kGZuI9/DZg==} - engines: {node: '>= 6.13.0'} - node-readfiles@0.2.0: resolution: {integrity: sha512-SU00ZarexNlE4Rjdm83vglt5Y9yiQ+XI1XpflWlb7q7UTN1JUItm69xMeiQCTxtTfnzt+83T8Cx+vI2ED++VDA==} @@ -4357,8 +4494,8 @@ packages: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} - normalize-url@8.1.0: - resolution: {integrity: sha512-X06Mfd/5aKsRHc0O0J5CUedwnPmnDtLF2+nq+KN9KSDlJHkPuh0JUviWjEWMe0SW/9TDdSLVPuk7L5gGTIA1/w==} + normalize-url@8.1.1: + resolution: {integrity: sha512-JYc0DPlpGWB40kH5g07gGTrYuMqV653k3uBKY6uITPWds3M0ov3GaWGp9lbE3Bzngx8+XkfzgvASb9vk9JDFXQ==} engines: {node: '>=14.16'} npm-run-path@4.0.1: @@ -4432,8 +4569,8 @@ packages: resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==} engines: {node: '>=12'} - openapi-sampler@1.6.2: - resolution: {integrity: sha512-NyKGiFKfSWAZr4srD/5WDhInOWDhfml32h/FKUqLpEwKJt0kG0LGUU0MdyNkKrVGuJnw6DuPWq/sHCwAMpiRxg==} + openapi-sampler@1.7.0: + resolution: {integrity: sha512-fWq32F5vqGpgRJYIarC/9Y1wC9tKnRDcCOjsDJ7MIcSv2HsE7kNifcXIZ8FVtNStBUWxYrEk/MKqVF0SwZ5gog==} opener@1.5.2: resolution: {integrity: sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==} @@ -4555,6 +4692,10 @@ packages: resolution: {integrity: sha512-Ie9z/WINcxxLp27BKOCHGde4ITq9UklYKDzVo1nhk5sqGEXU3FpkwP5GM2voTGJkGd9B3Otl+Q4uwSOeSUtOBA==} engines: {node: '>=14.16'} + pkijs@3.3.3: + resolution: {integrity: sha512-+KD8hJtqQMYoTuL1bbGOqxb4z+nZkTAwVdNtWwe8Tc2xNbEmdJYIYoc6Qt0uF55e6YW6KuTHw1DjQ18gMhzepw==} + engines: {node: '>=16.0.0'} + pluralize@8.0.0: resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} engines: {node: '>=4'} @@ -4879,8 +5020,8 @@ packages: peerDependencies: postcss: '>4 <9' - postcss-preset-env@10.5.0: - resolution: {integrity: sha512-xgxFQPAPxeWmsgy8cR7GM1PGAL/smA5E9qU7K//D4vucS01es3M0fDujhDJn3kY8Ip7/vVYcecbe1yY+vBo3qQ==} + postcss-preset-env@10.6.1: + resolution: {integrity: sha512-yrk74d9EvY+W7+lO9Aj1QmjWY9q5NsKjK2V9drkOPZB/X6KZ0B3igKsHUYakb7oYVhnioWypQX3xGuePf89f3g==} engines: {node: '>=18'} peerDependencies: postcss: ^8.4 @@ -4963,8 +5104,8 @@ packages: resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} engines: {node: ^10 || ^12 || >=14} - prettier@3.7.4: - resolution: {integrity: sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==} + prettier@3.8.1: + resolution: {integrity: sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==} engines: {node: '>=14'} hasBin: true @@ -5015,8 +5156,15 @@ packages: resolution: {integrity: sha512-LjgDO2zPtoXP2wJpDjZrGdojii1uqO0cnwKoIoUzkfS98HDmbeiGmYiXo3lXeFlq2xvne1QFQhwYXSUCLKtEuA==} engines: {node: '>=12.20'} - qs@6.14.0: - resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==} + pvtsutils@1.3.6: + resolution: {integrity: sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg==} + + pvutils@1.1.5: + resolution: {integrity: sha512-KTqnxsgGiQ6ZAzZCVlJH5eOjSnvlyEgx1m8bkRJfOhmGRqfo5KLvmAlACQkrjEtOQ4B7wF9TdSLIs9O90MX9xA==} + engines: {node: '>=16.0.0'} + + qs@6.14.2: + resolution: {integrity: sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==} engines: {node: '>=0.6'} queue-microtask@1.2.3: @@ -5045,10 +5193,10 @@ packages: resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} hasBin: true - react-dom@19.2.3: - resolution: {integrity: sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==} + react-dom@19.2.4: + resolution: {integrity: sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==} peerDependencies: - react: ^19.2.3 + react: ^19.2.4 react-fast-compare@3.2.2: resolution: {integrity: sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==} @@ -5090,8 +5238,8 @@ packages: peerDependencies: react: ^18.0.0 || ^19.0.0 - react@19.2.3: - resolution: {integrity: sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==} + react@19.2.4: + resolution: {integrity: sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==} engines: {node: '>=0.10.0'} readable-stream@2.3.8: @@ -5136,6 +5284,9 @@ packages: '@docusaurus/theme-common': ^3.6.0 '@docusaurus/utils': ^3.6.0 + reflect-metadata@0.2.2: + resolution: {integrity: sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==} + reftools@1.1.9: resolution: {integrity: sha512-OVede/NQE13xBQ+ob5CKd5KyeJYU2YInb1bmV4nRoOfquZPkAkxuOXicSe1PvqIuZZ4kD13sPKBbR7UFDmli6w==} @@ -5150,8 +5301,8 @@ packages: resolution: {integrity: sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA==} engines: {node: '>=4'} - registry-auth-token@5.1.0: - resolution: {integrity: sha512-GdekYuwLXLxMuFTwAPg5UKGLW/UXzQrZvH/Zj791BQif5T05T0RsaLfHc9q3ZOKi7n+BoprPD9mJ0O0k4xzUlw==} + registry-auth-token@5.1.1: + resolution: {integrity: sha512-P7B4+jq8DeD2nMsAcdfaqHbssgHtZ7Z5+++a5ask90fvmJ8p5je4mOa+wzu+DB4vQ5tdJV/xywY+UnVFeQLV5Q==} engines: {node: '>=14'} registry-url@6.0.1: @@ -5272,8 +5423,9 @@ packages: safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - sax@1.4.3: - resolution: {integrity: sha512-yqYn1JhPczigF94DMS+shiDMjDowYO6y9+wB/4WgO0Y19jWYk0lQ4tuG5KI7kj4FTp1wxPj5IFfcrz/s1c3jjQ==} + sax@1.4.4: + resolution: {integrity: sha512-1n3r/tGXO6b6VXMdFT54SHzT9ytu9yr7TaELowdYpMqY/Ao7EnlQGmAQ1+RatX7Tkkdm6hONI2owqNx2aZj5Sw==} + engines: {node: '>=11.0.0'} saxes@6.0.0: resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} @@ -5303,9 +5455,9 @@ packages: select-hose@2.0.0: resolution: {integrity: sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==} - selfsigned@2.4.1: - resolution: {integrity: sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==} - engines: {node: '>=10'} + selfsigned@5.5.0: + resolution: {integrity: sha512-ftnu3TW4+3eBfLRFnDEkzGxSF/10BJBkaLJuBHZX0kiPS7bRdlpZGu6YGt4KngMkdTwJE6MbjavFpqHvqVt+Ew==} + engines: {node: '>=18'} semver-diff@4.0.0: resolution: {integrity: sha512-0Ju4+6A8iOnpL/Thra7dZsSlOHYAHIeMxfhWQRI1/VLcT3WDBZKKtQt/QkBOsiIN9ZpuvHE6cGZ0x4glCMmfiA==} @@ -5315,17 +5467,13 @@ packages: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true - semver@7.7.3: - resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} + semver@7.7.4: + resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==} engines: {node: '>=10'} hasBin: true - send@0.19.0: - resolution: {integrity: sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==} - engines: {node: '>= 0.8.0'} - - send@0.19.1: - resolution: {integrity: sha512-p4rRk4f23ynFEfcD9LA0xRYngj+IyGiEYyqqOak8kaN0TvNmuxC2dcVeBn62GpCeR2CpWqyHCNScTP91QbAVFg==} + send@0.19.2: + resolution: {integrity: sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==} engines: {node: '>= 0.8.0'} serialize-javascript@6.0.2: @@ -5334,21 +5482,18 @@ packages: serve-handler@6.1.6: resolution: {integrity: sha512-x5RL9Y2p5+Sh3D38Fh9i/iQ5ZK+e4xuXRd/pGbM4D13tgo/MGwbttUk8emytcr1YYzBYs+apnUngBDFYfpjPuQ==} - serve-index@1.9.1: - resolution: {integrity: sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==} + serve-index@1.9.2: + resolution: {integrity: sha512-KDj11HScOaLmrPxl70KYNW1PksP4Nb/CLL2yvC+Qd2kHMPEEpfc4Re2e4FOay+bC/+XQl/7zAcWON3JVo5v3KQ==} engines: {node: '>= 0.8.0'} - serve-static@1.16.2: - resolution: {integrity: sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==} + serve-static@1.16.3: + resolution: {integrity: sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==} engines: {node: '>= 0.8.0'} set-function-length@1.2.2: resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} engines: {node: '>= 0.4'} - setprototypeof@1.1.0: - resolution: {integrity: sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==} - setprototypeof@1.2.0: resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} @@ -5486,10 +5631,6 @@ packages: resolution: {integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==} engines: {node: '>= 0.6'} - statuses@2.0.1: - resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} - engines: {node: '>= 0.8'} - statuses@2.0.2: resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} engines: {node: '>= 0.8'} @@ -5545,8 +5686,8 @@ packages: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} - strnum@1.1.2: - resolution: {integrity: sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA==} + strnum@2.1.2: + resolution: {integrity: sha512-l63NF9y/cLROq/yqKXSLtcMeeyOfnSQlfMSlzFt/K73oIaD8DGaQWd7Z34X9GPiKqP5rbSh84Hl4bOlLcjiSrQ==} style-to-js@1.1.21: resolution: {integrity: sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ==} @@ -5554,12 +5695,15 @@ packages: style-to-object@1.0.14: resolution: {integrity: sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==} - styled-components@6.1.19: - resolution: {integrity: sha512-1v/e3Dl1BknC37cXMhwGomhO8AkYmN41CqyX9xhUDxry1ns3BFQy2lLDRQXJRdVVWB9OHemv/53xaStimvWyuA==} + styled-components@6.3.11: + resolution: {integrity: sha512-opzgceGlQ5rdZdGwf9ddLW7EM2F4L7tgsgLn6fFzQ2JgE5EVQ4HZwNkcgB1p8WfOBx1GEZP3fa66ajJmtXhSrA==} engines: {node: '>= 16'} peerDependencies: react: '>= 16.8.0' react-dom: '>= 16.8.0' + peerDependenciesMeta: + react-dom: + optional: true stylehacks@6.1.1: resolution: {integrity: sha512-gSTTEQ670cJNoaeIp9KX6lZmm8LJ3jPB5yJmX8Zq/wQxOsAFXV3qjWzHas3YYk1qesuVIyYWWUpZ0vSE/dTSGg==} @@ -5567,8 +5711,8 @@ packages: peerDependencies: postcss: ^8.4.31 - stylis@4.3.2: - resolution: {integrity: sha512-bhtUjWd/z6ltJiQwg0dUfxEJ+W+jdqQd8TbWLWyeIJHlnsqmGLRFFd8e5mA0AZi/zx90smXRlN66YMTcaSFifg==} + stylis@4.3.6: + resolution: {integrity: sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ==} supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} @@ -5594,17 +5738,12 @@ packages: resolution: {integrity: sha512-upi/0ZGkYgEcLeGieoz8gT74oWHA0E7JivX7aN9mAf+Tc7BQoRBvnIGHoPDw+f9TXTW4s6kGYCZJtauP6OYp7g==} hasBin: true - swc-loader@0.2.6: - resolution: {integrity: sha512-9Zi9UP2YmDpgmQVbyOPJClY0dwf58JDyDMQ7uRc4krmc72twNI2fvlBWHLqVekBpPc7h5NJkGVT1zNDxFrqhvg==} + swc-loader@0.2.7: + resolution: {integrity: sha512-nwYWw3Fh9ame3Rtm7StS9SBLpHRRnYcK7bnpF3UKZmesAK0gw2/ADvlURFAINmPvKtDLzp+GBiP9yLoEjg6S9w==} peerDependencies: '@swc/core': ^1.2.147 webpack: '>=2' - swr@2.3.7: - resolution: {integrity: sha512-ZEquQ82QvalqTxhBVv/DlAg2mbmUjF4UgpPg9wwk4ufb9rQnZXh1iKyyKBqV6bQGu1Ie7L1QwSYO07qFIa1p+g==} - peerDependencies: - react: ^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - symbol-tree@3.2.4: resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} @@ -5628,8 +5767,8 @@ packages: uglify-js: optional: true - terser@5.44.1: - resolution: {integrity: sha512-t/R3R/n0MSwnnazuPpPNVO60LX0SKL45pyl9YlvxIdkH0Of7D5qM2EVe+yASRIlY5pZ73nclYJfNANGWPwFDZw==} + terser@5.46.0: + resolution: {integrity: sha512-jTwoImyr/QbOWFFso3YoU3ik0jBBDJ6JTOQiy/J2YxVJdZCc+5u7skhNwiOR3FQIygFqVUPHl7qbbxtjW2K3Qg==} engines: {node: '>=10'} hasBin: true @@ -5639,10 +5778,6 @@ packages: peerDependencies: tslib: ^2 - throttleit@2.1.0: - resolution: {integrity: sha512-nt6AMGKW1p/70DF/hGBdJB57B8Tspmbp5gfJ8ilhLnt7kkr2ye7hzD6NVG8GGErk2HWF34igrL2CXmNIkzKqKw==} - engines: {node: '>=18'} - thunky@1.1.0: resolution: {integrity: sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==} @@ -5656,11 +5791,11 @@ packages: resolution: {integrity: sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==} engines: {node: ^18.0.0 || >=20.0.0} - tldts-core@7.0.19: - resolution: {integrity: sha512-lJX2dEWx0SGH4O6p+7FPwYmJ/bu1JbcGJ8RLaG9b7liIgZ85itUVEPbMtWRVrde/0fnDPEPHW10ZsKW3kVsE9A==} + tldts-core@7.0.23: + resolution: {integrity: sha512-0g9vrtDQLrNIiCj22HSe9d4mLVG3g5ph5DZ8zCKBr4OtrspmNB6ss7hVyzArAeE88ceZocIEGkyW1Ime7fxPtQ==} - tldts@7.0.19: - resolution: {integrity: sha512-8PWx8tvC4jDB39BQw1m4x8y5MH1BcQ5xHeL2n7UVFulMPH/3Q0uiamahFJ3lXA0zO2SUyRXuVVbWSDmstlt9YA==} + tldts@7.0.23: + resolution: {integrity: sha512-ASdhgQIBSay0R/eXggAkQ53G4nTJqTXqC2kbaBbdDwM7SkjyZyO0OaaN1/FH7U/yCeqOHDwFO5j8+Os/IS1dXw==} hasBin: true to-regex-range@5.0.1: @@ -5702,12 +5837,16 @@ packages: trough@2.2.0: resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==} - tslib@2.6.2: - resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} + tslib@1.14.1: + resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + tsyringe@4.10.0: + resolution: {integrity: sha512-axr3IdNuVIxnaK5XGEUFTu3YmAQ6lllgrvqfEoR16g/HGnYY/6We4oWENtAnzK6/LpJ2ur9PAb80RBt7/U4ugw==} + engines: {node: '>= 6.0.0'} + type-fest@0.21.3: resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} engines: {node: '>=10'} @@ -5735,8 +5874,11 @@ packages: undici-types@7.16.0: resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} - undici@7.16.0: - resolution: {integrity: sha512-QEg3HPMll0o3t2ourKwOeUAZ159Kn9mx5pnzHRQO8+Wixmh88YdZRiIwat0iNzNNXn0yoEtXJqFpyW7eM8BV7g==} + undici-types@7.18.2: + resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} + + undici@7.22.0: + resolution: {integrity: sha512-RqslV2Us5BrllB+JeiZnK4peryVTndy9Dnqq62S3yYRRTj0tFQCwEniUy2167skdGOy3vqRzEvl1Dm4sV2ReDg==} engines: {node: '>=20.18.1'} unicode-canonical-property-names-ecmascript@2.0.1: @@ -5781,8 +5923,8 @@ packages: unist-util-visit-parents@6.0.2: resolution: {integrity: sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==} - unist-util-visit@5.0.0: - resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==} + unist-util-visit@5.1.0: + resolution: {integrity: sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==} universalify@2.0.1: resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} @@ -5792,8 +5934,8 @@ packages: resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} engines: {node: '>= 0.8'} - update-browserslist-db@1.2.2: - resolution: {integrity: sha512-E85pfNzMQ9jpKkA7+TJAi4TJN+tBCuWh5rUcS/sv6cFi+1q9LYDwDI5dpUL0u/73EElyQ8d3TEaeW4sPedBqYA==} + update-browserslist-db@1.2.3: + resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} hasBin: true peerDependencies: browserslist: '>= 4.21.0' @@ -5861,8 +6003,8 @@ packages: resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} engines: {node: '>=18'} - watchpack@2.4.4: - resolution: {integrity: sha512-c5EGNOiyxxV5qmTtAB7rbiXxi1ooX1pQKMLX/MIabJjRA0SJBQOjKF+KSVfHkr9U1cADPon0mRiVe/riyaiDUA==} + watchpack@2.5.1: + resolution: {integrity: sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==} engines: {node: '>=10.13.0'} wbuf@1.7.3: @@ -5874,8 +6016,8 @@ packages: webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} - webidl-conversions@8.0.0: - resolution: {integrity: sha512-n4W4YFyz5JzOfQeA8oN7dUYpR+MBP3PIUsn2jLjWXwK5ASUzt0Jc/A5sAUZoCYFJRGF0FBKJ+1JjN43rNdsQzA==} + webidl-conversions@8.0.1: + resolution: {integrity: sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==} engines: {node: '>=20'} webpack-bundle-analyzer@4.10.2: @@ -5892,8 +6034,8 @@ packages: webpack: optional: true - webpack-dev-server@5.2.2: - resolution: {integrity: sha512-QcQ72gh8a+7JO63TAx/6XZf/CWhgMzu5m0QirvPfGvptOusAxG12w2+aua1Jkjr7hzaWDnJ2n6JFeexMHI+Zjg==} + webpack-dev-server@5.2.3: + resolution: {integrity: sha512-9Gyu2F7+bg4Vv+pjbovuYDhHX+mqdqITykfzdM9UyKqKHlsE5aAjRhR+oOEfXW5vBeu8tarzlJFIZva4ZjAdrQ==} engines: {node: '>= 18.12.0'} hasBin: true peerDependencies: @@ -5913,12 +6055,12 @@ packages: resolution: {integrity: sha512-hXXvrjtx2PLYx4qruKl+kyRSLc52V+cCvMxRjmKwoA+CBbbF5GfIBtR6kCvl0fYGqTUPKB+1ktVmTHqMOzgCBg==} engines: {node: '>=18.0.0'} - webpack-sources@3.3.3: - resolution: {integrity: sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==} + webpack-sources@3.3.4: + resolution: {integrity: sha512-7tP1PdV4vF+lYPnkMR0jMY5/la2ub5Fc/8VQrrU+lXkiM6C4TjVfGw7iKfyhnTQOsD+6Q/iKw0eFciziRgD58Q==} engines: {node: '>=10.13.0'} - webpack@5.103.0: - resolution: {integrity: sha512-HU1JOuV1OavsZ+mfigY0j8d1TgQgbZ6M+J75zDkpEAwYeXjWSqrGJtgnPblJjd/mAyTNQ7ygw0MiKOn6etz8yw==} + webpack@5.105.2: + resolution: {integrity: sha512-dRXm0a2qcHPUBEzVk8uph0xWSjV/xZxenQQbLwnwP7caQCYpqG1qddwlyEkIDkYn0K8tvmcrZ+bOrzoQ3HxCDw==} engines: {node: '>=10.13.0'} hasBin: true peerDependencies: @@ -5944,15 +6086,20 @@ packages: whatwg-encoding@3.1.1: resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} engines: {node: '>=18'} + deprecated: Use @exodus/bytes instead for a more spec-conformant and faster implementation whatwg-mimetype@4.0.0: resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} engines: {node: '>=18'} - whatwg-url@15.1.0: - resolution: {integrity: sha512-2ytDk0kiEj/yu90JOAp44PVPUkO9+jVhyf+SybKlRHSDlvOOZhdPIrr7xTH64l4WixO2cP+wQIcgujkGBPPz6g==} + whatwg-mimetype@5.0.0: + resolution: {integrity: sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==} engines: {node: '>=20'} + whatwg-url@16.0.1: + resolution: {integrity: sha512-1to4zXBxmXHV3IiSSEInrreIlu02vUOvrhxJJH5vcxYTBDAx51cqZiKdyTxlecdKNSjj8EcxGBxNf6Vg+945gw==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + whatwg-url@5.0.0: resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} @@ -5991,8 +6138,8 @@ packages: utf-8-validate: optional: true - ws@8.18.3: - resolution: {integrity: sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==} + ws@8.19.0: + resolution: {integrity: sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==} engines: {node: '>=10.0.0'} peerDependencies: bufferutil: ^4.0.1 @@ -6053,189 +6200,158 @@ packages: resolution: {integrity: sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==} engines: {node: '>=12.20'} - zod@4.1.13: - resolution: {integrity: sha512-AvvthqfqrAhNH9dnfmrfKzX5upOdjUVJYFqNSlkmGf64gRaTzlPwz99IHYnVs28qYAybvAlBV+H7pn0saFY4Ig==} - zwitch@2.0.4: resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} snapshots: - '@acemir/cssom@0.9.29': {} + '@acemir/cssom@0.9.31': {} - '@ai-sdk/gateway@2.0.21(zod@4.1.13)': + '@algolia/abtesting@1.15.0': dependencies: - '@ai-sdk/provider': 2.0.0 - '@ai-sdk/provider-utils': 3.0.19(zod@4.1.13) - '@vercel/oidc': 3.0.5 - zod: 4.1.13 + '@algolia/client-common': 5.49.0 + '@algolia/requester-browser-xhr': 5.49.0 + '@algolia/requester-fetch': 5.49.0 + '@algolia/requester-node-http': 5.49.0 - '@ai-sdk/provider-utils@3.0.19(zod@4.1.13)': + '@algolia/autocomplete-core@1.19.2(@algolia/client-search@5.49.0)(algoliasearch@5.49.0)(search-insights@2.17.3)': dependencies: - '@ai-sdk/provider': 2.0.0 - '@standard-schema/spec': 1.0.0 - eventsource-parser: 3.0.6 - zod: 4.1.13 - - '@ai-sdk/provider@2.0.0': - dependencies: - json-schema: 0.4.0 - - '@ai-sdk/react@2.0.115(react@19.2.3)(zod@4.1.13)': - dependencies: - '@ai-sdk/provider-utils': 3.0.19(zod@4.1.13) - ai: 5.0.113(zod@4.1.13) - react: 19.2.3 - swr: 2.3.7(react@19.2.3) - throttleit: 2.1.0 - optionalDependencies: - zod: 4.1.13 - - '@algolia/abtesting@1.12.0': - dependencies: - '@algolia/client-common': 5.46.0 - '@algolia/requester-browser-xhr': 5.46.0 - '@algolia/requester-fetch': 5.46.0 - '@algolia/requester-node-http': 5.46.0 - - '@algolia/autocomplete-core@1.19.2(@algolia/client-search@5.46.0)(algoliasearch@5.46.0)(search-insights@2.17.3)': - dependencies: - '@algolia/autocomplete-plugin-algolia-insights': 1.19.2(@algolia/client-search@5.46.0)(algoliasearch@5.46.0)(search-insights@2.17.3) - '@algolia/autocomplete-shared': 1.19.2(@algolia/client-search@5.46.0)(algoliasearch@5.46.0) + '@algolia/autocomplete-plugin-algolia-insights': 1.19.2(@algolia/client-search@5.49.0)(algoliasearch@5.49.0)(search-insights@2.17.3) + '@algolia/autocomplete-shared': 1.19.2(@algolia/client-search@5.49.0)(algoliasearch@5.49.0) transitivePeerDependencies: - '@algolia/client-search' - algoliasearch - search-insights - '@algolia/autocomplete-plugin-algolia-insights@1.19.2(@algolia/client-search@5.46.0)(algoliasearch@5.46.0)(search-insights@2.17.3)': + '@algolia/autocomplete-plugin-algolia-insights@1.19.2(@algolia/client-search@5.49.0)(algoliasearch@5.49.0)(search-insights@2.17.3)': dependencies: - '@algolia/autocomplete-shared': 1.19.2(@algolia/client-search@5.46.0)(algoliasearch@5.46.0) + '@algolia/autocomplete-shared': 1.19.2(@algolia/client-search@5.49.0)(algoliasearch@5.49.0) search-insights: 2.17.3 transitivePeerDependencies: - '@algolia/client-search' - algoliasearch - '@algolia/autocomplete-shared@1.19.2(@algolia/client-search@5.46.0)(algoliasearch@5.46.0)': + '@algolia/autocomplete-shared@1.19.2(@algolia/client-search@5.49.0)(algoliasearch@5.49.0)': dependencies: - '@algolia/client-search': 5.46.0 - algoliasearch: 5.46.0 + '@algolia/client-search': 5.49.0 + algoliasearch: 5.49.0 - '@algolia/client-abtesting@5.46.0': + '@algolia/client-abtesting@5.49.0': dependencies: - '@algolia/client-common': 5.46.0 - '@algolia/requester-browser-xhr': 5.46.0 - '@algolia/requester-fetch': 5.46.0 - '@algolia/requester-node-http': 5.46.0 + '@algolia/client-common': 5.49.0 + '@algolia/requester-browser-xhr': 5.49.0 + '@algolia/requester-fetch': 5.49.0 + '@algolia/requester-node-http': 5.49.0 - '@algolia/client-analytics@5.46.0': + '@algolia/client-analytics@5.49.0': dependencies: - '@algolia/client-common': 5.46.0 - '@algolia/requester-browser-xhr': 5.46.0 - '@algolia/requester-fetch': 5.46.0 - '@algolia/requester-node-http': 5.46.0 + '@algolia/client-common': 5.49.0 + '@algolia/requester-browser-xhr': 5.49.0 + '@algolia/requester-fetch': 5.49.0 + '@algolia/requester-node-http': 5.49.0 - '@algolia/client-common@5.46.0': {} + '@algolia/client-common@5.49.0': {} - '@algolia/client-insights@5.46.0': + '@algolia/client-insights@5.49.0': dependencies: - '@algolia/client-common': 5.46.0 - '@algolia/requester-browser-xhr': 5.46.0 - '@algolia/requester-fetch': 5.46.0 - '@algolia/requester-node-http': 5.46.0 + '@algolia/client-common': 5.49.0 + '@algolia/requester-browser-xhr': 5.49.0 + '@algolia/requester-fetch': 5.49.0 + '@algolia/requester-node-http': 5.49.0 - '@algolia/client-personalization@5.46.0': + '@algolia/client-personalization@5.49.0': dependencies: - '@algolia/client-common': 5.46.0 - '@algolia/requester-browser-xhr': 5.46.0 - '@algolia/requester-fetch': 5.46.0 - '@algolia/requester-node-http': 5.46.0 + '@algolia/client-common': 5.49.0 + '@algolia/requester-browser-xhr': 5.49.0 + '@algolia/requester-fetch': 5.49.0 + '@algolia/requester-node-http': 5.49.0 - '@algolia/client-query-suggestions@5.46.0': + '@algolia/client-query-suggestions@5.49.0': dependencies: - '@algolia/client-common': 5.46.0 - '@algolia/requester-browser-xhr': 5.46.0 - '@algolia/requester-fetch': 5.46.0 - '@algolia/requester-node-http': 5.46.0 + '@algolia/client-common': 5.49.0 + '@algolia/requester-browser-xhr': 5.49.0 + '@algolia/requester-fetch': 5.49.0 + '@algolia/requester-node-http': 5.49.0 - '@algolia/client-search@5.46.0': + '@algolia/client-search@5.49.0': dependencies: - '@algolia/client-common': 5.46.0 - '@algolia/requester-browser-xhr': 5.46.0 - '@algolia/requester-fetch': 5.46.0 - '@algolia/requester-node-http': 5.46.0 + '@algolia/client-common': 5.49.0 + '@algolia/requester-browser-xhr': 5.49.0 + '@algolia/requester-fetch': 5.49.0 + '@algolia/requester-node-http': 5.49.0 '@algolia/events@4.0.1': {} - '@algolia/ingestion@1.46.0': + '@algolia/ingestion@1.49.0': dependencies: - '@algolia/client-common': 5.46.0 - '@algolia/requester-browser-xhr': 5.46.0 - '@algolia/requester-fetch': 5.46.0 - '@algolia/requester-node-http': 5.46.0 + '@algolia/client-common': 5.49.0 + '@algolia/requester-browser-xhr': 5.49.0 + '@algolia/requester-fetch': 5.49.0 + '@algolia/requester-node-http': 5.49.0 - '@algolia/monitoring@1.46.0': + '@algolia/monitoring@1.49.0': dependencies: - '@algolia/client-common': 5.46.0 - '@algolia/requester-browser-xhr': 5.46.0 - '@algolia/requester-fetch': 5.46.0 - '@algolia/requester-node-http': 5.46.0 + '@algolia/client-common': 5.49.0 + '@algolia/requester-browser-xhr': 5.49.0 + '@algolia/requester-fetch': 5.49.0 + '@algolia/requester-node-http': 5.49.0 - '@algolia/recommend@5.46.0': + '@algolia/recommend@5.49.0': dependencies: - '@algolia/client-common': 5.46.0 - '@algolia/requester-browser-xhr': 5.46.0 - '@algolia/requester-fetch': 5.46.0 - '@algolia/requester-node-http': 5.46.0 + '@algolia/client-common': 5.49.0 + '@algolia/requester-browser-xhr': 5.49.0 + '@algolia/requester-fetch': 5.49.0 + '@algolia/requester-node-http': 5.49.0 - '@algolia/requester-browser-xhr@5.46.0': + '@algolia/requester-browser-xhr@5.49.0': dependencies: - '@algolia/client-common': 5.46.0 + '@algolia/client-common': 5.49.0 - '@algolia/requester-fetch@5.46.0': + '@algolia/requester-fetch@5.49.0': dependencies: - '@algolia/client-common': 5.46.0 + '@algolia/client-common': 5.49.0 - '@algolia/requester-node-http@5.46.0': + '@algolia/requester-node-http@5.49.0': dependencies: - '@algolia/client-common': 5.46.0 + '@algolia/client-common': 5.49.0 - '@asamuzakjp/css-color@4.1.0': + '@asamuzakjp/css-color@5.0.0': dependencies: - '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) - '@csstools/css-color-parser': 3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) - '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) - '@csstools/css-tokenizer': 3.0.4 - lru-cache: 11.2.4 + '@csstools/css-calc': 3.1.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-color-parser': 4.0.2(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + lru-cache: 11.2.6 - '@asamuzakjp/dom-selector@6.7.6': + '@asamuzakjp/dom-selector@6.8.1': dependencies: '@asamuzakjp/nwsapi': 2.3.9 bidi-js: 1.0.3 css-tree: 3.1.0 is-potential-custom-element-name: 1.0.1 - lru-cache: 11.2.4 + lru-cache: 11.2.6 '@asamuzakjp/nwsapi@2.3.9': {} - '@babel/code-frame@7.27.1': + '@babel/code-frame@7.29.0': dependencies: '@babel/helper-validator-identifier': 7.28.5 js-tokens: 4.0.0 picocolors: 1.1.1 - '@babel/compat-data@7.28.5': {} + '@babel/compat-data@7.29.0': {} - '@babel/core@7.28.5': + '@babel/core@7.29.0': dependencies: - '@babel/code-frame': 7.27.1 - '@babel/generator': 7.28.5 - '@babel/helper-compilation-targets': 7.27.2 - '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5) - '@babel/helpers': 7.28.4 - '@babel/parser': 7.28.5 - '@babel/template': 7.27.2 - '@babel/traverse': 7.28.5 - '@babel/types': 7.28.5 + '@babel/code-frame': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) + '@babel/helpers': 7.28.6 + '@babel/parser': 7.29.0 + '@babel/template': 7.28.6 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 '@jridgewell/remapping': 2.3.5 convert-source-map: 2.0.0 debug: 4.4.3 @@ -6245,51 +6361,51 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/generator@7.28.5': + '@babel/generator@7.29.1': dependencies: - '@babel/parser': 7.28.5 - '@babel/types': 7.28.5 + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 '@jridgewell/gen-mapping': 0.3.13 '@jridgewell/trace-mapping': 0.3.31 jsesc: 3.1.0 '@babel/helper-annotate-as-pure@7.27.3': dependencies: - '@babel/types': 7.28.5 + '@babel/types': 7.29.0 - '@babel/helper-compilation-targets@7.27.2': + '@babel/helper-compilation-targets@7.28.6': dependencies: - '@babel/compat-data': 7.28.5 + '@babel/compat-data': 7.29.0 '@babel/helper-validator-option': 7.27.1 browserslist: 4.28.1 lru-cache: 5.1.1 semver: 6.3.1 - '@babel/helper-create-class-features-plugin@7.28.5(@babel/core@7.28.5)': + '@babel/helper-create-class-features-plugin@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 + '@babel/core': 7.29.0 '@babel/helper-annotate-as-pure': 7.27.3 '@babel/helper-member-expression-to-functions': 7.28.5 '@babel/helper-optimise-call-expression': 7.27.1 - '@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.5) + '@babel/helper-replace-supers': 7.28.6(@babel/core@7.29.0) '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/traverse': 7.28.5 + '@babel/traverse': 7.29.0 semver: 6.3.1 transitivePeerDependencies: - supports-color - '@babel/helper-create-regexp-features-plugin@7.28.5(@babel/core@7.28.5)': + '@babel/helper-create-regexp-features-plugin@7.28.5(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 + '@babel/core': 7.29.0 '@babel/helper-annotate-as-pure': 7.27.3 regexpu-core: 6.4.0 semver: 6.3.1 - '@babel/helper-define-polyfill-provider@0.6.5(@babel/core@7.28.5)': + '@babel/helper-define-polyfill-provider@0.6.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-compilation-targets': 7.27.2 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 debug: 4.4.3 lodash.debounce: 4.0.8 resolve: 1.22.11 @@ -6300,55 +6416,55 @@ snapshots: '@babel/helper-member-expression-to-functions@7.28.5': dependencies: - '@babel/traverse': 7.28.5 - '@babel/types': 7.28.5 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 transitivePeerDependencies: - supports-color - '@babel/helper-module-imports@7.27.1': + '@babel/helper-module-imports@7.28.6': dependencies: - '@babel/traverse': 7.28.5 - '@babel/types': 7.28.5 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 transitivePeerDependencies: - supports-color - '@babel/helper-module-transforms@7.28.3(@babel/core@7.28.5)': + '@babel/helper-module-transforms@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-module-imports': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-module-imports': 7.28.6 '@babel/helper-validator-identifier': 7.28.5 - '@babel/traverse': 7.28.5 + '@babel/traverse': 7.29.0 transitivePeerDependencies: - supports-color '@babel/helper-optimise-call-expression@7.27.1': dependencies: - '@babel/types': 7.28.5 + '@babel/types': 7.29.0 - '@babel/helper-plugin-utils@7.27.1': {} + '@babel/helper-plugin-utils@7.28.6': {} - '@babel/helper-remap-async-to-generator@7.27.1(@babel/core@7.28.5)': + '@babel/helper-remap-async-to-generator@7.27.1(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 + '@babel/core': 7.29.0 '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-wrap-function': 7.28.3 - '@babel/traverse': 7.28.5 + '@babel/helper-wrap-function': 7.28.6 + '@babel/traverse': 7.29.0 transitivePeerDependencies: - supports-color - '@babel/helper-replace-supers@7.27.1(@babel/core@7.28.5)': + '@babel/helper-replace-supers@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 + '@babel/core': 7.29.0 '@babel/helper-member-expression-to-functions': 7.28.5 '@babel/helper-optimise-call-expression': 7.27.1 - '@babel/traverse': 7.28.5 + '@babel/traverse': 7.29.0 transitivePeerDependencies: - supports-color '@babel/helper-skip-transparent-expression-wrappers@7.27.1': dependencies: - '@babel/traverse': 7.28.5 - '@babel/types': 7.28.5 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 transitivePeerDependencies: - supports-color @@ -6358,618 +6474,622 @@ snapshots: '@babel/helper-validator-option@7.27.1': {} - '@babel/helper-wrap-function@7.28.3': + '@babel/helper-wrap-function@7.28.6': dependencies: - '@babel/template': 7.27.2 - '@babel/traverse': 7.28.5 - '@babel/types': 7.28.5 + '@babel/template': 7.28.6 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 transitivePeerDependencies: - supports-color - '@babel/helpers@7.28.4': + '@babel/helpers@7.28.6': dependencies: - '@babel/template': 7.27.2 - '@babel/types': 7.28.5 + '@babel/template': 7.28.6 + '@babel/types': 7.29.0 - '@babel/parser@7.28.5': + '@babel/parser@7.29.0': dependencies: - '@babel/types': 7.28.5 + '@babel/types': 7.29.0 - '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.28.5(@babel/core@7.28.5)': + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.28.5(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/traverse': 7.28.5 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/traverse': 7.29.0 transitivePeerDependencies: - supports-color - '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.27.1(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.27.1(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.27.1(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/plugin-transform-optional-chaining': 7.28.5(@babel/core@7.28.5) + '@babel/plugin-transform-optional-chaining': 7.28.6(@babel/core@7.29.0) transitivePeerDependencies: - supports-color - '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.28.3(@babel/core@7.28.5)': + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/traverse': 7.28.5 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/traverse': 7.29.0 transitivePeerDependencies: - supports-color - '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.28.5)': + '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 + '@babel/core': 7.29.0 - '@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.28.5)': + '@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-import-assertions@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-syntax-import-assertions@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-import-attributes@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-syntax-import-attributes@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-jsx@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-typescript@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-syntax-typescript@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.28.5)': + '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-arrow-functions@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-arrow-functions@7.27.1(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-async-generator-functions@7.28.0(@babel/core@7.28.5)': + '@babel/plugin-transform-async-generator-functions@7.29.0(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-remap-async-to-generator': 7.27.1(@babel/core@7.28.5) - '@babel/traverse': 7.28.5 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-remap-async-to-generator': 7.27.1(@babel/core@7.29.0) + '@babel/traverse': 7.29.0 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-async-to-generator@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-async-to-generator@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-module-imports': 7.27.1 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-remap-async-to-generator': 7.27.1(@babel/core@7.28.5) + '@babel/core': 7.29.0 + '@babel/helper-module-imports': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-remap-async-to-generator': 7.27.1(@babel/core@7.29.0) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-block-scoped-functions@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-block-scoped-functions@7.27.1(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-block-scoping@7.28.5(@babel/core@7.28.5)': + '@babel/plugin-transform-block-scoping@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-class-properties@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-class-properties@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-class-static-block@7.28.3(@babel/core@7.28.5)': + '@babel/plugin-transform-class-static-block@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-classes@7.28.4(@babel/core@7.28.5)': + '@babel/plugin-transform-classes@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 + '@babel/core': 7.29.0 '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-compilation-targets': 7.27.2 + '@babel/helper-compilation-targets': 7.28.6 '@babel/helper-globals': 7.28.0 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.5) - '@babel/traverse': 7.28.5 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-replace-supers': 7.28.6(@babel/core@7.29.0) + '@babel/traverse': 7.29.0 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-computed-properties@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-computed-properties@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/template': 7.27.2 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/template': 7.28.6 - '@babel/plugin-transform-destructuring@7.28.5(@babel/core@7.28.5)': + '@babel/plugin-transform-destructuring@7.28.5(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/traverse': 7.28.5 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/traverse': 7.29.0 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-dotall-regex@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-dotall-regex@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-duplicate-keys@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-duplicate-keys@7.27.1(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.29.0(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-dynamic-import@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-dynamic-import@7.27.1(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-explicit-resource-management@7.28.0(@babel/core@7.28.5)': + '@babel/plugin-transform-explicit-resource-management@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.28.5) + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.29.0) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-exponentiation-operator@7.28.5(@babel/core@7.28.5)': + '@babel/plugin-transform-exponentiation-operator@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-export-namespace-from@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-export-namespace-from@7.27.1(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-for-of@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-for-of@7.27.1(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-function-name@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-function-name@7.27.1(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-compilation-targets': 7.27.2 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/traverse': 7.28.5 + '@babel/core': 7.29.0 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/traverse': 7.29.0 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-json-strings@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-json-strings@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-literals@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-literals@7.27.1(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-logical-assignment-operators@7.28.5(@babel/core@7.28.5)': + '@babel/plugin-transform-logical-assignment-operators@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-member-expression-literals@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-member-expression-literals@7.27.1(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-modules-amd@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-modules-amd@7.27.1(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-modules-commonjs@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-modules-commonjs@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-modules-systemjs@7.28.5(@babel/core@7.28.5)': + '@babel/plugin-transform-modules-systemjs@7.29.0(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 '@babel/helper-validator-identifier': 7.28.5 - '@babel/traverse': 7.28.5 + '@babel/traverse': 7.29.0 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-modules-umd@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-modules-umd@7.27.1(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-named-capturing-groups-regex@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-named-capturing-groups-regex@7.29.0(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-new-target@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-new-target@7.27.1(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-nullish-coalescing-operator@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-nullish-coalescing-operator@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-numeric-separator@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-numeric-separator@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-object-rest-spread@7.28.4(@babel/core@7.28.5)': + '@babel/plugin-transform-object-rest-spread@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-compilation-targets': 7.27.2 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.28.5) - '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.28.5) - '@babel/traverse': 7.28.5 + '@babel/core': 7.29.0 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.29.0) + '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.29.0) + '@babel/traverse': 7.29.0 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-object-super@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-object-super@7.27.1(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.5) + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-replace-supers': 7.28.6(@babel/core@7.29.0) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-optional-catch-binding@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-optional-catch-binding@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-optional-chaining@7.28.5(@babel/core@7.28.5)': + '@babel/plugin-transform-optional-chaining@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-parameters@7.27.7(@babel/core@7.28.5)': + '@babel/plugin-transform-parameters@7.27.7(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-private-methods@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-private-methods@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-private-property-in-object@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-private-property-in-object@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 + '@babel/core': 7.29.0 '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-property-literals@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-property-literals@7.27.1(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-react-constant-elements@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-react-constant-elements@7.27.1(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-react-display-name@7.28.0(@babel/core@7.28.5)': + '@babel/plugin-transform-react-display-name@7.28.0(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-react-jsx-development@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-react-jsx-development@7.27.1(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/plugin-transform-react-jsx': 7.27.1(@babel/core@7.28.5) + '@babel/core': 7.29.0 + '@babel/plugin-transform-react-jsx': 7.28.6(@babel/core@7.29.0) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-react-jsx@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-react-jsx@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 + '@babel/core': 7.29.0 '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-module-imports': 7.27.1 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.5) - '@babel/types': 7.28.5 + '@babel/helper-module-imports': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0) + '@babel/types': 7.29.0 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-react-pure-annotations@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-react-pure-annotations@7.27.1(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 + '@babel/core': 7.29.0 '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-regenerator@7.28.4(@babel/core@7.28.5)': + '@babel/plugin-transform-regenerator@7.29.0(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-regexp-modifiers@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-regexp-modifiers@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-reserved-words@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-reserved-words@7.27.1(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-runtime@7.28.5(@babel/core@7.28.5)': + '@babel/plugin-transform-runtime@7.29.0(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-module-imports': 7.27.1 - '@babel/helper-plugin-utils': 7.27.1 - babel-plugin-polyfill-corejs2: 0.4.14(@babel/core@7.28.5) - babel-plugin-polyfill-corejs3: 0.13.0(@babel/core@7.28.5) - babel-plugin-polyfill-regenerator: 0.6.5(@babel/core@7.28.5) + '@babel/core': 7.29.0 + '@babel/helper-module-imports': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 + babel-plugin-polyfill-corejs2: 0.4.15(@babel/core@7.29.0) + babel-plugin-polyfill-corejs3: 0.13.0(@babel/core@7.29.0) + babel-plugin-polyfill-regenerator: 0.6.6(@babel/core@7.29.0) semver: 6.3.1 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-shorthand-properties@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-shorthand-properties@7.27.1(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-spread@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-spread@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-sticky-regex@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-sticky-regex@7.27.1(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-template-literals@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-template-literals@7.27.1(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-typeof-symbol@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-typeof-symbol@7.27.1(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-typescript@7.28.5(@babel/core@7.28.5)': + '@babel/plugin-transform-typescript@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 + '@babel/core': 7.29.0 '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.29.0) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-unicode-escapes@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-unicode-escapes@7.27.1(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-unicode-property-regex@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-unicode-property-regex@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-unicode-regex@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-unicode-regex@7.27.1(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-unicode-sets-regex@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-unicode-sets-regex@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 - '@babel/preset-env@7.28.5(@babel/core@7.28.5)': + '@babel/preset-env@7.29.0(@babel/core@7.29.0)': dependencies: - '@babel/compat-data': 7.28.5 - '@babel/core': 7.28.5 - '@babel/helper-compilation-targets': 7.27.2 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/compat-data': 7.29.0 + '@babel/core': 7.29.0 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 '@babel/helper-validator-option': 7.27.1 - '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.28.5(@babel/core@7.28.5) - '@babel/plugin-bugfix-safari-class-field-initializer-scope': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.28.3(@babel/core@7.28.5) - '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.28.5) - '@babel/plugin-syntax-import-assertions': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-syntax-import-attributes': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.28.5) - '@babel/plugin-transform-arrow-functions': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-async-generator-functions': 7.28.0(@babel/core@7.28.5) - '@babel/plugin-transform-async-to-generator': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-block-scoped-functions': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-block-scoping': 7.28.5(@babel/core@7.28.5) - '@babel/plugin-transform-class-properties': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-class-static-block': 7.28.3(@babel/core@7.28.5) - '@babel/plugin-transform-classes': 7.28.4(@babel/core@7.28.5) - '@babel/plugin-transform-computed-properties': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.28.5) - '@babel/plugin-transform-dotall-regex': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-duplicate-keys': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-duplicate-named-capturing-groups-regex': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-dynamic-import': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-explicit-resource-management': 7.28.0(@babel/core@7.28.5) - '@babel/plugin-transform-exponentiation-operator': 7.28.5(@babel/core@7.28.5) - '@babel/plugin-transform-export-namespace-from': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-for-of': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-function-name': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-json-strings': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-literals': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-logical-assignment-operators': 7.28.5(@babel/core@7.28.5) - '@babel/plugin-transform-member-expression-literals': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-modules-amd': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-modules-commonjs': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-modules-systemjs': 7.28.5(@babel/core@7.28.5) - '@babel/plugin-transform-modules-umd': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-named-capturing-groups-regex': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-new-target': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-nullish-coalescing-operator': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-numeric-separator': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-object-rest-spread': 7.28.4(@babel/core@7.28.5) - '@babel/plugin-transform-object-super': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-optional-catch-binding': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-optional-chaining': 7.28.5(@babel/core@7.28.5) - '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.28.5) - '@babel/plugin-transform-private-methods': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-private-property-in-object': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-property-literals': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-regenerator': 7.28.4(@babel/core@7.28.5) - '@babel/plugin-transform-regexp-modifiers': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-reserved-words': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-shorthand-properties': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-spread': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-sticky-regex': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-template-literals': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-typeof-symbol': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-unicode-escapes': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-unicode-property-regex': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-unicode-regex': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-unicode-sets-regex': 7.27.1(@babel/core@7.28.5) - '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.28.5) - babel-plugin-polyfill-corejs2: 0.4.14(@babel/core@7.28.5) - babel-plugin-polyfill-corejs3: 0.13.0(@babel/core@7.28.5) - babel-plugin-polyfill-regenerator: 0.6.5(@babel/core@7.28.5) - core-js-compat: 3.47.0 + '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.28.5(@babel/core@7.29.0) + '@babel/plugin-bugfix-safari-class-field-initializer-scope': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.29.0) + '@babel/plugin-syntax-import-assertions': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-syntax-import-attributes': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.29.0) + '@babel/plugin-transform-arrow-functions': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-async-generator-functions': 7.29.0(@babel/core@7.29.0) + '@babel/plugin-transform-async-to-generator': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-block-scoped-functions': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-block-scoping': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-class-properties': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-class-static-block': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-classes': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-computed-properties': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.29.0) + '@babel/plugin-transform-dotall-regex': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-duplicate-keys': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-duplicate-named-capturing-groups-regex': 7.29.0(@babel/core@7.29.0) + '@babel/plugin-transform-dynamic-import': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-explicit-resource-management': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-exponentiation-operator': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-export-namespace-from': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-for-of': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-function-name': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-json-strings': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-literals': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-logical-assignment-operators': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-member-expression-literals': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-modules-amd': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-modules-commonjs': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-modules-systemjs': 7.29.0(@babel/core@7.29.0) + '@babel/plugin-transform-modules-umd': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-named-capturing-groups-regex': 7.29.0(@babel/core@7.29.0) + '@babel/plugin-transform-new-target': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-nullish-coalescing-operator': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-numeric-separator': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-object-rest-spread': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-object-super': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-optional-catch-binding': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-optional-chaining': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.29.0) + '@babel/plugin-transform-private-methods': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-private-property-in-object': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-property-literals': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-regenerator': 7.29.0(@babel/core@7.29.0) + '@babel/plugin-transform-regexp-modifiers': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-reserved-words': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-shorthand-properties': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-spread': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-sticky-regex': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-template-literals': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-typeof-symbol': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-unicode-escapes': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-unicode-property-regex': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-unicode-regex': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-unicode-sets-regex': 7.28.6(@babel/core@7.29.0) + '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.29.0) + babel-plugin-polyfill-corejs2: 0.4.15(@babel/core@7.29.0) + babel-plugin-polyfill-corejs3: 0.14.0(@babel/core@7.29.0) + babel-plugin-polyfill-regenerator: 0.6.6(@babel/core@7.29.0) + core-js-compat: 3.48.0 semver: 6.3.1 transitivePeerDependencies: - supports-color - '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.28.5)': + '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/types': 7.28.5 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/types': 7.29.0 esutils: 2.0.3 - '@babel/preset-react@7.28.5(@babel/core@7.28.5)': + '@babel/preset-react@7.28.5(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 '@babel/helper-validator-option': 7.27.1 - '@babel/plugin-transform-react-display-name': 7.28.0(@babel/core@7.28.5) - '@babel/plugin-transform-react-jsx': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-react-jsx-development': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-react-pure-annotations': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-react-display-name': 7.28.0(@babel/core@7.29.0) + '@babel/plugin-transform-react-jsx': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-react-jsx-development': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-react-pure-annotations': 7.27.1(@babel/core@7.29.0) transitivePeerDependencies: - supports-color - '@babel/preset-typescript@7.28.5(@babel/core@7.28.5)': + '@babel/preset-typescript@7.28.5(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 '@babel/helper-validator-option': 7.27.1 - '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-modules-commonjs': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-typescript': 7.28.5(@babel/core@7.28.5) + '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-modules-commonjs': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-typescript': 7.28.6(@babel/core@7.29.0) transitivePeerDependencies: - supports-color - '@babel/runtime-corejs3@7.28.4': + '@babel/runtime-corejs3@7.29.0': dependencies: - core-js-pure: 3.47.0 + core-js-pure: 3.48.0 - '@babel/runtime@7.28.4': {} + '@babel/runtime@7.28.6': {} - '@babel/template@7.27.2': + '@babel/template@7.28.6': dependencies: - '@babel/code-frame': 7.27.1 - '@babel/parser': 7.28.5 - '@babel/types': 7.28.5 + '@babel/code-frame': 7.29.0 + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 - '@babel/traverse@7.28.5': + '@babel/traverse@7.29.0': dependencies: - '@babel/code-frame': 7.27.1 - '@babel/generator': 7.28.5 + '@babel/code-frame': 7.29.0 + '@babel/generator': 7.29.1 '@babel/helper-globals': 7.28.0 - '@babel/parser': 7.28.5 - '@babel/template': 7.27.2 - '@babel/types': 7.28.5 + '@babel/parser': 7.29.0 + '@babel/template': 7.28.6 + '@babel/types': 7.29.0 debug: 4.4.3 transitivePeerDependencies: - supports-color - '@babel/types@7.28.5': + '@babel/types@7.29.0': dependencies: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.28.5 + '@bramus/specificity@2.4.2': + dependencies: + css-tree: 3.1.0 + '@colors/colors@1.5.0': optional: true @@ -6980,11 +7100,18 @@ snapshots: '@csstools/color-helpers@5.1.0': {} + '@csstools/color-helpers@6.0.2': {} + '@csstools/css-calc@2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)': dependencies: '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) '@csstools/css-tokenizer': 3.0.4 + '@csstools/css-calc@3.1.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': + dependencies: + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + '@csstools/css-color-parser@3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)': dependencies: '@csstools/color-helpers': 5.1.0 @@ -6992,16 +7119,27 @@ snapshots: '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) '@csstools/css-tokenizer': 3.0.4 + '@csstools/css-color-parser@4.0.2(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': + dependencies: + '@csstools/color-helpers': 6.0.2 + '@csstools/css-calc': 3.1.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + '@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4)': dependencies: '@csstools/css-tokenizer': 3.0.4 - '@csstools/css-syntax-patches-for-csstree@1.0.14(postcss@8.5.6)': + '@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0)': dependencies: - postcss: 8.5.6 + '@csstools/css-tokenizer': 4.0.0 + + '@csstools/css-syntax-patches-for-csstree@1.0.28': {} '@csstools/css-tokenizer@3.0.4': {} + '@csstools/css-tokenizer@4.0.0': {} + '@csstools/media-query-list-parser@4.0.3(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)': dependencies: '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) @@ -7182,7 +7320,7 @@ snapshots: postcss: 8.5.6 postcss-value-parser: 4.2.0 - '@csstools/postcss-normalize-display-values@4.0.0(postcss@8.5.6)': + '@csstools/postcss-normalize-display-values@4.0.1(postcss@8.5.6)': dependencies: postcss: 8.5.6 postcss-value-parser: 4.2.0 @@ -7205,6 +7343,12 @@ snapshots: postcss: 8.5.6 postcss-value-parser: 4.2.0 + '@csstools/postcss-property-rule-prelude-list@1.0.0(postcss@8.5.6)': + dependencies: + '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) + '@csstools/css-tokenizer': 3.0.4 + postcss: 8.5.6 + '@csstools/postcss-random-function@2.0.1(postcss@8.5.6)': dependencies: '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) @@ -7240,6 +7384,11 @@ snapshots: '@csstools/css-tokenizer': 3.0.4 postcss: 8.5.6 + '@csstools/postcss-syntax-descriptor-syntax-production@1.0.1(postcss@8.5.6)': + dependencies: + '@csstools/css-tokenizer': 3.0.4 + postcss: 8.5.6 + '@csstools/postcss-system-ui-font-family@1.0.0(postcss@8.5.6)': dependencies: '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) @@ -7277,48 +7426,44 @@ snapshots: '@discoveryjs/json-ext@0.5.7': {} - '@docsearch/core@4.3.1(@types/react@19.2.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + '@docsearch/core@4.6.0(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': optionalDependencies: - '@types/react': 19.2.7 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) + '@types/react': 19.2.14 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) - '@docsearch/css@4.3.2': {} + '@docsearch/css@4.6.0': {} - '@docsearch/react@4.3.2(@algolia/client-search@5.46.0)(@types/react@19.2.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(search-insights@2.17.3)': + '@docsearch/react@4.6.0(@algolia/client-search@5.49.0)(@types/react@19.2.14)(algoliasearch@5.49.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(search-insights@2.17.3)': dependencies: - '@ai-sdk/react': 2.0.115(react@19.2.3)(zod@4.1.13) - '@algolia/autocomplete-core': 1.19.2(@algolia/client-search@5.46.0)(algoliasearch@5.46.0)(search-insights@2.17.3) - '@docsearch/core': 4.3.1(@types/react@19.2.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@docsearch/css': 4.3.2 - ai: 5.0.113(zod@4.1.13) - algoliasearch: 5.46.0 - marked: 16.4.2 - zod: 4.1.13 + '@algolia/autocomplete-core': 1.19.2(@algolia/client-search@5.49.0)(algoliasearch@5.49.0)(search-insights@2.17.3) + '@docsearch/core': 4.6.0(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@docsearch/css': 4.6.0 optionalDependencies: - '@types/react': 19.2.7 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) + '@types/react': 19.2.14 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) search-insights: 2.17.3 transitivePeerDependencies: - '@algolia/client-search' + - algoliasearch - '@docusaurus/babel@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + '@docusaurus/babel@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@babel/core': 7.28.5 - '@babel/generator': 7.28.5 - '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.28.5) - '@babel/plugin-transform-runtime': 7.28.5(@babel/core@7.28.5) - '@babel/preset-env': 7.28.5(@babel/core@7.28.5) - '@babel/preset-react': 7.28.5(@babel/core@7.28.5) - '@babel/preset-typescript': 7.28.5(@babel/core@7.28.5) - '@babel/runtime': 7.28.4 - '@babel/runtime-corejs3': 7.28.4 - '@babel/traverse': 7.28.5 + '@babel/core': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-transform-runtime': 7.29.0(@babel/core@7.29.0) + '@babel/preset-env': 7.29.0(@babel/core@7.29.0) + '@babel/preset-react': 7.28.5(@babel/core@7.29.0) + '@babel/preset-typescript': 7.28.5(@babel/core@7.29.0) + '@babel/runtime': 7.28.6 + '@babel/runtime-corejs3': 7.29.0 + '@babel/traverse': 7.29.0 '@docusaurus/logger': 3.9.2 - '@docusaurus/utils': 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@docusaurus/utils': 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) babel-plugin-dynamic-import-node: 2.3.3 - fs-extra: 11.3.2 + fs-extra: 11.3.3 tslib: 2.8.1 transitivePeerDependencies: - '@swc/core' @@ -7329,34 +7474,34 @@ snapshots: - uglify-js - webpack-cli - '@docusaurus/bundler@3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@rspack/core@1.6.7)(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3)': + '@docusaurus/bundler@3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@rspack/core@1.7.6)(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)': dependencies: - '@babel/core': 7.28.5 - '@docusaurus/babel': 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@babel/core': 7.29.0 + '@docusaurus/babel': 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@docusaurus/cssnano-preset': 3.9.2 '@docusaurus/logger': 3.9.2 - '@docusaurus/types': 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@docusaurus/utils': 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - babel-loader: 9.2.1(@babel/core@7.28.5)(webpack@5.103.0(@swc/core@1.15.4)) + '@docusaurus/types': 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@docusaurus/utils': 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + babel-loader: 9.2.1(@babel/core@7.29.0)(webpack@5.105.2(@swc/core@1.15.11)) clean-css: 5.3.3 - copy-webpack-plugin: 11.0.0(webpack@5.103.0(@swc/core@1.15.4)) - css-loader: 6.11.0(@rspack/core@1.6.7)(webpack@5.103.0(@swc/core@1.15.4)) - css-minimizer-webpack-plugin: 5.0.1(clean-css@5.3.3)(webpack@5.103.0(@swc/core@1.15.4)) + copy-webpack-plugin: 11.0.0(webpack@5.105.2(@swc/core@1.15.11)) + css-loader: 6.11.0(@rspack/core@1.7.6)(webpack@5.105.2(@swc/core@1.15.11)) + css-minimizer-webpack-plugin: 5.0.1(clean-css@5.3.3)(webpack@5.105.2(@swc/core@1.15.11)) cssnano: 6.1.2(postcss@8.5.6) - file-loader: 6.2.0(webpack@5.103.0(@swc/core@1.15.4)) + file-loader: 6.2.0(webpack@5.105.2(@swc/core@1.15.11)) html-minifier-terser: 7.2.0 - mini-css-extract-plugin: 2.9.4(webpack@5.103.0(@swc/core@1.15.4)) - null-loader: 4.0.1(webpack@5.103.0(@swc/core@1.15.4)) + mini-css-extract-plugin: 2.10.0(webpack@5.105.2(@swc/core@1.15.11)) + null-loader: 4.0.1(webpack@5.105.2(@swc/core@1.15.11)) postcss: 8.5.6 - postcss-loader: 7.3.4(postcss@8.5.6)(typescript@5.9.3)(webpack@5.103.0(@swc/core@1.15.4)) - postcss-preset-env: 10.5.0(postcss@8.5.6) - terser-webpack-plugin: 5.3.16(@swc/core@1.15.4)(webpack@5.103.0(@swc/core@1.15.4)) + postcss-loader: 7.3.4(postcss@8.5.6)(typescript@5.9.3)(webpack@5.105.2(@swc/core@1.15.11)) + postcss-preset-env: 10.6.1(postcss@8.5.6) + terser-webpack-plugin: 5.3.16(@swc/core@1.15.11)(webpack@5.105.2(@swc/core@1.15.11)) tslib: 2.8.1 - url-loader: 4.1.1(file-loader@6.2.0(webpack@5.103.0(@swc/core@1.15.4)))(webpack@5.103.0(@swc/core@1.15.4)) - webpack: 5.103.0(@swc/core@1.15.4) - webpackbar: 6.0.1(webpack@5.103.0(@swc/core@1.15.4)) + url-loader: 4.1.1(file-loader@6.2.0(webpack@5.105.2(@swc/core@1.15.11)))(webpack@5.105.2(@swc/core@1.15.11)) + webpack: 5.105.2(@swc/core@1.15.11) + webpackbar: 6.0.1(webpack@5.105.2(@swc/core@1.15.11)) optionalDependencies: - '@docusaurus/faster': 3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)) + '@docusaurus/faster': 3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)) transitivePeerDependencies: - '@parcel/css' - '@rspack/core' @@ -7372,52 +7517,52 @@ snapshots: - uglify-js - webpack-cli - '@docusaurus/core@3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3))(@rspack/core@1.6.7)(@swc/core@1.15.4)(debug@4.4.3)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3)': + '@docusaurus/core@3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.4))(@rspack/core@1.7.6)(@swc/core@1.15.11)(debug@4.4.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)': dependencies: - '@docusaurus/babel': 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@docusaurus/bundler': 3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@rspack/core@1.6.7)(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3) + '@docusaurus/babel': 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@docusaurus/bundler': 3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@rspack/core@1.7.6)(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) '@docusaurus/logger': 3.9.2 - '@docusaurus/mdx-loader': 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@docusaurus/utils': 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@docusaurus/utils-common': 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@docusaurus/utils-validation': 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@mdx-js/react': 3.1.1(@types/react@19.2.7)(react@19.2.3) + '@docusaurus/mdx-loader': 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@docusaurus/utils': 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@docusaurus/utils-common': 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@docusaurus/utils-validation': 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@mdx-js/react': 3.1.1(@types/react@19.2.14)(react@19.2.4) boxen: 6.2.1 chalk: 4.1.2 chokidar: 3.6.0 cli-table3: 0.6.5 combine-promises: 1.2.0 commander: 5.1.0 - core-js: 3.47.0 + core-js: 3.48.0 detect-port: 1.6.1 escape-html: 1.0.3 eta: 2.2.0 eval: 0.1.8 execa: 5.1.1 - fs-extra: 11.3.2 + fs-extra: 11.3.3 html-tags: 3.3.1 - html-webpack-plugin: 5.6.5(@rspack/core@1.6.7)(webpack@5.103.0(@swc/core@1.15.4)) + html-webpack-plugin: 5.6.6(@rspack/core@1.7.6)(webpack@5.105.2(@swc/core@1.15.11)) leven: 3.1.0 - lodash: 4.17.21 + lodash: 4.17.23 open: 8.4.2 p-map: 4.0.0 prompts: 2.4.2 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - react-helmet-async: '@slorber/react-helmet-async@1.3.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)' - react-loadable: '@docusaurus/react-loadable@6.0.0(react@19.2.3)' - react-loadable-ssr-addon-v5-slorber: 1.0.1(@docusaurus/react-loadable@6.0.0(react@19.2.3))(webpack@5.103.0(@swc/core@1.15.4)) - react-router: 5.3.4(react@19.2.3) - react-router-config: 5.1.1(react-router@5.3.4(react@19.2.3))(react@19.2.3) - react-router-dom: 5.3.4(react@19.2.3) - semver: 7.7.3 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + react-helmet-async: '@slorber/react-helmet-async@1.3.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4)' + react-loadable: '@docusaurus/react-loadable@6.0.0(react@19.2.4)' + react-loadable-ssr-addon-v5-slorber: 1.0.1(@docusaurus/react-loadable@6.0.0(react@19.2.4))(webpack@5.105.2(@swc/core@1.15.11)) + react-router: 5.3.4(react@19.2.4) + react-router-config: 5.1.1(react-router@5.3.4(react@19.2.4))(react@19.2.4) + react-router-dom: 5.3.4(react@19.2.4) + semver: 7.7.4 serve-handler: 6.1.6 tinypool: 1.1.1 tslib: 2.8.1 update-notifier: 6.0.2 - webpack: 5.103.0(@swc/core@1.15.4) + webpack: 5.105.2(@swc/core@1.15.11) webpack-bundle-analyzer: 4.10.2 - webpack-dev-server: 5.2.2(debug@4.4.3)(webpack@5.103.0(@swc/core@1.15.4)) + webpack-dev-server: 5.2.3(debug@4.4.3)(tslib@2.8.1)(webpack@5.105.2(@swc/core@1.15.11)) webpack-merge: 6.0.1 transitivePeerDependencies: - '@docusaurus/faster' @@ -7443,17 +7588,17 @@ snapshots: postcss-sort-media-queries: 5.2.0(postcss@8.5.6) tslib: 2.8.1 - '@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))': + '@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))': dependencies: - '@docusaurus/types': 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@rspack/core': 1.6.7 - '@swc/core': 1.15.4 - '@swc/html': 1.15.4 + '@docusaurus/types': 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@rspack/core': 1.7.6 + '@swc/core': 1.15.11 + '@swc/html': 1.15.11 browserslist: 4.28.1 - lightningcss: 1.30.2 - swc-loader: 0.2.6(@swc/core@1.15.4)(webpack@5.103.0(@swc/core@1.15.4)) + lightningcss: 1.31.1 + swc-loader: 0.2.7(@swc/core@1.15.11)(webpack@5.105.2(@swc/core@1.15.11)) tslib: 2.8.1 - webpack: 5.103.0(@swc/core@1.15.4) + webpack: 5.105.2(@swc/core@1.15.11) transitivePeerDependencies: - '@swc/helpers' - esbuild @@ -7465,22 +7610,22 @@ snapshots: chalk: 4.1.2 tslib: 2.8.1 - '@docusaurus/mdx-loader@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + '@docusaurus/mdx-loader@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: '@docusaurus/logger': 3.9.2 - '@docusaurus/utils': 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@docusaurus/utils-validation': 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@docusaurus/utils': 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@docusaurus/utils-validation': 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@mdx-js/mdx': 3.1.1 '@slorber/remark-comment': 1.0.0 escape-html: 1.0.3 estree-util-value-to-estree: 3.5.0 - file-loader: 6.2.0(webpack@5.103.0(@swc/core@1.15.4)) - fs-extra: 11.3.2 + file-loader: 6.2.0(webpack@5.105.2(@swc/core@1.15.11)) + fs-extra: 11.3.3 image-size: 2.0.2 mdast-util-mdx: 3.0.0 mdast-util-to-string: 4.0.0 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) rehype-raw: 7.0.0 remark-directive: 3.0.1 remark-emoji: 4.0.1 @@ -7489,10 +7634,10 @@ snapshots: stringify-object: 3.3.0 tslib: 2.8.1 unified: 11.0.5 - unist-util-visit: 5.0.0 - url-loader: 4.1.1(file-loader@6.2.0(webpack@5.103.0(@swc/core@1.15.4)))(webpack@5.103.0(@swc/core@1.15.4)) + unist-util-visit: 5.1.0 + url-loader: 4.1.1(file-loader@6.2.0(webpack@5.105.2(@swc/core@1.15.11)))(webpack@5.105.2(@swc/core@1.15.11)) vfile: 6.0.3 - webpack: 5.103.0(@swc/core@1.15.4) + webpack: 5.105.2(@swc/core@1.15.11) transitivePeerDependencies: - '@swc/core' - esbuild @@ -7500,17 +7645,17 @@ snapshots: - uglify-js - webpack-cli - '@docusaurus/module-type-aliases@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + '@docusaurus/module-type-aliases@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@docusaurus/types': 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@docusaurus/types': 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@types/history': 4.7.11 - '@types/react': 19.2.7 + '@types/react': 19.2.14 '@types/react-router-config': 5.0.11 '@types/react-router-dom': 5.3.3 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - react-helmet-async: '@slorber/react-helmet-async@1.3.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)' - react-loadable: '@docusaurus/react-loadable@6.0.0(react@19.2.3)' + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + react-helmet-async: '@slorber/react-helmet-async@1.3.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4)' + react-loadable: '@docusaurus/react-loadable@6.0.0(react@19.2.4)' transitivePeerDependencies: - '@swc/core' - esbuild @@ -7518,29 +7663,29 @@ snapshots: - uglify-js - webpack-cli - '@docusaurus/plugin-content-blog@3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@docusaurus/plugin-content-docs@3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3))(@rspack/core@1.6.7)(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3))(@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3))(@rspack/core@1.6.7)(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3)': + '@docusaurus/plugin-content-blog@3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@docusaurus/plugin-content-docs@3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.4))(@rspack/core@1.7.6)(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.4))(@rspack/core@1.7.6)(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)': dependencies: - '@docusaurus/core': 3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3))(@rspack/core@1.6.7)(@swc/core@1.15.4)(debug@4.4.3)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3) + '@docusaurus/core': 3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.4))(@rspack/core@1.7.6)(@swc/core@1.15.11)(debug@4.4.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) '@docusaurus/logger': 3.9.2 - '@docusaurus/mdx-loader': 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@docusaurus/plugin-content-docs': 3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3))(@rspack/core@1.6.7)(@swc/core@1.15.4)(debug@4.4.3)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3) - '@docusaurus/theme-common': 3.9.2(@docusaurus/plugin-content-docs@3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3))(@rspack/core@1.6.7)(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3))(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@docusaurus/types': 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@docusaurus/utils': 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@docusaurus/utils-common': 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@docusaurus/utils-validation': 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@docusaurus/mdx-loader': 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@docusaurus/plugin-content-docs': 3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.4))(@rspack/core@1.7.6)(@swc/core@1.15.11)(debug@4.4.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) + '@docusaurus/theme-common': 3.9.2(@docusaurus/plugin-content-docs@3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.4))(@rspack/core@1.7.6)(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@docusaurus/types': 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@docusaurus/utils': 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@docusaurus/utils-common': 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@docusaurus/utils-validation': 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) cheerio: 1.0.0-rc.12 feed: 4.2.2 - fs-extra: 11.3.2 - lodash: 4.17.21 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) + fs-extra: 11.3.3 + lodash: 4.17.23 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) schema-dts: 1.1.5 srcset: 4.0.0 tslib: 2.8.1 - unist-util-visit: 5.0.0 + unist-util-visit: 5.1.0 utility-types: 3.11.0 - webpack: 5.103.0(@swc/core@1.15.4) + webpack: 5.105.2(@swc/core@1.15.11) transitivePeerDependencies: - '@docusaurus/faster' - '@mdx-js/react' @@ -7559,28 +7704,28 @@ snapshots: - utf-8-validate - webpack-cli - '@docusaurus/plugin-content-docs@3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3))(@rspack/core@1.6.7)(@swc/core@1.15.4)(debug@4.4.3)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3)': + '@docusaurus/plugin-content-docs@3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.4))(@rspack/core@1.7.6)(@swc/core@1.15.11)(debug@4.4.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)': dependencies: - '@docusaurus/core': 3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3))(@rspack/core@1.6.7)(@swc/core@1.15.4)(debug@4.4.3)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3) + '@docusaurus/core': 3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.4))(@rspack/core@1.7.6)(@swc/core@1.15.11)(debug@4.4.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) '@docusaurus/logger': 3.9.2 - '@docusaurus/mdx-loader': 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@docusaurus/module-type-aliases': 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@docusaurus/theme-common': 3.9.2(@docusaurus/plugin-content-docs@3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3))(@rspack/core@1.6.7)(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3))(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@docusaurus/types': 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@docusaurus/utils': 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@docusaurus/utils-common': 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@docusaurus/utils-validation': 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@docusaurus/mdx-loader': 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@docusaurus/module-type-aliases': 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@docusaurus/theme-common': 3.9.2(@docusaurus/plugin-content-docs@3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.4))(@rspack/core@1.7.6)(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@docusaurus/types': 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@docusaurus/utils': 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@docusaurus/utils-common': 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@docusaurus/utils-validation': 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@types/react-router-config': 5.0.11 combine-promises: 1.2.0 - fs-extra: 11.3.2 + fs-extra: 11.3.3 js-yaml: 4.1.1 - lodash: 4.17.21 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) + lodash: 4.17.23 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) schema-dts: 1.1.5 tslib: 2.8.1 utility-types: 3.11.0 - webpack: 5.103.0(@swc/core@1.15.4) + webpack: 5.105.2(@swc/core@1.15.11) transitivePeerDependencies: - '@docusaurus/faster' - '@mdx-js/react' @@ -7599,18 +7744,18 @@ snapshots: - utf-8-validate - webpack-cli - '@docusaurus/plugin-content-pages@3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3))(@rspack/core@1.6.7)(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3)': + '@docusaurus/plugin-content-pages@3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.4))(@rspack/core@1.7.6)(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)': dependencies: - '@docusaurus/core': 3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3))(@rspack/core@1.6.7)(@swc/core@1.15.4)(debug@4.4.3)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3) - '@docusaurus/mdx-loader': 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@docusaurus/types': 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@docusaurus/utils': 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@docusaurus/utils-validation': 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - fs-extra: 11.3.2 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) + '@docusaurus/core': 3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.4))(@rspack/core@1.7.6)(@swc/core@1.15.11)(debug@4.4.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) + '@docusaurus/mdx-loader': 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@docusaurus/types': 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@docusaurus/utils': 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@docusaurus/utils-validation': 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + fs-extra: 11.3.3 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) tslib: 2.8.1 - webpack: 5.103.0(@swc/core@1.15.4) + webpack: 5.105.2(@swc/core@1.15.11) transitivePeerDependencies: - '@docusaurus/faster' - '@mdx-js/react' @@ -7629,12 +7774,12 @@ snapshots: - utf-8-validate - webpack-cli - '@docusaurus/plugin-css-cascade-layers@3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3))(@rspack/core@1.6.7)(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3)': + '@docusaurus/plugin-css-cascade-layers@3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.4))(@rspack/core@1.7.6)(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)': dependencies: - '@docusaurus/core': 3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3))(@rspack/core@1.6.7)(@swc/core@1.15.4)(debug@4.4.3)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3) - '@docusaurus/types': 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@docusaurus/utils': 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@docusaurus/utils-validation': 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@docusaurus/core': 3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.4))(@rspack/core@1.7.6)(@swc/core@1.15.11)(debug@4.4.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) + '@docusaurus/types': 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@docusaurus/utils': 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@docusaurus/utils-validation': 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) tslib: 2.8.1 transitivePeerDependencies: - '@docusaurus/faster' @@ -7656,15 +7801,15 @@ snapshots: - utf-8-validate - webpack-cli - '@docusaurus/plugin-debug@3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3))(@rspack/core@1.6.7)(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3)': + '@docusaurus/plugin-debug@3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.4))(@rspack/core@1.7.6)(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)': dependencies: - '@docusaurus/core': 3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3))(@rspack/core@1.6.7)(@swc/core@1.15.4)(debug@4.4.3)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3) - '@docusaurus/types': 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@docusaurus/utils': 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - fs-extra: 11.3.2 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - react-json-view-lite: 2.5.0(react@19.2.3) + '@docusaurus/core': 3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.4))(@rspack/core@1.7.6)(@swc/core@1.15.11)(debug@4.4.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) + '@docusaurus/types': 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@docusaurus/utils': 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + fs-extra: 11.3.3 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + react-json-view-lite: 2.5.0(react@19.2.4) tslib: 2.8.1 transitivePeerDependencies: - '@docusaurus/faster' @@ -7684,13 +7829,13 @@ snapshots: - utf-8-validate - webpack-cli - '@docusaurus/plugin-google-analytics@3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3))(@rspack/core@1.6.7)(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3)': + '@docusaurus/plugin-google-analytics@3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.4))(@rspack/core@1.7.6)(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)': dependencies: - '@docusaurus/core': 3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3))(@rspack/core@1.6.7)(@swc/core@1.15.4)(debug@4.4.3)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3) - '@docusaurus/types': 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@docusaurus/utils-validation': 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) + '@docusaurus/core': 3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.4))(@rspack/core@1.7.6)(@swc/core@1.15.11)(debug@4.4.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) + '@docusaurus/types': 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@docusaurus/utils-validation': 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) tslib: 2.8.1 transitivePeerDependencies: - '@docusaurus/faster' @@ -7710,14 +7855,14 @@ snapshots: - utf-8-validate - webpack-cli - '@docusaurus/plugin-google-gtag@3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3))(@rspack/core@1.6.7)(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3)': + '@docusaurus/plugin-google-gtag@3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.4))(@rspack/core@1.7.6)(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)': dependencies: - '@docusaurus/core': 3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3))(@rspack/core@1.6.7)(@swc/core@1.15.4)(debug@4.4.3)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3) - '@docusaurus/types': 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@docusaurus/utils-validation': 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@docusaurus/core': 3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.4))(@rspack/core@1.7.6)(@swc/core@1.15.11)(debug@4.4.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) + '@docusaurus/types': 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@docusaurus/utils-validation': 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@types/gtag.js': 0.0.12 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) tslib: 2.8.1 transitivePeerDependencies: - '@docusaurus/faster' @@ -7737,13 +7882,13 @@ snapshots: - utf-8-validate - webpack-cli - '@docusaurus/plugin-google-tag-manager@3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3))(@rspack/core@1.6.7)(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3)': + '@docusaurus/plugin-google-tag-manager@3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.4))(@rspack/core@1.7.6)(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)': dependencies: - '@docusaurus/core': 3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3))(@rspack/core@1.6.7)(@swc/core@1.15.4)(debug@4.4.3)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3) - '@docusaurus/types': 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@docusaurus/utils-validation': 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) + '@docusaurus/core': 3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.4))(@rspack/core@1.7.6)(@swc/core@1.15.11)(debug@4.4.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) + '@docusaurus/types': 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@docusaurus/utils-validation': 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) tslib: 2.8.1 transitivePeerDependencies: - '@docusaurus/faster' @@ -7763,17 +7908,17 @@ snapshots: - utf-8-validate - webpack-cli - '@docusaurus/plugin-sitemap@3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3))(@rspack/core@1.6.7)(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3)': + '@docusaurus/plugin-sitemap@3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.4))(@rspack/core@1.7.6)(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)': dependencies: - '@docusaurus/core': 3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3))(@rspack/core@1.6.7)(@swc/core@1.15.4)(debug@4.4.3)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3) + '@docusaurus/core': 3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.4))(@rspack/core@1.7.6)(@swc/core@1.15.11)(debug@4.4.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) '@docusaurus/logger': 3.9.2 - '@docusaurus/types': 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@docusaurus/utils': 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@docusaurus/utils-common': 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@docusaurus/utils-validation': 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - fs-extra: 11.3.2 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) + '@docusaurus/types': 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@docusaurus/utils': 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@docusaurus/utils-common': 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@docusaurus/utils-validation': 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + fs-extra: 11.3.3 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) sitemap: 7.1.2 tslib: 2.8.1 transitivePeerDependencies: @@ -7794,18 +7939,18 @@ snapshots: - utf-8-validate - webpack-cli - '@docusaurus/plugin-svgr@3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3))(@rspack/core@1.6.7)(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3)': + '@docusaurus/plugin-svgr@3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.4))(@rspack/core@1.7.6)(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)': dependencies: - '@docusaurus/core': 3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3))(@rspack/core@1.6.7)(@swc/core@1.15.4)(debug@4.4.3)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3) - '@docusaurus/types': 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@docusaurus/utils': 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@docusaurus/utils-validation': 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@docusaurus/core': 3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.4))(@rspack/core@1.7.6)(@swc/core@1.15.11)(debug@4.4.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) + '@docusaurus/types': 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@docusaurus/utils': 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@docusaurus/utils-validation': 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@svgr/core': 8.1.0(typescript@5.9.3) '@svgr/webpack': 8.1.0(typescript@5.9.3) - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) tslib: 2.8.1 - webpack: 5.103.0(@swc/core@1.15.4) + webpack: 5.105.2(@swc/core@1.15.11) transitivePeerDependencies: - '@docusaurus/faster' - '@mdx-js/react' @@ -7824,25 +7969,25 @@ snapshots: - utf-8-validate - webpack-cli - '@docusaurus/preset-classic@3.9.2(@algolia/client-search@5.46.0)(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3))(@rspack/core@1.6.7)(@swc/core@1.15.4)(@types/react@19.2.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(search-insights@2.17.3)(typescript@5.9.3)': + '@docusaurus/preset-classic@3.9.2(@algolia/client-search@5.49.0)(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.4))(@rspack/core@1.7.6)(@swc/core@1.15.11)(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(search-insights@2.17.3)(typescript@5.9.3)': dependencies: - '@docusaurus/core': 3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3))(@rspack/core@1.6.7)(@swc/core@1.15.4)(debug@4.4.3)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3) - '@docusaurus/plugin-content-blog': 3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@docusaurus/plugin-content-docs@3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3))(@rspack/core@1.6.7)(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3))(@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3))(@rspack/core@1.6.7)(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3) - '@docusaurus/plugin-content-docs': 3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3))(@rspack/core@1.6.7)(@swc/core@1.15.4)(debug@4.4.3)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3) - '@docusaurus/plugin-content-pages': 3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3))(@rspack/core@1.6.7)(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3) - '@docusaurus/plugin-css-cascade-layers': 3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3))(@rspack/core@1.6.7)(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3) - '@docusaurus/plugin-debug': 3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3))(@rspack/core@1.6.7)(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3) - '@docusaurus/plugin-google-analytics': 3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3))(@rspack/core@1.6.7)(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3) - '@docusaurus/plugin-google-gtag': 3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3))(@rspack/core@1.6.7)(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3) - '@docusaurus/plugin-google-tag-manager': 3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3))(@rspack/core@1.6.7)(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3) - '@docusaurus/plugin-sitemap': 3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3))(@rspack/core@1.6.7)(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3) - '@docusaurus/plugin-svgr': 3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3))(@rspack/core@1.6.7)(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3) - '@docusaurus/theme-classic': 3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@rspack/core@1.6.7)(@swc/core@1.15.4)(@types/react@19.2.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3) - '@docusaurus/theme-common': 3.9.2(@docusaurus/plugin-content-docs@3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3))(@rspack/core@1.6.7)(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3))(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@docusaurus/theme-search-algolia': 3.9.2(@algolia/client-search@5.46.0)(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3))(@rspack/core@1.6.7)(@swc/core@1.15.4)(@types/react@19.2.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(search-insights@2.17.3)(typescript@5.9.3) - '@docusaurus/types': 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) + '@docusaurus/core': 3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.4))(@rspack/core@1.7.6)(@swc/core@1.15.11)(debug@4.4.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) + '@docusaurus/plugin-content-blog': 3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@docusaurus/plugin-content-docs@3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.4))(@rspack/core@1.7.6)(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.4))(@rspack/core@1.7.6)(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) + '@docusaurus/plugin-content-docs': 3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.4))(@rspack/core@1.7.6)(@swc/core@1.15.11)(debug@4.4.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) + '@docusaurus/plugin-content-pages': 3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.4))(@rspack/core@1.7.6)(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) + '@docusaurus/plugin-css-cascade-layers': 3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.4))(@rspack/core@1.7.6)(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) + '@docusaurus/plugin-debug': 3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.4))(@rspack/core@1.7.6)(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) + '@docusaurus/plugin-google-analytics': 3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.4))(@rspack/core@1.7.6)(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) + '@docusaurus/plugin-google-gtag': 3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.4))(@rspack/core@1.7.6)(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) + '@docusaurus/plugin-google-tag-manager': 3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.4))(@rspack/core@1.7.6)(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) + '@docusaurus/plugin-sitemap': 3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.4))(@rspack/core@1.7.6)(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) + '@docusaurus/plugin-svgr': 3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.4))(@rspack/core@1.7.6)(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) + '@docusaurus/theme-classic': 3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@rspack/core@1.7.6)(@swc/core@1.15.11)(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) + '@docusaurus/theme-common': 3.9.2(@docusaurus/plugin-content-docs@3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.4))(@rspack/core@1.7.6)(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@docusaurus/theme-search-algolia': 3.9.2(@algolia/client-search@5.49.0)(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.4))(@rspack/core@1.7.6)(@swc/core@1.15.11)(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(search-insights@2.17.3)(typescript@5.9.3) + '@docusaurus/types': 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) transitivePeerDependencies: - '@algolia/client-search' - '@docusaurus/faster' @@ -7864,37 +8009,37 @@ snapshots: - utf-8-validate - webpack-cli - '@docusaurus/react-loadable@6.0.0(react@19.2.3)': + '@docusaurus/react-loadable@6.0.0(react@19.2.4)': dependencies: - '@types/react': 19.2.7 - react: 19.2.3 + '@types/react': 19.2.14 + react: 19.2.4 - '@docusaurus/theme-classic@3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@rspack/core@1.6.7)(@swc/core@1.15.4)(@types/react@19.2.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3)': + '@docusaurus/theme-classic@3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@rspack/core@1.7.6)(@swc/core@1.15.11)(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)': dependencies: - '@docusaurus/core': 3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3))(@rspack/core@1.6.7)(@swc/core@1.15.4)(debug@4.4.3)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3) + '@docusaurus/core': 3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.4))(@rspack/core@1.7.6)(@swc/core@1.15.11)(debug@4.4.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) '@docusaurus/logger': 3.9.2 - '@docusaurus/mdx-loader': 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@docusaurus/module-type-aliases': 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@docusaurus/plugin-content-blog': 3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@docusaurus/plugin-content-docs@3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3))(@rspack/core@1.6.7)(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3))(@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3))(@rspack/core@1.6.7)(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3) - '@docusaurus/plugin-content-docs': 3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3))(@rspack/core@1.6.7)(@swc/core@1.15.4)(debug@4.4.3)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3) - '@docusaurus/plugin-content-pages': 3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3))(@rspack/core@1.6.7)(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3) - '@docusaurus/theme-common': 3.9.2(@docusaurus/plugin-content-docs@3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3))(@rspack/core@1.6.7)(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3))(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@docusaurus/mdx-loader': 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@docusaurus/module-type-aliases': 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@docusaurus/plugin-content-blog': 3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@docusaurus/plugin-content-docs@3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.4))(@rspack/core@1.7.6)(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.4))(@rspack/core@1.7.6)(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) + '@docusaurus/plugin-content-docs': 3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.4))(@rspack/core@1.7.6)(@swc/core@1.15.11)(debug@4.4.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) + '@docusaurus/plugin-content-pages': 3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.4))(@rspack/core@1.7.6)(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) + '@docusaurus/theme-common': 3.9.2(@docusaurus/plugin-content-docs@3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.4))(@rspack/core@1.7.6)(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@docusaurus/theme-translations': 3.9.2 - '@docusaurus/types': 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@docusaurus/utils': 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@docusaurus/utils-common': 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@docusaurus/utils-validation': 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@mdx-js/react': 3.1.1(@types/react@19.2.7)(react@19.2.3) + '@docusaurus/types': 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@docusaurus/utils': 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@docusaurus/utils-common': 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@docusaurus/utils-validation': 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@mdx-js/react': 3.1.1(@types/react@19.2.14)(react@19.2.4) clsx: 2.1.1 infima: 0.2.0-alpha.45 - lodash: 4.17.21 + lodash: 4.17.23 nprogress: 0.2.0 postcss: 8.5.6 - prism-react-renderer: 2.4.1(react@19.2.3) + prism-react-renderer: 2.4.1(react@19.2.4) prismjs: 1.30.0 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - react-router-dom: 5.3.4(react@19.2.3) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + react-router-dom: 5.3.4(react@19.2.4) rtlcss: 4.3.0 tslib: 2.8.1 utility-types: 3.11.0 @@ -7916,21 +8061,21 @@ snapshots: - utf-8-validate - webpack-cli - '@docusaurus/theme-common@3.9.2(@docusaurus/plugin-content-docs@3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3))(@rspack/core@1.6.7)(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3))(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + '@docusaurus/theme-common@3.9.2(@docusaurus/plugin-content-docs@3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.4))(@rspack/core@1.7.6)(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@docusaurus/mdx-loader': 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@docusaurus/module-type-aliases': 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@docusaurus/plugin-content-docs': 3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3))(@rspack/core@1.6.7)(@swc/core@1.15.4)(debug@4.4.3)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3) - '@docusaurus/utils': 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@docusaurus/utils-common': 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@docusaurus/mdx-loader': 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@docusaurus/module-type-aliases': 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@docusaurus/plugin-content-docs': 3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.4))(@rspack/core@1.7.6)(@swc/core@1.15.11)(debug@4.4.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) + '@docusaurus/utils': 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@docusaurus/utils-common': 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@types/history': 4.7.11 - '@types/react': 19.2.7 + '@types/react': 19.2.14 '@types/react-router-config': 5.0.11 clsx: 2.1.1 parse-numeric-range: 1.3.0 - prism-react-renderer: 2.4.1(react@19.2.3) - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) + prism-react-renderer: 2.4.1(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) tslib: 2.8.1 utility-types: 3.11.0 transitivePeerDependencies: @@ -7940,24 +8085,24 @@ snapshots: - uglify-js - webpack-cli - '@docusaurus/theme-search-algolia@3.9.2(@algolia/client-search@5.46.0)(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3))(@rspack/core@1.6.7)(@swc/core@1.15.4)(@types/react@19.2.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(search-insights@2.17.3)(typescript@5.9.3)': + '@docusaurus/theme-search-algolia@3.9.2(@algolia/client-search@5.49.0)(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.4))(@rspack/core@1.7.6)(@swc/core@1.15.11)(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(search-insights@2.17.3)(typescript@5.9.3)': dependencies: - '@docsearch/react': 4.3.2(@algolia/client-search@5.46.0)(@types/react@19.2.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(search-insights@2.17.3) - '@docusaurus/core': 3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3))(@rspack/core@1.6.7)(@swc/core@1.15.4)(debug@4.4.3)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3) + '@docsearch/react': 4.6.0(@algolia/client-search@5.49.0)(@types/react@19.2.14)(algoliasearch@5.49.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(search-insights@2.17.3) + '@docusaurus/core': 3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.4))(@rspack/core@1.7.6)(@swc/core@1.15.11)(debug@4.4.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) '@docusaurus/logger': 3.9.2 - '@docusaurus/plugin-content-docs': 3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3))(@rspack/core@1.6.7)(@swc/core@1.15.4)(debug@4.4.3)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3) - '@docusaurus/theme-common': 3.9.2(@docusaurus/plugin-content-docs@3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3))(@rspack/core@1.6.7)(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3))(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@docusaurus/plugin-content-docs': 3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.4))(@rspack/core@1.7.6)(@swc/core@1.15.11)(debug@4.4.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) + '@docusaurus/theme-common': 3.9.2(@docusaurus/plugin-content-docs@3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.4))(@rspack/core@1.7.6)(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@docusaurus/theme-translations': 3.9.2 - '@docusaurus/utils': 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@docusaurus/utils-validation': 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - algoliasearch: 5.46.0 - algoliasearch-helper: 3.26.1(algoliasearch@5.46.0) + '@docusaurus/utils': 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@docusaurus/utils-validation': 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + algoliasearch: 5.49.0 + algoliasearch-helper: 3.27.1(algoliasearch@5.49.0) clsx: 2.1.1 eta: 2.2.0 - fs-extra: 11.3.2 - lodash: 4.17.21 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) + fs-extra: 11.3.3 + lodash: 4.17.23 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) tslib: 2.8.1 utility-types: 3.11.0 transitivePeerDependencies: @@ -7983,24 +8128,24 @@ snapshots: '@docusaurus/theme-translations@3.9.2': dependencies: - fs-extra: 11.3.2 + fs-extra: 11.3.3 tslib: 2.8.1 '@docusaurus/tsconfig@3.9.2': {} - '@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + '@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: '@mdx-js/mdx': 3.1.1 '@types/history': 4.7.11 '@types/mdast': 4.0.4 - '@types/react': 19.2.7 + '@types/react': 19.2.14 commander: 5.1.0 joi: 17.13.3 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - react-helmet-async: '@slorber/react-helmet-async@1.3.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)' + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + react-helmet-async: '@slorber/react-helmet-async@1.3.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4)' utility-types: 3.11.0 - webpack: 5.103.0(@swc/core@1.15.4) + webpack: 5.105.2(@swc/core@1.15.11) webpack-merge: 5.10.0 transitivePeerDependencies: - '@swc/core' @@ -8009,9 +8154,9 @@ snapshots: - uglify-js - webpack-cli - '@docusaurus/utils-common@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + '@docusaurus/utils-common@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@docusaurus/types': 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@docusaurus/types': 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) tslib: 2.8.1 transitivePeerDependencies: - '@swc/core' @@ -8022,15 +8167,15 @@ snapshots: - uglify-js - webpack-cli - '@docusaurus/utils-validation@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + '@docusaurus/utils-validation@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: '@docusaurus/logger': 3.9.2 - '@docusaurus/utils': 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@docusaurus/utils-common': 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - fs-extra: 11.3.2 + '@docusaurus/utils': 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@docusaurus/utils-common': 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + fs-extra: 11.3.3 joi: 17.13.3 js-yaml: 4.1.1 - lodash: 4.17.21 + lodash: 4.17.23 tslib: 2.8.1 transitivePeerDependencies: - '@swc/core' @@ -8041,29 +8186,29 @@ snapshots: - uglify-js - webpack-cli - '@docusaurus/utils@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + '@docusaurus/utils@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: '@docusaurus/logger': 3.9.2 - '@docusaurus/types': 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@docusaurus/utils-common': 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@docusaurus/types': 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@docusaurus/utils-common': 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) escape-string-regexp: 4.0.0 execa: 5.1.1 - file-loader: 6.2.0(webpack@5.103.0(@swc/core@1.15.4)) - fs-extra: 11.3.2 + file-loader: 6.2.0(webpack@5.105.2(@swc/core@1.15.11)) + fs-extra: 11.3.3 github-slugger: 1.5.0 globby: 11.1.0 gray-matter: 4.0.3 jiti: 1.21.7 js-yaml: 4.1.1 - lodash: 4.17.21 + lodash: 4.17.23 micromatch: 4.0.8 p-queue: 6.6.2 prompts: 2.4.2 resolve-pathname: 3.0.0 tslib: 2.8.1 - url-loader: 4.1.1(file-loader@6.2.0(webpack@5.103.0(@swc/core@1.15.4)))(webpack@5.103.0(@swc/core@1.15.4)) + url-loader: 4.1.1(file-loader@6.2.0(webpack@5.105.2(@swc/core@1.15.11)))(webpack@5.105.2(@swc/core@1.15.11)) utility-types: 3.11.0 - webpack: 5.103.0(@swc/core@1.15.4) + webpack: 5.105.2(@swc/core@1.15.11) transitivePeerDependencies: - '@swc/core' - esbuild @@ -8078,17 +8223,17 @@ snapshots: cssesc: 3.0.0 immediate: 3.3.0 - '@easyops-cn/docusaurus-search-local@0.52.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@docusaurus/theme-common@3.9.2(@docusaurus/plugin-content-docs@3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3))(@rspack/core@1.6.7)(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3))(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3))(@rspack/core@1.6.7)(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3)': + '@easyops-cn/docusaurus-search-local@0.55.0(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@docusaurus/theme-common@3.9.2(@docusaurus/plugin-content-docs@3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.4))(@rspack/core@1.7.6)(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.4))(@rspack/core@1.7.6)(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)': dependencies: - '@docusaurus/plugin-content-docs': 3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3))(@rspack/core@1.6.7)(@swc/core@1.15.4)(debug@4.4.3)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3) - '@docusaurus/theme-common': 3.9.2(@docusaurus/plugin-content-docs@3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3))(@rspack/core@1.6.7)(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3))(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@docusaurus/plugin-content-docs': 3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.4))(@rspack/core@1.7.6)(@swc/core@1.15.11)(debug@4.4.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) + '@docusaurus/theme-common': 3.9.2(@docusaurus/plugin-content-docs@3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.4))(@rspack/core@1.7.6)(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@docusaurus/theme-translations': 3.9.2 - '@docusaurus/utils': 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@docusaurus/utils-common': 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@docusaurus/utils-validation': 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@docusaurus/utils': 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@docusaurus/utils-common': 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@docusaurus/utils-validation': 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@easyops-cn/autocomplete.js': 0.38.1 '@node-rs/jieba': 1.10.4 - cheerio: 1.1.2 + cheerio: 1.2.0 clsx: 2.1.1 comlink: 4.4.2 debug: 4.4.3 @@ -8097,8 +8242,8 @@ snapshots: lunr: 2.3.9 lunr-languages: 1.14.0 mark.js: 8.11.1 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) tslib: 2.8.1 transitivePeerDependencies: - '@docusaurus/faster' @@ -8117,13 +8262,13 @@ snapshots: - utf-8-validate - webpack-cli - '@emnapi/core@1.7.1': + '@emnapi/core@1.8.1': dependencies: '@emnapi/wasi-threads': 1.1.0 tslib: 2.8.1 optional: true - '@emnapi/runtime@1.7.1': + '@emnapi/runtime@1.8.1': dependencies: tslib: 2.8.1 optional: true @@ -8133,13 +8278,15 @@ snapshots: tslib: 2.8.1 optional: true - '@emotion/is-prop-valid@1.2.2': + '@emotion/is-prop-valid@1.4.0': dependencies: - '@emotion/memoize': 0.8.1 + '@emotion/memoize': 0.9.0 - '@emotion/memoize@0.8.1': {} + '@emotion/memoize@0.9.0': {} - '@emotion/unitless@0.8.1': {} + '@emotion/unitless@0.10.0': {} + + '@exodus/bytes@1.14.1': {} '@exodus/schemasafe@1.3.0': {} @@ -8149,27 +8296,27 @@ snapshots: dependencies: '@hapi/hoek': 9.3.0 - '@ianvs/prettier-plugin-sort-imports@4.7.0(prettier@3.7.4)': + '@ianvs/prettier-plugin-sort-imports@4.7.1(prettier@3.8.1)': dependencies: - '@babel/generator': 7.28.5 - '@babel/parser': 7.28.5 - '@babel/traverse': 7.28.5 - '@babel/types': 7.28.5 - prettier: 3.7.4 - semver: 7.7.3 + '@babel/generator': 7.29.1 + '@babel/parser': 7.29.0 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + prettier: 3.8.1 + semver: 7.7.4 transitivePeerDependencies: - supports-color '@jest/schemas@29.6.3': dependencies: - '@sinclair/typebox': 0.27.8 + '@sinclair/typebox': 0.27.10 '@jest/types@29.6.3': dependencies: '@jest/schemas': 29.6.3 '@types/istanbul-lib-coverage': 2.0.6 '@types/istanbul-reports': 3.0.4 - '@types/node': 24.10.4 + '@types/node': 25.3.0 '@types/yargs': 17.0.35 chalk: 4.1.2 @@ -8201,14 +8348,82 @@ snapshots: dependencies: tslib: 2.8.1 + '@jsonjoy.com/base64@17.67.0(tslib@2.8.1)': + dependencies: + tslib: 2.8.1 + '@jsonjoy.com/buffers@1.2.1(tslib@2.8.1)': dependencies: tslib: 2.8.1 + '@jsonjoy.com/buffers@17.67.0(tslib@2.8.1)': + dependencies: + tslib: 2.8.1 + '@jsonjoy.com/codegen@1.0.0(tslib@2.8.1)': dependencies: tslib: 2.8.1 + '@jsonjoy.com/codegen@17.67.0(tslib@2.8.1)': + dependencies: + tslib: 2.8.1 + + '@jsonjoy.com/fs-core@4.56.10(tslib@2.8.1)': + dependencies: + '@jsonjoy.com/fs-node-builtins': 4.56.10(tslib@2.8.1) + '@jsonjoy.com/fs-node-utils': 4.56.10(tslib@2.8.1) + thingies: 2.5.0(tslib@2.8.1) + tslib: 2.8.1 + + '@jsonjoy.com/fs-fsa@4.56.10(tslib@2.8.1)': + dependencies: + '@jsonjoy.com/fs-core': 4.56.10(tslib@2.8.1) + '@jsonjoy.com/fs-node-builtins': 4.56.10(tslib@2.8.1) + '@jsonjoy.com/fs-node-utils': 4.56.10(tslib@2.8.1) + thingies: 2.5.0(tslib@2.8.1) + tslib: 2.8.1 + + '@jsonjoy.com/fs-node-builtins@4.56.10(tslib@2.8.1)': + dependencies: + tslib: 2.8.1 + + '@jsonjoy.com/fs-node-to-fsa@4.56.10(tslib@2.8.1)': + dependencies: + '@jsonjoy.com/fs-fsa': 4.56.10(tslib@2.8.1) + '@jsonjoy.com/fs-node-builtins': 4.56.10(tslib@2.8.1) + '@jsonjoy.com/fs-node-utils': 4.56.10(tslib@2.8.1) + tslib: 2.8.1 + + '@jsonjoy.com/fs-node-utils@4.56.10(tslib@2.8.1)': + dependencies: + '@jsonjoy.com/fs-node-builtins': 4.56.10(tslib@2.8.1) + tslib: 2.8.1 + + '@jsonjoy.com/fs-node@4.56.10(tslib@2.8.1)': + dependencies: + '@jsonjoy.com/fs-core': 4.56.10(tslib@2.8.1) + '@jsonjoy.com/fs-node-builtins': 4.56.10(tslib@2.8.1) + '@jsonjoy.com/fs-node-utils': 4.56.10(tslib@2.8.1) + '@jsonjoy.com/fs-print': 4.56.10(tslib@2.8.1) + '@jsonjoy.com/fs-snapshot': 4.56.10(tslib@2.8.1) + glob-to-regex.js: 1.2.0(tslib@2.8.1) + thingies: 2.5.0(tslib@2.8.1) + tslib: 2.8.1 + + '@jsonjoy.com/fs-print@4.56.10(tslib@2.8.1)': + dependencies: + '@jsonjoy.com/fs-node-utils': 4.56.10(tslib@2.8.1) + tree-dump: 1.1.0(tslib@2.8.1) + tslib: 2.8.1 + + '@jsonjoy.com/fs-snapshot@4.56.10(tslib@2.8.1)': + dependencies: + '@jsonjoy.com/buffers': 17.67.0(tslib@2.8.1) + '@jsonjoy.com/fs-node-utils': 4.56.10(tslib@2.8.1) + '@jsonjoy.com/json-pack': 17.67.0(tslib@2.8.1) + '@jsonjoy.com/util': 17.67.0(tslib@2.8.1) + tslib: 2.8.1 + '@jsonjoy.com/json-pack@1.21.0(tslib@2.8.1)': dependencies: '@jsonjoy.com/base64': 1.1.2(tslib@2.8.1) @@ -8221,18 +8436,41 @@ snapshots: tree-dump: 1.1.0(tslib@2.8.1) tslib: 2.8.1 + '@jsonjoy.com/json-pack@17.67.0(tslib@2.8.1)': + dependencies: + '@jsonjoy.com/base64': 17.67.0(tslib@2.8.1) + '@jsonjoy.com/buffers': 17.67.0(tslib@2.8.1) + '@jsonjoy.com/codegen': 17.67.0(tslib@2.8.1) + '@jsonjoy.com/json-pointer': 17.67.0(tslib@2.8.1) + '@jsonjoy.com/util': 17.67.0(tslib@2.8.1) + hyperdyperid: 1.2.0 + thingies: 2.5.0(tslib@2.8.1) + tree-dump: 1.1.0(tslib@2.8.1) + tslib: 2.8.1 + '@jsonjoy.com/json-pointer@1.0.2(tslib@2.8.1)': dependencies: '@jsonjoy.com/codegen': 1.0.0(tslib@2.8.1) '@jsonjoy.com/util': 1.9.0(tslib@2.8.1) tslib: 2.8.1 + '@jsonjoy.com/json-pointer@17.67.0(tslib@2.8.1)': + dependencies: + '@jsonjoy.com/util': 17.67.0(tslib@2.8.1) + tslib: 2.8.1 + '@jsonjoy.com/util@1.9.0(tslib@2.8.1)': dependencies: '@jsonjoy.com/buffers': 1.2.1(tslib@2.8.1) '@jsonjoy.com/codegen': 1.0.0(tslib@2.8.1) tslib: 2.8.1 + '@jsonjoy.com/util@17.67.0(tslib@2.8.1)': + dependencies: + '@jsonjoy.com/buffers': 17.67.0(tslib@2.8.1) + '@jsonjoy.com/codegen': 17.67.0(tslib@2.8.1) + tslib: 2.8.1 + '@leichtgewicht/ip-codec@2.0.5': {} '@mdx-js/mdx@3.1.1': @@ -8241,7 +8479,7 @@ snapshots: '@types/estree-jsx': 1.0.5 '@types/hast': 3.0.4 '@types/mdx': 2.0.13 - acorn: 8.15.0 + acorn: 8.16.0 collapse-white-space: 2.1.0 devlop: 1.1.0 estree-util-is-identifier-name: 3.0.0 @@ -8250,7 +8488,7 @@ snapshots: hast-util-to-jsx-runtime: 2.3.6 markdown-extensions: 2.0.0 recma-build-jsx: 1.0.0 - recma-jsx: 1.0.1(acorn@8.15.0) + recma-jsx: 1.0.1(acorn@8.16.0) recma-stringify: 1.0.0 rehype-recma: 1.0.0 remark-mdx: 3.1.1 @@ -8260,56 +8498,58 @@ snapshots: unified: 11.0.5 unist-util-position-from-estree: 2.0.0 unist-util-stringify-position: 4.0.0 - unist-util-visit: 5.0.0 + unist-util-visit: 5.1.0 vfile: 6.0.3 transitivePeerDependencies: - supports-color - '@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3)': + '@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.4)': dependencies: '@types/mdx': 2.0.13 - '@types/react': 19.2.7 - react: 19.2.3 + '@types/react': 19.2.14 + react: 19.2.4 - '@module-federation/error-codes@0.21.6': {} + '@module-federation/error-codes@0.22.0': {} - '@module-federation/runtime-core@0.21.6': + '@module-federation/runtime-core@0.22.0': dependencies: - '@module-federation/error-codes': 0.21.6 - '@module-federation/sdk': 0.21.6 + '@module-federation/error-codes': 0.22.0 + '@module-federation/sdk': 0.22.0 - '@module-federation/runtime-tools@0.21.6': + '@module-federation/runtime-tools@0.22.0': dependencies: - '@module-federation/runtime': 0.21.6 - '@module-federation/webpack-bundler-runtime': 0.21.6 + '@module-federation/runtime': 0.22.0 + '@module-federation/webpack-bundler-runtime': 0.22.0 - '@module-federation/runtime@0.21.6': + '@module-federation/runtime@0.22.0': dependencies: - '@module-federation/error-codes': 0.21.6 - '@module-federation/runtime-core': 0.21.6 - '@module-federation/sdk': 0.21.6 + '@module-federation/error-codes': 0.22.0 + '@module-federation/runtime-core': 0.22.0 + '@module-federation/sdk': 0.22.0 - '@module-federation/sdk@0.21.6': {} + '@module-federation/sdk@0.22.0': {} - '@module-federation/webpack-bundler-runtime@0.21.6': + '@module-federation/webpack-bundler-runtime@0.22.0': dependencies: - '@module-federation/runtime': 0.21.6 - '@module-federation/sdk': 0.21.6 + '@module-federation/runtime': 0.22.0 + '@module-federation/sdk': 0.22.0 '@napi-rs/wasm-runtime@0.2.12': dependencies: - '@emnapi/core': 1.7.1 - '@emnapi/runtime': 1.7.1 + '@emnapi/core': 1.8.1 + '@emnapi/runtime': 1.8.1 '@tybys/wasm-util': 0.10.1 optional: true '@napi-rs/wasm-runtime@1.0.7': dependencies: - '@emnapi/core': 1.7.1 - '@emnapi/runtime': 1.7.1 + '@emnapi/core': 1.8.1 + '@emnapi/runtime': 1.8.1 '@tybys/wasm-util': 0.10.1 optional: true + '@noble/hashes@1.4.0': {} + '@node-rs/jieba-android-arm-eabi@1.10.4': optional: true @@ -8381,9 +8621,97 @@ snapshots: '@nodelib/fs.walk@1.2.8': dependencies: '@nodelib/fs.scandir': 2.1.5 - fastq: 1.19.1 + fastq: 1.20.1 - '@opentelemetry/api@1.9.0': {} + '@peculiar/asn1-cms@2.6.1': + dependencies: + '@peculiar/asn1-schema': 2.6.0 + '@peculiar/asn1-x509': 2.6.1 + '@peculiar/asn1-x509-attr': 2.6.1 + asn1js: 3.0.7 + tslib: 2.8.1 + + '@peculiar/asn1-csr@2.6.1': + dependencies: + '@peculiar/asn1-schema': 2.6.0 + '@peculiar/asn1-x509': 2.6.1 + asn1js: 3.0.7 + tslib: 2.8.1 + + '@peculiar/asn1-ecc@2.6.1': + dependencies: + '@peculiar/asn1-schema': 2.6.0 + '@peculiar/asn1-x509': 2.6.1 + asn1js: 3.0.7 + tslib: 2.8.1 + + '@peculiar/asn1-pfx@2.6.1': + dependencies: + '@peculiar/asn1-cms': 2.6.1 + '@peculiar/asn1-pkcs8': 2.6.1 + '@peculiar/asn1-rsa': 2.6.1 + '@peculiar/asn1-schema': 2.6.0 + asn1js: 3.0.7 + tslib: 2.8.1 + + '@peculiar/asn1-pkcs8@2.6.1': + dependencies: + '@peculiar/asn1-schema': 2.6.0 + '@peculiar/asn1-x509': 2.6.1 + asn1js: 3.0.7 + tslib: 2.8.1 + + '@peculiar/asn1-pkcs9@2.6.1': + dependencies: + '@peculiar/asn1-cms': 2.6.1 + '@peculiar/asn1-pfx': 2.6.1 + '@peculiar/asn1-pkcs8': 2.6.1 + '@peculiar/asn1-schema': 2.6.0 + '@peculiar/asn1-x509': 2.6.1 + '@peculiar/asn1-x509-attr': 2.6.1 + asn1js: 3.0.7 + tslib: 2.8.1 + + '@peculiar/asn1-rsa@2.6.1': + dependencies: + '@peculiar/asn1-schema': 2.6.0 + '@peculiar/asn1-x509': 2.6.1 + asn1js: 3.0.7 + tslib: 2.8.1 + + '@peculiar/asn1-schema@2.6.0': + dependencies: + asn1js: 3.0.7 + pvtsutils: 1.3.6 + tslib: 2.8.1 + + '@peculiar/asn1-x509-attr@2.6.1': + dependencies: + '@peculiar/asn1-schema': 2.6.0 + '@peculiar/asn1-x509': 2.6.1 + asn1js: 3.0.7 + tslib: 2.8.1 + + '@peculiar/asn1-x509@2.6.1': + dependencies: + '@peculiar/asn1-schema': 2.6.0 + asn1js: 3.0.7 + pvtsutils: 1.3.6 + tslib: 2.8.1 + + '@peculiar/x509@1.14.3': + dependencies: + '@peculiar/asn1-cms': 2.6.1 + '@peculiar/asn1-csr': 2.6.1 + '@peculiar/asn1-ecc': 2.6.1 + '@peculiar/asn1-pkcs9': 2.6.1 + '@peculiar/asn1-rsa': 2.6.1 + '@peculiar/asn1-schema': 2.6.0 + '@peculiar/asn1-x509': 2.6.1 + pvtsutils: 1.3.6 + reflect-metadata: 0.2.2 + tslib: 2.8.1 + tsyringe: 4.10.0 '@pnpm/config.env-replace@1.1.0': {} @@ -8391,7 +8719,7 @@ snapshots: dependencies: graceful-fs: 4.2.10 - '@pnpm/npm-conf@2.3.1': + '@pnpm/npm-conf@3.0.2': dependencies: '@pnpm/config.env-replace': 1.1.0 '@pnpm/network.ca-file': 1.0.2 @@ -8399,7 +8727,7 @@ snapshots: '@polka/url@1.0.0-next.29': {} - '@redocly/ajv@8.17.1': + '@redocly/ajv@8.17.4': dependencies: fast-deep-equal: 3.1.3 fast-uri: 3.1.0 @@ -8410,14 +8738,14 @@ snapshots: '@redocly/openapi-core@1.16.0': dependencies: - '@redocly/ajv': 8.17.1 + '@redocly/ajv': 8.17.4 '@redocly/config': 0.6.3 colorette: 1.4.0 https-proxy-agent: 7.0.6 js-levenshtein: 1.1.6 js-yaml: 4.1.1 lodash.isequal: 4.5.0 - minimatch: 5.1.6 + minimatch: 10.2.2 node-fetch: 2.7.0 pluralize: 8.0.0 yaml-ast-parser: 0.0.43 @@ -8425,55 +8753,55 @@ snapshots: - encoding - supports-color - '@rspack/binding-darwin-arm64@1.6.7': + '@rspack/binding-darwin-arm64@1.7.6': optional: true - '@rspack/binding-darwin-x64@1.6.7': + '@rspack/binding-darwin-x64@1.7.6': optional: true - '@rspack/binding-linux-arm64-gnu@1.6.7': + '@rspack/binding-linux-arm64-gnu@1.7.6': optional: true - '@rspack/binding-linux-arm64-musl@1.6.7': + '@rspack/binding-linux-arm64-musl@1.7.6': optional: true - '@rspack/binding-linux-x64-gnu@1.6.7': + '@rspack/binding-linux-x64-gnu@1.7.6': optional: true - '@rspack/binding-linux-x64-musl@1.6.7': + '@rspack/binding-linux-x64-musl@1.7.6': optional: true - '@rspack/binding-wasm32-wasi@1.6.7': + '@rspack/binding-wasm32-wasi@1.7.6': dependencies: '@napi-rs/wasm-runtime': 1.0.7 optional: true - '@rspack/binding-win32-arm64-msvc@1.6.7': + '@rspack/binding-win32-arm64-msvc@1.7.6': optional: true - '@rspack/binding-win32-ia32-msvc@1.6.7': + '@rspack/binding-win32-ia32-msvc@1.7.6': optional: true - '@rspack/binding-win32-x64-msvc@1.6.7': + '@rspack/binding-win32-x64-msvc@1.7.6': optional: true - '@rspack/binding@1.6.7': + '@rspack/binding@1.7.6': optionalDependencies: - '@rspack/binding-darwin-arm64': 1.6.7 - '@rspack/binding-darwin-x64': 1.6.7 - '@rspack/binding-linux-arm64-gnu': 1.6.7 - '@rspack/binding-linux-arm64-musl': 1.6.7 - '@rspack/binding-linux-x64-gnu': 1.6.7 - '@rspack/binding-linux-x64-musl': 1.6.7 - '@rspack/binding-wasm32-wasi': 1.6.7 - '@rspack/binding-win32-arm64-msvc': 1.6.7 - '@rspack/binding-win32-ia32-msvc': 1.6.7 - '@rspack/binding-win32-x64-msvc': 1.6.7 + '@rspack/binding-darwin-arm64': 1.7.6 + '@rspack/binding-darwin-x64': 1.7.6 + '@rspack/binding-linux-arm64-gnu': 1.7.6 + '@rspack/binding-linux-arm64-musl': 1.7.6 + '@rspack/binding-linux-x64-gnu': 1.7.6 + '@rspack/binding-linux-x64-musl': 1.7.6 + '@rspack/binding-wasm32-wasi': 1.7.6 + '@rspack/binding-win32-arm64-msvc': 1.7.6 + '@rspack/binding-win32-ia32-msvc': 1.7.6 + '@rspack/binding-win32-x64-msvc': 1.7.6 - '@rspack/core@1.6.7': + '@rspack/core@1.7.6': dependencies: - '@module-federation/runtime-tools': 0.21.6 - '@rspack/binding': 1.6.7 + '@module-federation/runtime-tools': 0.22.0 + '@rspack/binding': 1.7.6 '@rspack/lite-tapable': 1.1.0 '@rspack/lite-tapable@1.1.0': {} @@ -8486,19 +8814,19 @@ snapshots: '@sideway/pinpoint@2.0.0': {} - '@sinclair/typebox@0.27.8': {} + '@sinclair/typebox@0.27.10': {} '@sindresorhus/is@4.6.0': {} '@sindresorhus/is@5.6.0': {} - '@slorber/react-helmet-async@1.3.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + '@slorber/react-helmet-async@1.3.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@babel/runtime': 7.28.4 + '@babel/runtime': 7.28.6 invariant: 2.2.4 prop-types: 15.8.1 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) react-fast-compare: 3.2.2 shallowequal: 1.1.0 @@ -8508,56 +8836,54 @@ snapshots: micromark-util-character: 1.2.0 micromark-util-symbol: 1.1.0 - '@standard-schema/spec@1.0.0': {} - - '@svgr/babel-plugin-add-jsx-attribute@8.0.0(@babel/core@7.28.5)': + '@svgr/babel-plugin-add-jsx-attribute@8.0.0(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 + '@babel/core': 7.29.0 - '@svgr/babel-plugin-remove-jsx-attribute@8.0.0(@babel/core@7.28.5)': + '@svgr/babel-plugin-remove-jsx-attribute@8.0.0(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 + '@babel/core': 7.29.0 - '@svgr/babel-plugin-remove-jsx-empty-expression@8.0.0(@babel/core@7.28.5)': + '@svgr/babel-plugin-remove-jsx-empty-expression@8.0.0(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 + '@babel/core': 7.29.0 - '@svgr/babel-plugin-replace-jsx-attribute-value@8.0.0(@babel/core@7.28.5)': + '@svgr/babel-plugin-replace-jsx-attribute-value@8.0.0(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 + '@babel/core': 7.29.0 - '@svgr/babel-plugin-svg-dynamic-title@8.0.0(@babel/core@7.28.5)': + '@svgr/babel-plugin-svg-dynamic-title@8.0.0(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 + '@babel/core': 7.29.0 - '@svgr/babel-plugin-svg-em-dimensions@8.0.0(@babel/core@7.28.5)': + '@svgr/babel-plugin-svg-em-dimensions@8.0.0(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 + '@babel/core': 7.29.0 - '@svgr/babel-plugin-transform-react-native-svg@8.1.0(@babel/core@7.28.5)': + '@svgr/babel-plugin-transform-react-native-svg@8.1.0(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 + '@babel/core': 7.29.0 - '@svgr/babel-plugin-transform-svg-component@8.0.0(@babel/core@7.28.5)': + '@svgr/babel-plugin-transform-svg-component@8.0.0(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 + '@babel/core': 7.29.0 - '@svgr/babel-preset@8.1.0(@babel/core@7.28.5)': + '@svgr/babel-preset@8.1.0(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@svgr/babel-plugin-add-jsx-attribute': 8.0.0(@babel/core@7.28.5) - '@svgr/babel-plugin-remove-jsx-attribute': 8.0.0(@babel/core@7.28.5) - '@svgr/babel-plugin-remove-jsx-empty-expression': 8.0.0(@babel/core@7.28.5) - '@svgr/babel-plugin-replace-jsx-attribute-value': 8.0.0(@babel/core@7.28.5) - '@svgr/babel-plugin-svg-dynamic-title': 8.0.0(@babel/core@7.28.5) - '@svgr/babel-plugin-svg-em-dimensions': 8.0.0(@babel/core@7.28.5) - '@svgr/babel-plugin-transform-react-native-svg': 8.1.0(@babel/core@7.28.5) - '@svgr/babel-plugin-transform-svg-component': 8.0.0(@babel/core@7.28.5) + '@babel/core': 7.29.0 + '@svgr/babel-plugin-add-jsx-attribute': 8.0.0(@babel/core@7.29.0) + '@svgr/babel-plugin-remove-jsx-attribute': 8.0.0(@babel/core@7.29.0) + '@svgr/babel-plugin-remove-jsx-empty-expression': 8.0.0(@babel/core@7.29.0) + '@svgr/babel-plugin-replace-jsx-attribute-value': 8.0.0(@babel/core@7.29.0) + '@svgr/babel-plugin-svg-dynamic-title': 8.0.0(@babel/core@7.29.0) + '@svgr/babel-plugin-svg-em-dimensions': 8.0.0(@babel/core@7.29.0) + '@svgr/babel-plugin-transform-react-native-svg': 8.1.0(@babel/core@7.29.0) + '@svgr/babel-plugin-transform-svg-component': 8.0.0(@babel/core@7.29.0) '@svgr/core@8.1.0(typescript@5.9.3)': dependencies: - '@babel/core': 7.28.5 - '@svgr/babel-preset': 8.1.0(@babel/core@7.28.5) + '@babel/core': 7.29.0 + '@svgr/babel-preset': 8.1.0(@babel/core@7.29.0) camelcase: 6.3.0 cosmiconfig: 8.3.6(typescript@5.9.3) snake-case: 3.0.4 @@ -8567,13 +8893,13 @@ snapshots: '@svgr/hast-util-to-babel-ast@8.0.0': dependencies: - '@babel/types': 7.28.5 + '@babel/types': 7.29.0 entities: 4.5.0 '@svgr/plugin-jsx@8.1.0(@svgr/core@8.1.0(typescript@5.9.3))': dependencies: - '@babel/core': 7.28.5 - '@svgr/babel-preset': 8.1.0(@babel/core@7.28.5) + '@babel/core': 7.29.0 + '@svgr/babel-preset': 8.1.0(@babel/core@7.29.0) '@svgr/core': 8.1.0(typescript@5.9.3) '@svgr/hast-util-to-babel-ast': 8.0.0 svg-parser: 2.0.4 @@ -8591,11 +8917,11 @@ snapshots: '@svgr/webpack@8.1.0(typescript@5.9.3)': dependencies: - '@babel/core': 7.28.5 - '@babel/plugin-transform-react-constant-elements': 7.27.1(@babel/core@7.28.5) - '@babel/preset-env': 7.28.5(@babel/core@7.28.5) - '@babel/preset-react': 7.28.5(@babel/core@7.28.5) - '@babel/preset-typescript': 7.28.5(@babel/core@7.28.5) + '@babel/core': 7.29.0 + '@babel/plugin-transform-react-constant-elements': 7.27.1(@babel/core@7.29.0) + '@babel/preset-env': 7.29.0(@babel/core@7.29.0) + '@babel/preset-react': 7.28.5(@babel/core@7.29.0) + '@babel/preset-typescript': 7.28.5(@babel/core@7.29.0) '@svgr/core': 8.1.0(typescript@5.9.3) '@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0(typescript@5.9.3)) '@svgr/plugin-svgo': 8.1.0(@svgr/core@8.1.0(typescript@5.9.3))(typescript@5.9.3) @@ -8603,98 +8929,98 @@ snapshots: - supports-color - typescript - '@swc/core-darwin-arm64@1.15.4': + '@swc/core-darwin-arm64@1.15.11': optional: true - '@swc/core-darwin-x64@1.15.4': + '@swc/core-darwin-x64@1.15.11': optional: true - '@swc/core-linux-arm-gnueabihf@1.15.4': + '@swc/core-linux-arm-gnueabihf@1.15.11': optional: true - '@swc/core-linux-arm64-gnu@1.15.4': + '@swc/core-linux-arm64-gnu@1.15.11': optional: true - '@swc/core-linux-arm64-musl@1.15.4': + '@swc/core-linux-arm64-musl@1.15.11': optional: true - '@swc/core-linux-x64-gnu@1.15.4': + '@swc/core-linux-x64-gnu@1.15.11': optional: true - '@swc/core-linux-x64-musl@1.15.4': + '@swc/core-linux-x64-musl@1.15.11': optional: true - '@swc/core-win32-arm64-msvc@1.15.4': + '@swc/core-win32-arm64-msvc@1.15.11': optional: true - '@swc/core-win32-ia32-msvc@1.15.4': + '@swc/core-win32-ia32-msvc@1.15.11': optional: true - '@swc/core-win32-x64-msvc@1.15.4': + '@swc/core-win32-x64-msvc@1.15.11': optional: true - '@swc/core@1.15.4': + '@swc/core@1.15.11': dependencies: '@swc/counter': 0.1.3 '@swc/types': 0.1.25 optionalDependencies: - '@swc/core-darwin-arm64': 1.15.4 - '@swc/core-darwin-x64': 1.15.4 - '@swc/core-linux-arm-gnueabihf': 1.15.4 - '@swc/core-linux-arm64-gnu': 1.15.4 - '@swc/core-linux-arm64-musl': 1.15.4 - '@swc/core-linux-x64-gnu': 1.15.4 - '@swc/core-linux-x64-musl': 1.15.4 - '@swc/core-win32-arm64-msvc': 1.15.4 - '@swc/core-win32-ia32-msvc': 1.15.4 - '@swc/core-win32-x64-msvc': 1.15.4 + '@swc/core-darwin-arm64': 1.15.11 + '@swc/core-darwin-x64': 1.15.11 + '@swc/core-linux-arm-gnueabihf': 1.15.11 + '@swc/core-linux-arm64-gnu': 1.15.11 + '@swc/core-linux-arm64-musl': 1.15.11 + '@swc/core-linux-x64-gnu': 1.15.11 + '@swc/core-linux-x64-musl': 1.15.11 + '@swc/core-win32-arm64-msvc': 1.15.11 + '@swc/core-win32-ia32-msvc': 1.15.11 + '@swc/core-win32-x64-msvc': 1.15.11 '@swc/counter@0.1.3': {} - '@swc/html-darwin-arm64@1.15.4': + '@swc/html-darwin-arm64@1.15.11': optional: true - '@swc/html-darwin-x64@1.15.4': + '@swc/html-darwin-x64@1.15.11': optional: true - '@swc/html-linux-arm-gnueabihf@1.15.4': + '@swc/html-linux-arm-gnueabihf@1.15.11': optional: true - '@swc/html-linux-arm64-gnu@1.15.4': + '@swc/html-linux-arm64-gnu@1.15.11': optional: true - '@swc/html-linux-arm64-musl@1.15.4': + '@swc/html-linux-arm64-musl@1.15.11': optional: true - '@swc/html-linux-x64-gnu@1.15.4': + '@swc/html-linux-x64-gnu@1.15.11': optional: true - '@swc/html-linux-x64-musl@1.15.4': + '@swc/html-linux-x64-musl@1.15.11': optional: true - '@swc/html-win32-arm64-msvc@1.15.4': + '@swc/html-win32-arm64-msvc@1.15.11': optional: true - '@swc/html-win32-ia32-msvc@1.15.4': + '@swc/html-win32-ia32-msvc@1.15.11': optional: true - '@swc/html-win32-x64-msvc@1.15.4': + '@swc/html-win32-x64-msvc@1.15.11': optional: true - '@swc/html@1.15.4': + '@swc/html@1.15.11': dependencies: '@swc/counter': 0.1.3 optionalDependencies: - '@swc/html-darwin-arm64': 1.15.4 - '@swc/html-darwin-x64': 1.15.4 - '@swc/html-linux-arm-gnueabihf': 1.15.4 - '@swc/html-linux-arm64-gnu': 1.15.4 - '@swc/html-linux-arm64-musl': 1.15.4 - '@swc/html-linux-x64-gnu': 1.15.4 - '@swc/html-linux-x64-musl': 1.15.4 - '@swc/html-win32-arm64-msvc': 1.15.4 - '@swc/html-win32-ia32-msvc': 1.15.4 - '@swc/html-win32-x64-msvc': 1.15.4 + '@swc/html-darwin-arm64': 1.15.11 + '@swc/html-darwin-x64': 1.15.11 + '@swc/html-linux-arm-gnueabihf': 1.15.11 + '@swc/html-linux-arm64-gnu': 1.15.11 + '@swc/html-linux-arm64-musl': 1.15.11 + '@swc/html-linux-x64-gnu': 1.15.11 + '@swc/html-linux-x64-musl': 1.15.11 + '@swc/html-win32-arm64-msvc': 1.15.11 + '@swc/html-win32-ia32-msvc': 1.15.11 + '@swc/html-win32-x64-msvc': 1.15.11 '@swc/types@0.1.25': dependencies: @@ -8706,7 +9032,7 @@ snapshots: '@trysound/sax@0.2.0': {} - '@tsconfig/docusaurus@2.0.7': {} + '@tsconfig/docusaurus@2.0.9': {} '@tybys/wasm-util@0.10.1': dependencies: @@ -8716,20 +9042,20 @@ snapshots: '@types/body-parser@1.19.6': dependencies: '@types/connect': 3.4.38 - '@types/node': 24.10.4 + '@types/node': 25.3.0 '@types/bonjour@3.5.13': dependencies: - '@types/node': 24.10.4 + '@types/node': 25.3.0 '@types/connect-history-api-fallback@1.5.4': dependencies: - '@types/express-serve-static-core': 4.19.7 - '@types/node': 24.10.4 + '@types/express-serve-static-core': 4.19.8 + '@types/node': 25.3.0 '@types/connect@3.4.38': dependencies: - '@types/node': 24.10.4 + '@types/node': 25.3.0 '@types/debug@4.1.12': dependencies: @@ -8751,9 +9077,9 @@ snapshots: '@types/estree@1.0.8': {} - '@types/express-serve-static-core@4.19.7': + '@types/express-serve-static-core@4.19.8': dependencies: - '@types/node': 24.10.4 + '@types/node': 25.3.0 '@types/qs': 6.14.0 '@types/range-parser': 1.2.7 '@types/send': 1.2.1 @@ -8761,7 +9087,7 @@ snapshots: '@types/express@4.17.25': dependencies: '@types/body-parser': 1.19.6 - '@types/express-serve-static-core': 4.19.7 + '@types/express-serve-static-core': 4.19.8 '@types/qs': 6.14.0 '@types/serve-static': 1.15.10 @@ -8775,13 +9101,13 @@ snapshots: '@types/html-minifier-terser@6.1.0': {} - '@types/http-cache-semantics@4.0.4': {} + '@types/http-cache-semantics@4.2.0': {} '@types/http-errors@2.0.5': {} '@types/http-proxy@1.17.17': dependencies: - '@types/node': 24.10.4 + '@types/node': 25.3.0 '@types/istanbul-lib-coverage@2.0.6': {} @@ -8805,17 +9131,17 @@ snapshots: '@types/ms@2.1.0': {} - '@types/node-forge@1.3.14': - dependencies: - '@types/node': 24.10.4 - '@types/node@17.0.45': {} - '@types/node@24.10.4': + '@types/node@24.10.13': dependencies: undici-types: 7.16.0 - '@types/prismjs@1.26.5': {} + '@types/node@25.3.0': + dependencies: + undici-types: 7.18.2 + + '@types/prismjs@1.26.6': {} '@types/qs@6.14.0': {} @@ -8823,26 +9149,26 @@ snapshots: '@types/react-helmet@6.1.11': dependencies: - '@types/react': 19.2.7 + '@types/react': 19.2.14 '@types/react-router-config@5.0.11': dependencies: '@types/history': 4.7.11 - '@types/react': 19.2.7 + '@types/react': 19.2.14 '@types/react-router': 5.1.20 '@types/react-router-dom@5.3.3': dependencies: '@types/history': 4.7.11 - '@types/react': 19.2.7 + '@types/react': 19.2.14 '@types/react-router': 5.1.20 '@types/react-router@5.1.20': dependencies: '@types/history': 4.7.11 - '@types/react': 19.2.7 + '@types/react': 19.2.14 - '@types/react@19.2.7': + '@types/react@19.2.14': dependencies: csstype: 3.2.3 @@ -8850,16 +9176,16 @@ snapshots: '@types/sax@1.2.7': dependencies: - '@types/node': 24.10.4 + '@types/node': 25.3.0 '@types/send@0.17.6': dependencies: '@types/mime': 1.3.5 - '@types/node': 24.10.4 + '@types/node': 25.3.0 '@types/send@1.2.1': dependencies: - '@types/node': 24.10.4 + '@types/node': 25.3.0 '@types/serve-index@1.9.4': dependencies: @@ -8868,14 +9194,14 @@ snapshots: '@types/serve-static@1.15.10': dependencies: '@types/http-errors': 2.0.5 - '@types/node': 24.10.4 + '@types/node': 25.3.0 '@types/send': 0.17.6 '@types/sockjs@0.3.36': dependencies: - '@types/node': 24.10.4 + '@types/node': 25.3.0 - '@types/stylis@4.2.5': {} + '@types/stylis@4.2.7': {} '@types/trusted-types@2.0.7': optional: true @@ -8886,7 +9212,7 @@ snapshots: '@types/ws@8.18.1': dependencies: - '@types/node': 24.10.4 + '@types/node': 25.3.0 '@types/yargs-parser@21.0.3': {} @@ -8896,8 +9222,6 @@ snapshots: '@ungap/structured-clone@1.3.0': {} - '@vercel/oidc@3.0.5': {} - '@webassemblyjs/ast@1.14.1': dependencies: '@webassemblyjs/helper-numbers': 1.13.2 @@ -8983,19 +9307,19 @@ snapshots: mime-types: 2.1.35 negotiator: 0.6.3 - acorn-import-phases@1.0.4(acorn@8.15.0): + acorn-import-phases@1.0.4(acorn@8.16.0): dependencies: - acorn: 8.15.0 + acorn: 8.16.0 - acorn-jsx@5.3.2(acorn@8.15.0): + acorn-jsx@5.3.2(acorn@8.16.0): dependencies: - acorn: 8.15.0 + acorn: 8.16.0 - acorn-walk@8.3.4: + acorn-walk@8.3.5: dependencies: - acorn: 8.15.0 + acorn: 8.16.0 - acorn@8.15.0: {} + acorn@8.16.0: {} address@1.2.2: {} @@ -9006,62 +9330,47 @@ snapshots: clean-stack: 2.2.0 indent-string: 4.0.0 - ai@5.0.113(zod@4.1.13): - dependencies: - '@ai-sdk/gateway': 2.0.21(zod@4.1.13) - '@ai-sdk/provider': 2.0.0 - '@ai-sdk/provider-utils': 3.0.19(zod@4.1.13) - '@opentelemetry/api': 1.9.0 - zod: 4.1.13 - - ajv-formats@2.1.1(ajv@8.17.1): + ajv-formats@2.1.1(ajv@6.14.0): optionalDependencies: - ajv: 8.17.1 + ajv: 6.14.0 - ajv-keywords@3.5.2(ajv@6.12.6): + ajv-keywords@3.5.2(ajv@6.14.0): dependencies: - ajv: 6.12.6 + ajv: 6.14.0 - ajv-keywords@5.1.0(ajv@8.17.1): + ajv-keywords@5.1.0(ajv@6.14.0): dependencies: - ajv: 8.17.1 + ajv: 6.14.0 fast-deep-equal: 3.1.3 - ajv@6.12.6: + ajv@6.14.0: dependencies: fast-deep-equal: 3.1.3 fast-json-stable-stringify: 2.1.0 json-schema-traverse: 0.4.1 uri-js: 4.4.1 - ajv@8.17.1: - dependencies: - fast-deep-equal: 3.1.3 - fast-uri: 3.1.0 - json-schema-traverse: 1.0.0 - require-from-string: 2.0.2 - - algoliasearch-helper@3.26.1(algoliasearch@5.46.0): + algoliasearch-helper@3.27.1(algoliasearch@5.49.0): dependencies: '@algolia/events': 4.0.1 - algoliasearch: 5.46.0 + algoliasearch: 5.49.0 - algoliasearch@5.46.0: + algoliasearch@5.49.0: dependencies: - '@algolia/abtesting': 1.12.0 - '@algolia/client-abtesting': 5.46.0 - '@algolia/client-analytics': 5.46.0 - '@algolia/client-common': 5.46.0 - '@algolia/client-insights': 5.46.0 - '@algolia/client-personalization': 5.46.0 - '@algolia/client-query-suggestions': 5.46.0 - '@algolia/client-search': 5.46.0 - '@algolia/ingestion': 1.46.0 - '@algolia/monitoring': 1.46.0 - '@algolia/recommend': 5.46.0 - '@algolia/requester-browser-xhr': 5.46.0 - '@algolia/requester-fetch': 5.46.0 - '@algolia/requester-node-http': 5.46.0 + '@algolia/abtesting': 1.15.0 + '@algolia/client-abtesting': 5.49.0 + '@algolia/client-analytics': 5.49.0 + '@algolia/client-common': 5.49.0 + '@algolia/client-insights': 5.49.0 + '@algolia/client-personalization': 5.49.0 + '@algolia/client-query-suggestions': 5.49.0 + '@algolia/client-search': 5.49.0 + '@algolia/ingestion': 1.49.0 + '@algolia/monitoring': 1.49.0 + '@algolia/recommend': 5.49.0 + '@algolia/requester-browser-xhr': 5.49.0 + '@algolia/requester-fetch': 5.49.0 + '@algolia/requester-node-http': 5.49.0 ansi-align@3.0.1: dependencies: @@ -9100,20 +9409,26 @@ snapshots: array-union@2.1.0: {} + asn1js@3.0.7: + dependencies: + pvtsutils: 1.3.6 + pvutils: 1.1.5 + tslib: 2.8.1 + astring@1.9.0: {} asynckit@0.4.0: {} - autoprefixer@10.4.23(postcss@8.5.6): + autoprefixer@10.4.24(postcss@8.5.6): dependencies: browserslist: 4.28.1 - caniuse-lite: 1.0.30001760 + caniuse-lite: 1.0.30001772 fraction.js: 5.3.4 picocolors: 1.1.1 postcss: 8.5.6 postcss-value-parser: 4.2.0 - axios@1.13.2: + axios@1.13.5: dependencies: follow-redirects: 1.15.11(debug@4.4.3) form-data: 4.0.5 @@ -9121,46 +9436,54 @@ snapshots: transitivePeerDependencies: - debug - babel-loader@9.2.1(@babel/core@7.28.5)(webpack@5.103.0(@swc/core@1.15.4)): + babel-loader@9.2.1(@babel/core@7.29.0)(webpack@5.105.2(@swc/core@1.15.11)): dependencies: - '@babel/core': 7.28.5 + '@babel/core': 7.29.0 find-cache-dir: 4.0.0 schema-utils: 4.3.3 - webpack: 5.103.0(@swc/core@1.15.4) + webpack: 5.105.2(@swc/core@1.15.11) babel-plugin-dynamic-import-node@2.3.3: dependencies: object.assign: 4.1.7 - babel-plugin-polyfill-corejs2@0.4.14(@babel/core@7.28.5): + babel-plugin-polyfill-corejs2@0.4.15(@babel/core@7.29.0): dependencies: - '@babel/compat-data': 7.28.5 - '@babel/core': 7.28.5 - '@babel/helper-define-polyfill-provider': 0.6.5(@babel/core@7.28.5) + '@babel/compat-data': 7.29.0 + '@babel/core': 7.29.0 + '@babel/helper-define-polyfill-provider': 0.6.6(@babel/core@7.29.0) semver: 6.3.1 transitivePeerDependencies: - supports-color - babel-plugin-polyfill-corejs3@0.13.0(@babel/core@7.28.5): + babel-plugin-polyfill-corejs3@0.13.0(@babel/core@7.29.0): dependencies: - '@babel/core': 7.28.5 - '@babel/helper-define-polyfill-provider': 0.6.5(@babel/core@7.28.5) - core-js-compat: 3.47.0 + '@babel/core': 7.29.0 + '@babel/helper-define-polyfill-provider': 0.6.6(@babel/core@7.29.0) + core-js-compat: 3.48.0 transitivePeerDependencies: - supports-color - babel-plugin-polyfill-regenerator@0.6.5(@babel/core@7.28.5): + babel-plugin-polyfill-corejs3@0.14.0(@babel/core@7.29.0): dependencies: - '@babel/core': 7.28.5 - '@babel/helper-define-polyfill-provider': 0.6.5(@babel/core@7.28.5) + '@babel/core': 7.29.0 + '@babel/helper-define-polyfill-provider': 0.6.6(@babel/core@7.29.0) + core-js-compat: 3.48.0 + transitivePeerDependencies: + - supports-color + + babel-plugin-polyfill-regenerator@0.6.6(@babel/core@7.29.0): + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-define-polyfill-provider': 0.6.6(@babel/core@7.29.0) transitivePeerDependencies: - supports-color bail@2.0.2: {} - balanced-match@1.0.2: {} + balanced-match@4.0.4: {} - baseline-browser-mapping@2.9.7: {} + baseline-browser-mapping@2.10.0: {} batch@0.6.1: {} @@ -9182,7 +9505,7 @@ snapshots: http-errors: 2.0.1 iconv-lite: 0.4.24 on-finished: 2.4.1 - qs: 6.14.0 + qs: 6.14.2 raw-body: 2.5.3 type-is: 1.6.18 unpipe: 1.0.0 @@ -9218,14 +9541,9 @@ snapshots: widest-line: 4.0.1 wrap-ansi: 8.1.0 - brace-expansion@1.1.12: + brace-expansion@5.0.3: dependencies: - balanced-match: 1.0.2 - concat-map: 0.0.1 - - brace-expansion@2.0.2: - dependencies: - balanced-match: 1.0.2 + balanced-match: 4.0.4 braces@3.0.3: dependencies: @@ -9233,11 +9551,11 @@ snapshots: browserslist@4.28.1: dependencies: - baseline-browser-mapping: 2.9.7 - caniuse-lite: 1.0.30001760 - electron-to-chromium: 1.5.267 + baseline-browser-mapping: 2.10.0 + caniuse-lite: 1.0.30001772 + electron-to-chromium: 1.5.302 node-releases: 2.0.27 - update-browserslist-db: 1.2.2(browserslist@4.28.1) + update-browserslist-db: 1.2.3(browserslist@4.28.1) buffer-from@1.1.2: {} @@ -9249,16 +9567,18 @@ snapshots: bytes@3.1.2: {} + bytestreamjs@2.0.1: {} + cacheable-lookup@7.0.0: {} cacheable-request@10.2.14: dependencies: - '@types/http-cache-semantics': 4.0.4 + '@types/http-cache-semantics': 4.2.0 get-stream: 6.0.1 http-cache-semantics: 4.2.0 keyv: 4.5.4 mimic-response: 4.0.0 - normalize-url: 8.1.0 + normalize-url: 8.1.1 responselike: 3.0.0 call-bind-apply-helpers@1.0.2: @@ -9296,11 +9616,11 @@ snapshots: caniuse-api@3.0.0: dependencies: browserslist: 4.28.1 - caniuse-lite: 1.0.30001760 + caniuse-lite: 1.0.30001772 lodash.memoize: 4.1.2 lodash.uniq: 4.5.0 - caniuse-lite@1.0.30001760: {} + caniuse-lite@1.0.30001772: {} ccount@2.0.1: {} @@ -9340,18 +9660,18 @@ snapshots: parse5: 7.3.0 parse5-htmlparser2-tree-adapter: 7.1.0 - cheerio@1.1.2: + cheerio@1.2.0: dependencies: cheerio-select: 2.1.0 dom-serializer: 2.0.0 domhandler: 5.0.3 domutils: 3.2.2 encoding-sniffer: 0.2.1 - htmlparser2: 10.0.0 + htmlparser2: 10.1.0 parse5: 7.3.0 parse5-htmlparser2-tree-adapter: 7.1.0 parse5-parser-stream: 7.1.2 - undici: 7.16.0 + undici: 7.22.0 whatwg-mimetype: 4.0.0 chokidar@3.6.0: @@ -9454,8 +9774,6 @@ snapshots: transitivePeerDependencies: - supports-color - concat-map@0.0.1: {} - concurrently@9.2.1: dependencies: chalk: 4.1.2 @@ -9496,7 +9814,7 @@ snapshots: cookie@0.7.2: {} - copy-webpack-plugin@11.0.0(webpack@5.103.0(@swc/core@1.15.4)): + copy-webpack-plugin@11.0.0(webpack@5.105.2(@swc/core@1.15.11)): dependencies: fast-glob: 3.3.3 glob-parent: 6.0.2 @@ -9504,15 +9822,15 @@ snapshots: normalize-path: 3.0.0 schema-utils: 4.3.3 serialize-javascript: 6.0.2 - webpack: 5.103.0(@swc/core@1.15.4) + webpack: 5.105.2(@swc/core@1.15.11) - core-js-compat@3.47.0: + core-js-compat@3.48.0: dependencies: browserslist: 4.28.1 - core-js-pure@3.47.0: {} + core-js-pure@3.48.0: {} - core-js@3.47.0: {} + core-js@3.48.0: {} core-util-is@1.0.3: {} @@ -9542,7 +9860,7 @@ snapshots: css-color-keywords@1.0.0: {} - css-declaration-sorter@7.3.0(postcss@8.5.6): + css-declaration-sorter@7.3.1(postcss@8.5.6): dependencies: postcss: 8.5.6 @@ -9553,7 +9871,7 @@ snapshots: postcss-selector-parser: 7.1.1 postcss-value-parser: 4.2.0 - css-loader@6.11.0(@rspack/core@1.6.7)(webpack@5.103.0(@swc/core@1.15.4)): + css-loader@6.11.0(@rspack/core@1.7.6)(webpack@5.105.2(@swc/core@1.15.11)): dependencies: icss-utils: 5.1.0(postcss@8.5.6) postcss: 8.5.6 @@ -9562,12 +9880,12 @@ snapshots: postcss-modules-scope: 3.2.1(postcss@8.5.6) postcss-modules-values: 4.0.0(postcss@8.5.6) postcss-value-parser: 4.2.0 - semver: 7.7.3 + semver: 7.7.4 optionalDependencies: - '@rspack/core': 1.6.7 - webpack: 5.103.0(@swc/core@1.15.4) + '@rspack/core': 1.7.6 + webpack: 5.105.2(@swc/core@1.15.11) - css-minimizer-webpack-plugin@5.0.1(clean-css@5.3.3)(webpack@5.103.0(@swc/core@1.15.4)): + css-minimizer-webpack-plugin@5.0.1(clean-css@5.3.3)(webpack@5.105.2(@swc/core@1.15.11)): dependencies: '@jridgewell/trace-mapping': 0.3.31 cssnano: 6.1.2(postcss@8.5.6) @@ -9575,7 +9893,7 @@ snapshots: postcss: 8.5.6 schema-utils: 4.3.3 serialize-javascript: 6.0.2 - webpack: 5.103.0(@swc/core@1.15.4) + webpack: 5.105.2(@swc/core@1.15.11) optionalDependencies: clean-css: 5.3.3 @@ -9622,13 +9940,13 @@ snapshots: css-what@6.2.2: {} - cssdb@8.5.2: {} + cssdb@8.8.0: {} cssesc@3.0.0: {} cssnano-preset-advanced@6.1.2(postcss@8.5.6): dependencies: - autoprefixer: 10.4.23(postcss@8.5.6) + autoprefixer: 10.4.24(postcss@8.5.6) browserslist: 4.28.1 cssnano-preset-default: 6.1.2(postcss@8.5.6) postcss: 8.5.6 @@ -9640,7 +9958,7 @@ snapshots: cssnano-preset-default@6.1.2(postcss@8.5.6): dependencies: browserslist: 4.28.1 - css-declaration-sorter: 7.3.0(postcss@8.5.6) + css-declaration-sorter: 7.3.1(postcss@8.5.6) cssnano-utils: 4.0.2(postcss@8.5.6) postcss: 8.5.6 postcss-calc: 9.0.1(postcss@8.5.6) @@ -9685,22 +10003,21 @@ snapshots: dependencies: css-tree: 2.2.1 - cssstyle@5.3.4(postcss@8.5.6): + cssstyle@6.1.0: dependencies: - '@asamuzakjp/css-color': 4.1.0 - '@csstools/css-syntax-patches-for-csstree': 1.0.14(postcss@8.5.6) + '@asamuzakjp/css-color': 5.0.0 + '@csstools/css-syntax-patches-for-csstree': 1.0.28 css-tree: 3.1.0 - transitivePeerDependencies: - - postcss - - csstype@3.1.3: {} + lru-cache: 11.2.6 csstype@3.2.3: {} - data-urls@6.0.0: + data-urls@7.0.0: dependencies: - whatwg-mimetype: 4.0.0 - whatwg-url: 15.1.0 + whatwg-mimetype: 5.0.0 + whatwg-url: 16.0.1 + transitivePeerDependencies: + - '@noble/hashes' debounce@1.2.1: {} @@ -9716,7 +10033,7 @@ snapshots: decko@1.2.0: {} - decode-named-character-reference@1.2.0: + decode-named-character-reference@1.3.0: dependencies: character-entities: 2.0.2 @@ -9730,7 +10047,7 @@ snapshots: default-browser-id@5.0.1: {} - default-browser@5.4.0: + default-browser@5.5.0: dependencies: bundle-name: 4.1.0 default-browser-id: 5.0.1 @@ -9786,11 +10103,11 @@ snapshots: dependencies: '@leichtgewicht/ip-codec': 2.0.5 - docusaurus-plugin-redoc@2.5.0(@docusaurus/utils@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(core-js@3.47.0)(mobx@6.15.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(styled-components@6.1.19(react-dom@19.2.3(react@19.2.3))(react@19.2.3)): + docusaurus-plugin-redoc@2.5.0(@docusaurus/utils@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(core-js@3.48.0)(mobx@6.15.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(styled-components@6.3.11(react-dom@19.2.4(react@19.2.4))(react@19.2.4)): dependencies: - '@docusaurus/utils': 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@docusaurus/utils': 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@redocly/openapi-core': 1.16.0 - redoc: 2.4.0(core-js@3.47.0)(mobx@6.15.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(styled-components@6.1.19(react-dom@19.2.3(react@19.2.3))(react@19.2.3)) + redoc: 2.4.0(core-js@3.48.0)(mobx@6.15.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(styled-components@6.3.11(react-dom@19.2.4(react@19.2.4))(react@19.2.4)) transitivePeerDependencies: - core-js - encoding @@ -9801,18 +10118,18 @@ snapshots: - styled-components - supports-color - docusaurus-theme-redoc@2.5.0(@docusaurus/theme-common@3.9.2(@docusaurus/plugin-content-docs@3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3))(@rspack/core@1.6.7)(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3))(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(core-js@3.47.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(webpack@5.103.0(@swc/core@1.15.4)): + docusaurus-theme-redoc@2.5.0(@docusaurus/theme-common@3.9.2(@docusaurus/plugin-content-docs@3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.4))(@rspack/core@1.7.6)(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(core-js@3.48.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(webpack@5.105.2(@swc/core@1.15.11)): dependencies: - '@docusaurus/theme-common': 3.9.2(@docusaurus/plugin-content-docs@3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3))(@rspack/core@1.6.7)(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3))(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@docusaurus/theme-common': 3.9.2(@docusaurus/plugin-content-docs@3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.4))(@rspack/core@1.7.6)(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@redocly/openapi-core': 1.16.0 clsx: 1.2.1 - lodash: 4.17.21 + lodash: 4.17.23 mobx: 6.15.0 postcss: 8.5.6 postcss-prefix-selector: 1.16.1(postcss@8.5.6) - redoc: 2.4.0(core-js@3.47.0)(mobx@6.15.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(styled-components@6.1.19(react-dom@19.2.3(react@19.2.3))(react@19.2.3)) - styled-components: 6.1.19(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - webpack: 5.103.0(@swc/core@1.15.4) + redoc: 2.4.0(core-js@3.48.0)(mobx@6.15.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(styled-components@6.3.11(react-dom@19.2.4(react@19.2.4))(react@19.2.4)) + styled-components: 6.3.11(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + webpack: 5.105.2(@swc/core@1.15.11) transitivePeerDependencies: - core-js - encoding @@ -9884,7 +10201,7 @@ snapshots: ee-first@1.1.1: {} - electron-to-chromium@1.5.267: {} + electron-to-chromium@1.5.302: {} emoji-regex@8.0.0: {} @@ -9896,8 +10213,6 @@ snapshots: emoticon@4.1.0: {} - encodeurl@1.0.2: {} - encodeurl@2.0.0: {} encoding-sniffer@0.2.1: @@ -9905,7 +10220,7 @@ snapshots: iconv-lite: 0.6.3 whatwg-encoding: 3.1.1 - enhanced-resolve@5.18.4: + enhanced-resolve@5.19.0: dependencies: graceful-fs: 4.2.11 tapable: 2.3.0 @@ -9916,6 +10231,8 @@ snapshots: entities@6.0.1: {} + entities@7.0.1: {} + error-ex@1.3.4: dependencies: is-arrayish: 0.2.1 @@ -9924,7 +10241,7 @@ snapshots: es-errors@1.3.0: {} - es-module-lexer@1.7.0: {} + es-module-lexer@2.0.0: {} es-object-atoms@1.1.1: dependencies: @@ -9949,7 +10266,7 @@ snapshots: esast-util-from-js@2.0.1: dependencies: '@types/estree-jsx': 1.0.5 - acorn: 8.15.0 + acorn: 8.16.0 esast-util-from-estree: 2.0.0 vfile-message: 4.0.3 @@ -10025,17 +10342,15 @@ snapshots: eval@0.1.8: dependencies: - '@types/node': 24.10.4 + '@types/node': 25.3.0 require-like: 0.1.2 eventemitter3@4.0.7: {} - eventemitter3@5.0.1: {} + eventemitter3@5.0.4: {} events@3.3.0: {} - eventsource-parser@3.0.6: {} - execa@5.1.1: dependencies: cross-spawn: 7.0.6 @@ -10071,11 +10386,11 @@ snapshots: parseurl: 1.3.3 path-to-regexp: 0.1.12 proxy-addr: 2.0.7 - qs: 6.14.0 + qs: 6.14.2 range-parser: 1.2.1 safe-buffer: 5.2.1 - send: 0.19.1 - serve-static: 1.16.2 + send: 0.19.2 + serve-static: 1.16.3 setprototypeof: 1.2.0 statuses: 2.0.2 type-is: 1.6.18 @@ -10106,11 +10421,11 @@ snapshots: fast-uri@3.1.0: {} - fast-xml-parser@4.5.3: + fast-xml-parser@5.3.7: dependencies: - strnum: 1.1.2 + strnum: 2.1.2 - fastq@1.19.1: + fastq@1.20.1: dependencies: reusify: 1.1.0 @@ -10130,11 +10445,11 @@ snapshots: dependencies: escape-string-regexp: 1.0.5 - file-loader@6.2.0(webpack@5.103.0(@swc/core@1.15.4)): + file-loader@6.2.0(webpack@5.105.2(@swc/core@1.15.11)): dependencies: loader-utils: 2.0.4 schema-utils: 3.3.0 - webpack: 5.103.0(@swc/core@1.15.4) + webpack: 5.105.2(@swc/core@1.15.11) fill-range@7.1.1: dependencies: @@ -10194,7 +10509,7 @@ snapshots: jsonfile: 6.2.0 universalify: 2.0.1 - fs-extra@11.3.2: + fs-extra@11.3.3: dependencies: graceful-fs: 4.2.11 jsonfile: 6.2.0 @@ -10347,7 +10662,7 @@ snapshots: mdast-util-to-hast: 13.2.1 parse5: 7.3.0 unist-util-position: 5.0.0 - unist-util-visit: 5.0.0 + unist-util-visit: 5.1.0 vfile: 6.0.3 web-namespaces: 2.0.1 zwitch: 2.0.4 @@ -10419,7 +10734,7 @@ snapshots: history@4.10.1: dependencies: - '@babel/runtime': 7.28.4 + '@babel/runtime': 7.28.6 loose-envify: 1.4.0 resolve-pathname: 3.0.0 tiny-invariant: 1.3.3 @@ -10437,9 +10752,11 @@ snapshots: readable-stream: 2.3.8 wbuf: 1.7.3 - html-encoding-sniffer@4.0.0: + html-encoding-sniffer@6.0.0: dependencies: - whatwg-encoding: 3.1.1 + '@exodus/bytes': 1.14.1 + transitivePeerDependencies: + - '@noble/hashes' html-escaper@2.0.2: {} @@ -10451,7 +10768,7 @@ snapshots: he: 1.2.0 param-case: 3.0.4 relateurl: 0.2.7 - terser: 5.44.1 + terser: 5.46.0 html-minifier-terser@7.2.0: dependencies: @@ -10461,29 +10778,29 @@ snapshots: entities: 4.5.0 param-case: 3.0.4 relateurl: 0.2.7 - terser: 5.44.1 + terser: 5.46.0 html-tags@3.3.1: {} html-void-elements@3.0.0: {} - html-webpack-plugin@5.6.5(@rspack/core@1.6.7)(webpack@5.103.0(@swc/core@1.15.4)): + html-webpack-plugin@5.6.6(@rspack/core@1.7.6)(webpack@5.105.2(@swc/core@1.15.11)): dependencies: '@types/html-minifier-terser': 6.1.0 html-minifier-terser: 6.1.0 - lodash: 4.17.21 + lodash: 4.17.23 pretty-error: 4.0.0 tapable: 2.3.0 optionalDependencies: - '@rspack/core': 1.6.7 - webpack: 5.103.0(@swc/core@1.15.4) + '@rspack/core': 1.7.6 + webpack: 5.105.2(@swc/core@1.15.11) - htmlparser2@10.0.0: + htmlparser2@10.1.0: dependencies: domelementtype: 2.3.0 domhandler: 5.0.3 domutils: 3.2.2 - entities: 6.0.1 + entities: 7.0.1 htmlparser2@6.1.0: dependencies: @@ -10503,19 +10820,12 @@ snapshots: http-deceiver@1.2.7: {} - http-errors@1.6.3: + http-errors@1.8.1: dependencies: depd: 1.1.2 - inherits: 2.0.3 - setprototypeof: 1.1.0 - statuses: 1.5.0 - - http-errors@2.0.0: - dependencies: - depd: 2.0.0 inherits: 2.0.4 setprototypeof: 1.2.0 - statuses: 2.0.1 + statuses: 1.5.0 toidentifier: 1.0.1 http-errors@2.0.1: @@ -10604,8 +10914,6 @@ snapshots: infima@0.2.0-alpha.45: {} - inherits@2.0.3: {} - inherits@2.0.4: {} ini@1.3.8: {} @@ -10702,7 +11010,7 @@ snapshots: dependencies: is-docker: 2.2.1 - is-wsl@3.1.0: + is-wsl@3.1.1: dependencies: is-inside-container: 1.0.0 @@ -10716,21 +11024,19 @@ snapshots: isobject@3.0.1: {} - isomorphic-dompurify@2.34.0(postcss@8.5.6): + isomorphic-dompurify@3.0.0: dependencies: dompurify: 3.3.1 - jsdom: 27.3.0(postcss@8.5.6) + jsdom: 28.1.0 transitivePeerDependencies: - - bufferutil + - '@noble/hashes' - canvas - - postcss - supports-color - - utf-8-validate jest-util@29.7.0: dependencies: '@jest/types': 29.6.3 - '@types/node': 24.10.4 + '@types/node': 25.3.0 chalk: 4.1.2 ci-info: 3.9.0 graceful-fs: 4.2.11 @@ -10738,13 +11044,13 @@ snapshots: jest-worker@27.5.1: dependencies: - '@types/node': 24.10.4 + '@types/node': 25.3.0 merge-stream: 2.0.0 supports-color: 8.1.1 jest-worker@29.7.0: dependencies: - '@types/node': 24.10.4 + '@types/node': 25.3.0 jest-util: 29.7.0 merge-stream: 2.0.0 supports-color: 8.1.1 @@ -10772,14 +11078,16 @@ snapshots: dependencies: argparse: 2.0.1 - jsdom@27.3.0(postcss@8.5.6): + jsdom@28.1.0: dependencies: - '@acemir/cssom': 0.9.29 - '@asamuzakjp/dom-selector': 6.7.6 - cssstyle: 5.3.4(postcss@8.5.6) - data-urls: 6.0.0 + '@acemir/cssom': 0.9.31 + '@asamuzakjp/dom-selector': 6.8.1 + '@bramus/specificity': 2.4.2 + '@exodus/bytes': 1.14.1 + cssstyle: 6.1.0 + data-urls: 7.0.0 decimal.js: 10.6.0 - html-encoding-sniffer: 4.0.0 + html-encoding-sniffer: 6.0.0 http-proxy-agent: 7.0.2 https-proxy-agent: 7.0.6 is-potential-custom-element-name: 1.0.1 @@ -10787,18 +11095,15 @@ snapshots: saxes: 6.0.0 symbol-tree: 3.2.4 tough-cookie: 6.0.0 + undici: 7.22.0 w3c-xmlserializer: 5.0.0 - webidl-conversions: 8.0.0 - whatwg-encoding: 3.1.1 - whatwg-mimetype: 4.0.0 - whatwg-url: 15.1.0 - ws: 8.18.3 + webidl-conversions: 8.0.1 + whatwg-mimetype: 5.0.0 + whatwg-url: 16.0.1 xml-name-validator: 5.0.0 transitivePeerDependencies: - - bufferutil - - postcss + - '@noble/hashes' - supports-color - - utf-8-validate jsesc@3.1.0: {} @@ -10814,8 +11119,6 @@ snapshots: json-schema-traverse@1.0.0: {} - json-schema@0.4.0: {} - json5@2.2.3: {} jsonfile@6.2.0: @@ -10840,61 +11143,61 @@ snapshots: dependencies: package-json: 8.1.1 - launch-editor@2.12.0: + launch-editor@2.13.0: dependencies: picocolors: 1.1.1 shell-quote: 1.8.3 leven@3.1.0: {} - lightningcss-android-arm64@1.30.2: + lightningcss-android-arm64@1.31.1: optional: true - lightningcss-darwin-arm64@1.30.2: + lightningcss-darwin-arm64@1.31.1: optional: true - lightningcss-darwin-x64@1.30.2: + lightningcss-darwin-x64@1.31.1: optional: true - lightningcss-freebsd-x64@1.30.2: + lightningcss-freebsd-x64@1.31.1: optional: true - lightningcss-linux-arm-gnueabihf@1.30.2: + lightningcss-linux-arm-gnueabihf@1.31.1: optional: true - lightningcss-linux-arm64-gnu@1.30.2: + lightningcss-linux-arm64-gnu@1.31.1: optional: true - lightningcss-linux-arm64-musl@1.30.2: + lightningcss-linux-arm64-musl@1.31.1: optional: true - lightningcss-linux-x64-gnu@1.30.2: + lightningcss-linux-x64-gnu@1.31.1: optional: true - lightningcss-linux-x64-musl@1.30.2: + lightningcss-linux-x64-musl@1.31.1: optional: true - lightningcss-win32-arm64-msvc@1.30.2: + lightningcss-win32-arm64-msvc@1.31.1: optional: true - lightningcss-win32-x64-msvc@1.30.2: + lightningcss-win32-x64-msvc@1.31.1: optional: true - lightningcss@1.30.2: + lightningcss@1.31.1: dependencies: detect-libc: 2.1.2 optionalDependencies: - lightningcss-android-arm64: 1.30.2 - lightningcss-darwin-arm64: 1.30.2 - lightningcss-darwin-x64: 1.30.2 - lightningcss-freebsd-x64: 1.30.2 - lightningcss-linux-arm-gnueabihf: 1.30.2 - lightningcss-linux-arm64-gnu: 1.30.2 - lightningcss-linux-arm64-musl: 1.30.2 - lightningcss-linux-x64-gnu: 1.30.2 - lightningcss-linux-x64-musl: 1.30.2 - lightningcss-win32-arm64-msvc: 1.30.2 - lightningcss-win32-x64-msvc: 1.30.2 + lightningcss-android-arm64: 1.31.1 + lightningcss-darwin-arm64: 1.31.1 + lightningcss-darwin-x64: 1.31.1 + lightningcss-freebsd-x64: 1.31.1 + lightningcss-linux-arm-gnueabihf: 1.31.1 + lightningcss-linux-arm64-gnu: 1.31.1 + lightningcss-linux-arm64-musl: 1.31.1 + lightningcss-linux-x64-gnu: 1.31.1 + lightningcss-linux-x64-musl: 1.31.1 + lightningcss-win32-arm64-msvc: 1.31.1 + lightningcss-win32-x64-msvc: 1.31.1 lilconfig@3.1.3: {} @@ -10920,7 +11223,7 @@ snapshots: lodash.uniq@4.5.0: {} - lodash@4.17.21: {} + lodash@4.17.23: {} longest-streak@3.1.0: {} @@ -10934,7 +11237,7 @@ snapshots: lowercase-keys@3.0.0: {} - lru-cache@11.2.4: {} + lru-cache@11.2.6: {} lru-cache@5.1.1: dependencies: @@ -10954,9 +11257,7 @@ snapshots: markdown-table@3.0.4: {} - marked@16.4.2: {} - - marked@17.0.1: {} + marked@17.0.3: {} marked@4.3.0: {} @@ -10968,7 +11269,7 @@ snapshots: '@types/unist': 3.0.3 ccount: 2.0.1 devlop: 1.1.0 - mdast-util-from-markdown: 2.0.2 + mdast-util-from-markdown: 2.0.3 mdast-util-to-markdown: 2.1.2 parse-entities: 4.0.2 stringify-entities: 4.0.4 @@ -10983,11 +11284,11 @@ snapshots: unist-util-is: 6.0.1 unist-util-visit-parents: 6.0.2 - mdast-util-from-markdown@2.0.2: + mdast-util-from-markdown@2.0.3: dependencies: '@types/mdast': 4.0.4 '@types/unist': 3.0.3 - decode-named-character-reference: 1.2.0 + decode-named-character-reference: 1.3.0 devlop: 1.1.0 mdast-util-to-string: 4.0.0 micromark: 4.0.2 @@ -11005,7 +11306,7 @@ snapshots: '@types/mdast': 4.0.4 devlop: 1.1.0 escape-string-regexp: 5.0.0 - mdast-util-from-markdown: 2.0.2 + mdast-util-from-markdown: 2.0.3 mdast-util-to-markdown: 2.1.2 micromark-extension-frontmatter: 2.0.0 transitivePeerDependencies: @@ -11023,7 +11324,7 @@ snapshots: dependencies: '@types/mdast': 4.0.4 devlop: 1.1.0 - mdast-util-from-markdown: 2.0.2 + mdast-util-from-markdown: 2.0.3 mdast-util-to-markdown: 2.1.2 micromark-util-normalize-identifier: 2.0.1 transitivePeerDependencies: @@ -11032,7 +11333,7 @@ snapshots: mdast-util-gfm-strikethrough@2.0.0: dependencies: '@types/mdast': 4.0.4 - mdast-util-from-markdown: 2.0.2 + mdast-util-from-markdown: 2.0.3 mdast-util-to-markdown: 2.1.2 transitivePeerDependencies: - supports-color @@ -11042,7 +11343,7 @@ snapshots: '@types/mdast': 4.0.4 devlop: 1.1.0 markdown-table: 3.0.4 - mdast-util-from-markdown: 2.0.2 + mdast-util-from-markdown: 2.0.3 mdast-util-to-markdown: 2.1.2 transitivePeerDependencies: - supports-color @@ -11051,14 +11352,14 @@ snapshots: dependencies: '@types/mdast': 4.0.4 devlop: 1.1.0 - mdast-util-from-markdown: 2.0.2 + mdast-util-from-markdown: 2.0.3 mdast-util-to-markdown: 2.1.2 transitivePeerDependencies: - supports-color mdast-util-gfm@3.1.0: dependencies: - mdast-util-from-markdown: 2.0.2 + mdast-util-from-markdown: 2.0.3 mdast-util-gfm-autolink-literal: 2.0.1 mdast-util-gfm-footnote: 2.1.0 mdast-util-gfm-strikethrough: 2.0.0 @@ -11074,7 +11375,7 @@ snapshots: '@types/hast': 3.0.4 '@types/mdast': 4.0.4 devlop: 1.1.0 - mdast-util-from-markdown: 2.0.2 + mdast-util-from-markdown: 2.0.3 mdast-util-to-markdown: 2.1.2 transitivePeerDependencies: - supports-color @@ -11087,7 +11388,7 @@ snapshots: '@types/unist': 3.0.3 ccount: 2.0.1 devlop: 1.1.0 - mdast-util-from-markdown: 2.0.2 + mdast-util-from-markdown: 2.0.3 mdast-util-to-markdown: 2.1.2 parse-entities: 4.0.2 stringify-entities: 4.0.4 @@ -11098,7 +11399,7 @@ snapshots: mdast-util-mdx@3.0.0: dependencies: - mdast-util-from-markdown: 2.0.2 + mdast-util-from-markdown: 2.0.3 mdast-util-mdx-expression: 2.0.1 mdast-util-mdx-jsx: 3.2.0 mdast-util-mdxjs-esm: 2.0.1 @@ -11112,7 +11413,7 @@ snapshots: '@types/hast': 3.0.4 '@types/mdast': 4.0.4 devlop: 1.1.0 - mdast-util-from-markdown: 2.0.2 + mdast-util-from-markdown: 2.0.3 mdast-util-to-markdown: 2.1.2 transitivePeerDependencies: - supports-color @@ -11131,7 +11432,7 @@ snapshots: micromark-util-sanitize-uri: 2.0.1 trim-lines: 3.0.1 unist-util-position: 5.0.0 - unist-util-visit: 5.0.0 + unist-util-visit: 5.1.0 vfile: 6.0.3 mdast-util-to-markdown@2.1.2: @@ -11143,7 +11444,7 @@ snapshots: mdast-util-to-string: 4.0.0 micromark-util-classify-character: 2.0.1 micromark-util-decode-string: 2.0.1 - unist-util-visit: 5.0.0 + unist-util-visit: 5.1.0 zwitch: 2.0.4 mdast-util-to-string@4.0.0: @@ -11158,8 +11459,16 @@ snapshots: media-typer@0.3.0: {} - memfs@4.51.1: + memfs@4.56.10(tslib@2.8.1): dependencies: + '@jsonjoy.com/fs-core': 4.56.10(tslib@2.8.1) + '@jsonjoy.com/fs-fsa': 4.56.10(tslib@2.8.1) + '@jsonjoy.com/fs-node': 4.56.10(tslib@2.8.1) + '@jsonjoy.com/fs-node-builtins': 4.56.10(tslib@2.8.1) + '@jsonjoy.com/fs-node-to-fsa': 4.56.10(tslib@2.8.1) + '@jsonjoy.com/fs-node-utils': 4.56.10(tslib@2.8.1) + '@jsonjoy.com/fs-print': 4.56.10(tslib@2.8.1) + '@jsonjoy.com/fs-snapshot': 4.56.10(tslib@2.8.1) '@jsonjoy.com/json-pack': 1.21.0(tslib@2.8.1) '@jsonjoy.com/util': 1.9.0(tslib@2.8.1) glob-to-regex.js: 1.2.0(tslib@2.8.1) @@ -11177,7 +11486,7 @@ snapshots: micromark-core-commonmark@2.0.3: dependencies: - decode-named-character-reference: 1.2.0 + decode-named-character-reference: 1.3.0 devlop: 1.1.0 micromark-factory-destination: 2.0.1 micromark-factory-label: 2.0.1 @@ -11311,8 +11620,8 @@ snapshots: micromark-extension-mdxjs@3.0.0: dependencies: - acorn: 8.15.0 - acorn-jsx: 5.3.2(acorn@8.15.0) + acorn: 8.16.0 + acorn-jsx: 5.3.2(acorn@8.16.0) micromark-extension-mdx-expression: 3.0.1 micromark-extension-mdx-jsx: 3.0.2 micromark-extension-mdx-md: 2.0.0 @@ -11400,7 +11709,7 @@ snapshots: micromark-util-decode-string@2.0.1: dependencies: - decode-named-character-reference: 1.2.0 + decode-named-character-reference: 1.3.0 micromark-util-character: 2.1.1 micromark-util-decode-numeric-character-reference: 2.0.2 micromark-util-symbol: 2.0.1 @@ -11452,7 +11761,7 @@ snapshots: dependencies: '@types/debug': 4.1.12 debug: 4.4.3 - decode-named-character-reference: 1.2.0 + decode-named-character-reference: 1.3.0 devlop: 1.1.0 micromark-core-commonmark: 2.0.3 micromark-factory-space: 2.0.1 @@ -11501,39 +11810,35 @@ snapshots: mimic-response@4.0.0: {} - mini-css-extract-plugin@2.9.4(webpack@5.103.0(@swc/core@1.15.4)): + mini-css-extract-plugin@2.10.0(webpack@5.105.2(@swc/core@1.15.11)): dependencies: schema-utils: 4.3.3 tapable: 2.3.0 - webpack: 5.103.0(@swc/core@1.15.4) + webpack: 5.105.2(@swc/core@1.15.11) minimalistic-assert@1.0.1: {} - minimatch@3.1.2: + minimatch@10.2.2: dependencies: - brace-expansion: 1.1.12 - - minimatch@5.1.6: - dependencies: - brace-expansion: 2.0.2 + brace-expansion: 5.0.3 minimist@1.2.8: {} - mobx-react-lite@4.1.1(mobx@6.15.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3): + mobx-react-lite@4.1.1(mobx@6.15.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4): dependencies: mobx: 6.15.0 - react: 19.2.3 - use-sync-external-store: 1.6.0(react@19.2.3) + react: 19.2.4 + use-sync-external-store: 1.6.0(react@19.2.4) optionalDependencies: - react-dom: 19.2.3(react@19.2.3) + react-dom: 19.2.4(react@19.2.4) - mobx-react@9.2.1(mobx@6.15.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3): + mobx-react@9.2.1(mobx@6.15.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4): dependencies: mobx: 6.15.0 - mobx-react-lite: 4.1.1(mobx@6.15.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - react: 19.2.3 + mobx-react-lite: 4.1.1(mobx@6.15.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + react: 19.2.4 optionalDependencies: - react-dom: 19.2.3(react@19.2.3) + react-dom: 19.2.4(react@19.2.4) mobx@6.15.0: {} @@ -11576,8 +11881,6 @@ snapshots: dependencies: whatwg-url: 5.0.0 - node-forge@1.3.3: {} - node-readfiles@0.2.0: dependencies: es6-promise: 3.3.1 @@ -11586,7 +11889,7 @@ snapshots: normalize-path@3.0.0: {} - normalize-url@8.1.0: {} + normalize-url@8.1.1: {} npm-run-path@4.0.1: dependencies: @@ -11598,11 +11901,11 @@ snapshots: dependencies: boolbase: 1.0.0 - null-loader@4.0.1(webpack@5.103.0(@swc/core@1.15.4)): + null-loader@4.0.1(webpack@5.105.2(@swc/core@1.15.11)): dependencies: loader-utils: 2.0.4 schema-utils: 3.3.0 - webpack: 5.103.0(@swc/core@1.15.4) + webpack: 5.105.2(@swc/core@1.15.11) oas-kit-common@1.0.8: dependencies: @@ -11664,7 +11967,7 @@ snapshots: open@10.2.0: dependencies: - default-browser: 5.4.0 + default-browser: 5.5.0 define-lazy-prop: 3.0.0 is-inside-container: 1.0.0 wsl-utils: 0.1.0 @@ -11675,10 +11978,10 @@ snapshots: is-docker: 2.2.1 is-wsl: 2.2.0 - openapi-sampler@1.6.2: + openapi-sampler@1.7.0: dependencies: '@types/json-schema': 7.0.15 - fast-xml-parser: 4.5.3 + fast-xml-parser: 5.3.7 json-pointer: 0.6.2 opener@1.5.2: {} @@ -11717,9 +12020,9 @@ snapshots: package-json@8.1.1: dependencies: got: 12.6.1 - registry-auth-token: 5.1.0 + registry-auth-token: 5.1.1 registry-url: 6.0.1 - semver: 7.7.3 + semver: 7.7.4 param-case@3.0.4: dependencies: @@ -11735,14 +12038,14 @@ snapshots: '@types/unist': 2.0.11 character-entities-legacy: 3.0.0 character-reference-invalid: 2.0.1 - decode-named-character-reference: 1.2.0 + decode-named-character-reference: 1.3.0 is-alphanumerical: 2.0.1 is-decimal: 2.0.1 is-hexadecimal: 2.0.1 parse-json@5.2.0: dependencies: - '@babel/code-frame': 7.27.1 + '@babel/code-frame': 7.29.0 error-ex: 1.3.4 json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 @@ -11803,11 +12106,20 @@ snapshots: dependencies: find-up: 6.3.0 + pkijs@3.3.3: + dependencies: + '@noble/hashes': 1.4.0 + asn1js: 3.0.7 + bytestreamjs: 2.0.1 + pvtsutils: 1.3.6 + pvutils: 1.1.5 + tslib: 2.8.1 + pluralize@8.0.0: {} polished@4.3.1: dependencies: - '@babel/runtime': 7.28.4 + '@babel/runtime': 7.28.6 postcss-attribute-case-insensitive@7.0.1(postcss@8.5.6): dependencies: @@ -11951,13 +12263,13 @@ snapshots: '@csstools/utilities': 2.0.0(postcss@8.5.6) postcss: 8.5.6 - postcss-loader@7.3.4(postcss@8.5.6)(typescript@5.9.3)(webpack@5.103.0(@swc/core@1.15.4)): + postcss-loader@7.3.4(postcss@8.5.6)(typescript@5.9.3)(webpack@5.105.2(@swc/core@1.15.11)): dependencies: cosmiconfig: 8.3.6(typescript@5.9.3) jiti: 1.21.7 postcss: 8.5.6 - semver: 7.7.3 - webpack: 5.103.0(@swc/core@1.15.4) + semver: 7.7.4 + webpack: 5.105.2(@swc/core@1.15.11) transitivePeerDependencies: - typescript @@ -12111,7 +12423,7 @@ snapshots: dependencies: postcss: 8.5.6 - postcss-preset-env@10.5.0(postcss@8.5.6): + postcss-preset-env@10.6.1(postcss@8.5.6): dependencies: '@csstools/postcss-alpha-function': 1.0.1(postcss@8.5.6) '@csstools/postcss-cascade-layers': 5.0.2(postcss@8.5.6) @@ -12138,25 +12450,27 @@ snapshots: '@csstools/postcss-media-minmax': 2.0.9(postcss@8.5.6) '@csstools/postcss-media-queries-aspect-ratio-number-values': 3.0.5(postcss@8.5.6) '@csstools/postcss-nested-calc': 4.0.0(postcss@8.5.6) - '@csstools/postcss-normalize-display-values': 4.0.0(postcss@8.5.6) + '@csstools/postcss-normalize-display-values': 4.0.1(postcss@8.5.6) '@csstools/postcss-oklab-function': 4.0.12(postcss@8.5.6) '@csstools/postcss-position-area-property': 1.0.0(postcss@8.5.6) '@csstools/postcss-progressive-custom-properties': 4.2.1(postcss@8.5.6) + '@csstools/postcss-property-rule-prelude-list': 1.0.0(postcss@8.5.6) '@csstools/postcss-random-function': 2.0.1(postcss@8.5.6) '@csstools/postcss-relative-color-syntax': 3.0.12(postcss@8.5.6) '@csstools/postcss-scope-pseudo-class': 4.0.1(postcss@8.5.6) '@csstools/postcss-sign-functions': 1.1.4(postcss@8.5.6) '@csstools/postcss-stepped-value-functions': 4.0.9(postcss@8.5.6) + '@csstools/postcss-syntax-descriptor-syntax-production': 1.0.1(postcss@8.5.6) '@csstools/postcss-system-ui-font-family': 1.0.0(postcss@8.5.6) '@csstools/postcss-text-decoration-shorthand': 4.0.3(postcss@8.5.6) '@csstools/postcss-trigonometric-functions': 4.0.9(postcss@8.5.6) '@csstools/postcss-unset-value': 4.0.0(postcss@8.5.6) - autoprefixer: 10.4.23(postcss@8.5.6) + autoprefixer: 10.4.24(postcss@8.5.6) browserslist: 4.28.1 css-blank-pseudo: 7.0.1(postcss@8.5.6) css-has-pseudo: 7.0.3(postcss@8.5.6) css-prefers-color-scheme: 10.0.0(postcss@8.5.6) - cssdb: 8.5.2 + cssdb: 8.8.0 postcss: 8.5.6 postcss-attribute-case-insensitive: 7.0.1(postcss@8.5.6) postcss-clamp: 4.1.0(postcss@8.5.6) @@ -12258,20 +12572,20 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 - prettier@3.7.4: {} + prettier@3.8.1: {} pretty-error@4.0.0: dependencies: - lodash: 4.17.21 + lodash: 4.17.23 renderkid: 3.0.0 pretty-time@1.1.0: {} - prism-react-renderer@2.4.1(react@19.2.3): + prism-react-renderer@2.4.1(react@19.2.4): dependencies: - '@types/prismjs': 1.26.5 + '@types/prismjs': 1.26.6 clsx: 2.1.1 - react: 19.2.3 + react: 19.2.4 prismjs@1.30.0: {} @@ -12305,7 +12619,13 @@ snapshots: dependencies: escape-goat: 4.0.0 - qs@6.14.0: + pvtsutils@1.3.6: + dependencies: + tslib: 2.8.1 + + pvutils@1.1.5: {} + + qs@6.14.2: dependencies: side-channel: 1.1.0 @@ -12335,62 +12655,62 @@ snapshots: minimist: 1.2.8 strip-json-comments: 2.0.1 - react-dom@19.2.3(react@19.2.3): + react-dom@19.2.4(react@19.2.4): dependencies: - react: 19.2.3 + react: 19.2.4 scheduler: 0.27.0 react-fast-compare@3.2.2: {} react-is@16.13.1: {} - react-json-view-lite@2.5.0(react@19.2.3): + react-json-view-lite@2.5.0(react@19.2.4): dependencies: - react: 19.2.3 + react: 19.2.4 - react-loadable-ssr-addon-v5-slorber@1.0.1(@docusaurus/react-loadable@6.0.0(react@19.2.3))(webpack@5.103.0(@swc/core@1.15.4)): + react-loadable-ssr-addon-v5-slorber@1.0.1(@docusaurus/react-loadable@6.0.0(react@19.2.4))(webpack@5.105.2(@swc/core@1.15.11)): dependencies: - '@babel/runtime': 7.28.4 - react-loadable: '@docusaurus/react-loadable@6.0.0(react@19.2.3)' - webpack: 5.103.0(@swc/core@1.15.4) + '@babel/runtime': 7.28.6 + react-loadable: '@docusaurus/react-loadable@6.0.0(react@19.2.4)' + webpack: 5.105.2(@swc/core@1.15.11) - react-router-config@5.1.1(react-router@5.3.4(react@19.2.3))(react@19.2.3): + react-router-config@5.1.1(react-router@5.3.4(react@19.2.4))(react@19.2.4): dependencies: - '@babel/runtime': 7.28.4 - react: 19.2.3 - react-router: 5.3.4(react@19.2.3) + '@babel/runtime': 7.28.6 + react: 19.2.4 + react-router: 5.3.4(react@19.2.4) - react-router-dom@5.3.4(react@19.2.3): + react-router-dom@5.3.4(react@19.2.4): dependencies: - '@babel/runtime': 7.28.4 + '@babel/runtime': 7.28.6 history: 4.10.1 loose-envify: 1.4.0 prop-types: 15.8.1 - react: 19.2.3 - react-router: 5.3.4(react@19.2.3) + react: 19.2.4 + react-router: 5.3.4(react@19.2.4) tiny-invariant: 1.3.3 tiny-warning: 1.0.3 - react-router@5.3.4(react@19.2.3): + react-router@5.3.4(react@19.2.4): dependencies: - '@babel/runtime': 7.28.4 + '@babel/runtime': 7.28.6 history: 4.10.1 hoist-non-react-statics: 3.3.2 loose-envify: 1.4.0 path-to-regexp: 1.9.0 prop-types: 15.8.1 - react: 19.2.3 + react: 19.2.4 react-is: 16.13.1 tiny-invariant: 1.3.3 tiny-warning: 1.0.3 - react-tabs@6.1.0(react@19.2.3): + react-tabs@6.1.0(react@19.2.4): dependencies: clsx: 2.1.1 prop-types: 15.8.1 - react: 19.2.3 + react: 19.2.4 - react@19.2.3: {} + react@19.2.4: {} readable-stream@2.3.8: dependencies: @@ -12418,10 +12738,10 @@ snapshots: estree-util-build-jsx: 3.0.1 vfile: 6.0.3 - recma-jsx@1.0.1(acorn@8.15.0): + recma-jsx@1.0.1(acorn@8.16.0): dependencies: - acorn: 8.15.0 - acorn-jsx: 5.3.2(acorn@8.15.0) + acorn: 8.16.0 + acorn-jsx: 5.3.2(acorn@8.16.0) estree-util-to-js: 2.0.0 recma-parse: 1.0.0 recma-stringify: 1.0.0 @@ -12441,32 +12761,32 @@ snapshots: unified: 11.0.5 vfile: 6.0.3 - redoc@2.4.0(core-js@3.47.0)(mobx@6.15.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(styled-components@6.1.19(react-dom@19.2.3(react@19.2.3))(react@19.2.3)): + redoc@2.4.0(core-js@3.48.0)(mobx@6.15.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(styled-components@6.3.11(react-dom@19.2.4(react@19.2.4))(react@19.2.4)): dependencies: '@redocly/openapi-core': 1.16.0 classnames: 2.5.1 - core-js: 3.47.0 + core-js: 3.48.0 decko: 1.2.0 dompurify: 3.3.1 - eventemitter3: 5.0.1 + eventemitter3: 5.0.4 json-pointer: 0.6.2 lunr: 2.3.9 mark.js: 8.11.1 marked: 4.3.0 mobx: 6.15.0 - mobx-react: 9.2.1(mobx@6.15.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - openapi-sampler: 1.6.2 + mobx-react: 9.2.1(mobx@6.15.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + openapi-sampler: 1.7.0 path-browserify: 1.0.1 perfect-scrollbar: 1.5.6 polished: 4.3.1 prismjs: 1.30.0 prop-types: 15.8.1 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - react-tabs: 6.1.0(react@19.2.3) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + react-tabs: 6.1.0(react@19.2.4) slugify: 1.4.7 stickyfill: 1.1.1 - styled-components: 6.1.19(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + styled-components: 6.3.11(react-dom@19.2.4(react@19.2.4))(react@19.2.4) swagger2openapi: 7.0.8 url-template: 2.0.8 transitivePeerDependencies: @@ -12474,12 +12794,12 @@ snapshots: - react-native - supports-color - redocusaurus@2.5.0(@docusaurus/theme-common@3.9.2(@docusaurus/plugin-content-docs@3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3))(@rspack/core@1.6.7)(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3))(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(@docusaurus/utils@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(core-js@3.47.0)(mobx@6.15.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(styled-components@6.1.19(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(webpack@5.103.0(@swc/core@1.15.4)): + redocusaurus@2.5.0(@docusaurus/theme-common@3.9.2(@docusaurus/plugin-content-docs@3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.4))(@rspack/core@1.7.6)(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@docusaurus/utils@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(core-js@3.48.0)(mobx@6.15.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(styled-components@6.3.11(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(webpack@5.105.2(@swc/core@1.15.11)): dependencies: - '@docusaurus/theme-common': 3.9.2(@docusaurus/plugin-content-docs@3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3))(@rspack/core@1.6.7)(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3))(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@docusaurus/utils': 3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - docusaurus-plugin-redoc: 2.5.0(@docusaurus/utils@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(core-js@3.47.0)(mobx@6.15.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(styled-components@6.1.19(react-dom@19.2.3(react@19.2.3))(react@19.2.3)) - docusaurus-theme-redoc: 2.5.0(@docusaurus/theme-common@3.9.2(@docusaurus/plugin-content-docs@3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)))(@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3))(@rspack/core@1.6.7)(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3))(@swc/core@1.15.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(core-js@3.47.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(webpack@5.103.0(@swc/core@1.15.4)) + '@docusaurus/theme-common': 3.9.2(@docusaurus/plugin-content-docs@3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.4))(@rspack/core@1.7.6)(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@docusaurus/utils': 3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + docusaurus-plugin-redoc: 2.5.0(@docusaurus/utils@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(core-js@3.48.0)(mobx@6.15.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(styled-components@6.3.11(react-dom@19.2.4(react@19.2.4))(react@19.2.4)) + docusaurus-theme-redoc: 2.5.0(@docusaurus/theme-common@3.9.2(@docusaurus/plugin-content-docs@3.9.2(@docusaurus/faster@3.9.2(@docusaurus/types@3.9.2(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)))(@mdx-js/react@3.1.1(@types/react@19.2.14)(react@19.2.4))(@rspack/core@1.7.6)(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(@swc/core@1.15.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(core-js@3.48.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(webpack@5.105.2(@swc/core@1.15.11)) transitivePeerDependencies: - core-js - encoding @@ -12491,6 +12811,8 @@ snapshots: - supports-color - webpack + reflect-metadata@0.2.2: {} + reftools@1.1.9: {} regenerate-unicode-properties@10.2.2: @@ -12508,9 +12830,9 @@ snapshots: unicode-match-property-ecmascript: 2.0.0 unicode-match-property-value-ecmascript: 2.2.1 - registry-auth-token@5.1.0: + registry-auth-token@5.1.1: dependencies: - '@pnpm/npm-conf': 2.3.1 + '@pnpm/npm-conf': 3.0.2 registry-url@6.0.1: dependencies: @@ -12585,7 +12907,7 @@ snapshots: remark-parse@11.0.0: dependencies: '@types/mdast': 4.0.4 - mdast-util-from-markdown: 2.0.2 + mdast-util-from-markdown: 2.0.3 micromark-util-types: 2.0.2 unified: 11.0.5 transitivePeerDependencies: @@ -12610,7 +12932,7 @@ snapshots: css-select: 4.3.0 dom-converter: 0.2.0 htmlparser2: 6.1.0 - lodash: 4.17.21 + lodash: 4.17.23 strip-ansi: 6.0.1 repeat-string@1.6.1: {} @@ -12666,7 +12988,7 @@ snapshots: safer-buffer@2.1.2: {} - sax@1.4.3: {} + sax@1.4.4: {} saxes@6.0.0: dependencies: @@ -12679,15 +13001,15 @@ snapshots: schema-utils@3.3.0: dependencies: '@types/json-schema': 7.0.15 - ajv: 6.12.6 - ajv-keywords: 3.5.2(ajv@6.12.6) + ajv: 6.14.0 + ajv-keywords: 3.5.2(ajv@6.14.0) schema-utils@4.3.3: dependencies: '@types/json-schema': 7.0.15 - ajv: 8.17.1 - ajv-formats: 2.1.1(ajv@8.17.1) - ajv-keywords: 5.1.0(ajv@8.17.1) + ajv: 6.14.0 + ajv-formats: 2.1.1(ajv@6.14.0) + ajv-keywords: 5.1.0(ajv@6.14.0) search-insights@2.17.3: {} @@ -12698,38 +13020,20 @@ snapshots: select-hose@2.0.0: {} - selfsigned@2.4.1: + selfsigned@5.5.0: dependencies: - '@types/node-forge': 1.3.14 - node-forge: 1.3.3 + '@peculiar/x509': 1.14.3 + pkijs: 3.3.3 semver-diff@4.0.0: dependencies: - semver: 7.7.3 + semver: 7.7.4 semver@6.3.1: {} - semver@7.7.3: {} + semver@7.7.4: {} - send@0.19.0: - dependencies: - debug: 2.6.9 - depd: 2.0.0 - destroy: 1.2.0 - encodeurl: 1.0.2 - escape-html: 1.0.3 - etag: 1.8.1 - fresh: 0.5.2 - http-errors: 2.0.0 - mime: 1.6.0 - ms: 2.1.3 - on-finished: 2.4.1 - range-parser: 1.2.1 - statuses: 2.0.1 - transitivePeerDependencies: - - supports-color - - send@0.19.1: + send@0.19.2: dependencies: debug: 2.6.9 depd: 2.0.0 @@ -12738,12 +13042,12 @@ snapshots: escape-html: 1.0.3 etag: 1.8.1 fresh: 0.5.2 - http-errors: 2.0.0 + http-errors: 2.0.1 mime: 1.6.0 ms: 2.1.3 on-finished: 2.4.1 range-parser: 1.2.1 - statuses: 2.0.1 + statuses: 2.0.2 transitivePeerDependencies: - supports-color @@ -12756,29 +13060,29 @@ snapshots: bytes: 3.0.0 content-disposition: 0.5.2 mime-types: 2.1.18 - minimatch: 3.1.2 + minimatch: 10.2.2 path-is-inside: 1.0.2 path-to-regexp: 3.3.0 range-parser: 1.2.0 - serve-index@1.9.1: + serve-index@1.9.2: dependencies: accepts: 1.3.8 batch: 0.6.1 debug: 2.6.9 escape-html: 1.0.3 - http-errors: 1.6.3 + http-errors: 1.8.1 mime-types: 2.1.35 parseurl: 1.3.3 transitivePeerDependencies: - supports-color - serve-static@1.16.2: + serve-static@1.16.3: dependencies: encodeurl: 2.0.0 escape-html: 1.0.3 parseurl: 1.3.3 - send: 0.19.0 + send: 0.19.2 transitivePeerDependencies: - supports-color @@ -12791,8 +13095,6 @@ snapshots: gopd: 1.2.0 has-property-descriptors: 1.0.2 - setprototypeof@1.1.0: {} - setprototypeof@1.2.0: {} shallow-clone@3.0.1: @@ -12878,7 +13180,7 @@ snapshots: '@types/node': 17.0.45 '@types/sax': 1.2.7 arg: 5.0.2 - sax: 1.4.3 + sax: 1.4.4 skin-tone@2.0.0: dependencies: @@ -12945,8 +13247,6 @@ snapshots: statuses@1.5.0: {} - statuses@2.0.1: {} - statuses@2.0.2: {} std-env@3.10.0: {} @@ -13000,7 +13300,7 @@ snapshots: strip-json-comments@3.1.1: {} - strnum@1.1.2: {} + strnum@2.1.2: {} style-to-js@1.1.21: dependencies: @@ -13010,19 +13310,20 @@ snapshots: dependencies: inline-style-parser: 0.2.7 - styled-components@6.1.19(react-dom@19.2.3(react@19.2.3))(react@19.2.3): + styled-components@6.3.11(react-dom@19.2.4(react@19.2.4))(react@19.2.4): dependencies: - '@emotion/is-prop-valid': 1.2.2 - '@emotion/unitless': 0.8.1 - '@types/stylis': 4.2.5 + '@emotion/is-prop-valid': 1.4.0 + '@emotion/unitless': 0.10.0 + '@types/stylis': 4.2.7 css-to-react-native: 3.2.0 - csstype: 3.1.3 + csstype: 3.2.3 postcss: 8.4.49 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) + react: 19.2.4 shallowequal: 1.1.0 - stylis: 4.3.2 - tslib: 2.6.2 + stylis: 4.3.6 + tslib: 2.8.1 + optionalDependencies: + react-dom: 19.2.4(react@19.2.4) stylehacks@6.1.1(postcss@8.5.6): dependencies: @@ -13030,7 +13331,7 @@ snapshots: postcss: 8.5.6 postcss-selector-parser: 6.1.2 - stylis@4.3.2: {} + stylis@4.3.6: {} supports-color@7.2.0: dependencies: @@ -13070,37 +13371,31 @@ snapshots: transitivePeerDependencies: - encoding - swc-loader@0.2.6(@swc/core@1.15.4)(webpack@5.103.0(@swc/core@1.15.4)): + swc-loader@0.2.7(@swc/core@1.15.11)(webpack@5.105.2(@swc/core@1.15.11)): dependencies: - '@swc/core': 1.15.4 + '@swc/core': 1.15.11 '@swc/counter': 0.1.3 - webpack: 5.103.0(@swc/core@1.15.4) - - swr@2.3.7(react@19.2.3): - dependencies: - dequal: 2.0.3 - react: 19.2.3 - use-sync-external-store: 1.6.0(react@19.2.3) + webpack: 5.105.2(@swc/core@1.15.11) symbol-tree@3.2.4: {} tapable@2.3.0: {} - terser-webpack-plugin@5.3.16(@swc/core@1.15.4)(webpack@5.103.0(@swc/core@1.15.4)): + terser-webpack-plugin@5.3.16(@swc/core@1.15.11)(webpack@5.105.2(@swc/core@1.15.11)): dependencies: '@jridgewell/trace-mapping': 0.3.31 jest-worker: 27.5.1 schema-utils: 4.3.3 serialize-javascript: 6.0.2 - terser: 5.44.1 - webpack: 5.103.0(@swc/core@1.15.4) + terser: 5.46.0 + webpack: 5.105.2(@swc/core@1.15.11) optionalDependencies: - '@swc/core': 1.15.4 + '@swc/core': 1.15.11 - terser@5.44.1: + terser@5.46.0: dependencies: '@jridgewell/source-map': 0.3.11 - acorn: 8.15.0 + acorn: 8.16.0 commander: 2.20.3 source-map-support: 0.5.21 @@ -13108,8 +13403,6 @@ snapshots: dependencies: tslib: 2.8.1 - throttleit@2.1.0: {} - thunky@1.1.0: {} tiny-invariant@1.3.3: {} @@ -13118,11 +13411,11 @@ snapshots: tinypool@1.1.1: {} - tldts-core@7.0.19: {} + tldts-core@7.0.23: {} - tldts@7.0.19: + tldts@7.0.23: dependencies: - tldts-core: 7.0.19 + tldts-core: 7.0.23 to-regex-range@5.0.1: dependencies: @@ -13134,7 +13427,7 @@ snapshots: tough-cookie@6.0.0: dependencies: - tldts: 7.0.19 + tldts: 7.0.23 tr46@0.0.3: {} @@ -13152,10 +13445,14 @@ snapshots: trough@2.2.0: {} - tslib@2.6.2: {} + tslib@1.14.1: {} tslib@2.8.1: {} + tsyringe@4.10.0: + dependencies: + tslib: 1.14.1 + type-fest@0.21.3: {} type-fest@1.4.0: {} @@ -13175,7 +13472,9 @@ snapshots: undici-types@7.16.0: {} - undici@7.16.0: {} + undici-types@7.18.2: {} + + undici@7.22.0: {} unicode-canonical-property-names-ecmascript@2.0.1: {} @@ -13225,7 +13524,7 @@ snapshots: '@types/unist': 3.0.3 unist-util-is: 6.0.1 - unist-util-visit@5.0.0: + unist-util-visit@5.1.0: dependencies: '@types/unist': 3.0.3 unist-util-is: 6.0.1 @@ -13235,7 +13534,7 @@ snapshots: unpipe@1.0.0: {} - update-browserslist-db@1.2.2(browserslist@4.28.1): + update-browserslist-db@1.2.3(browserslist@4.28.1): dependencies: browserslist: 4.28.1 escalade: 3.2.0 @@ -13254,7 +13553,7 @@ snapshots: is-yarn-global: 0.4.1 latest-version: 7.0.0 pupa: 3.3.0 - semver: 7.7.3 + semver: 7.7.4 semver-diff: 4.0.0 xdg-basedir: 5.1.0 @@ -13262,20 +13561,20 @@ snapshots: dependencies: punycode: 2.3.1 - url-loader@4.1.1(file-loader@6.2.0(webpack@5.103.0(@swc/core@1.15.4)))(webpack@5.103.0(@swc/core@1.15.4)): + url-loader@4.1.1(file-loader@6.2.0(webpack@5.105.2(@swc/core@1.15.11)))(webpack@5.105.2(@swc/core@1.15.11)): dependencies: loader-utils: 2.0.4 mime-types: 2.1.35 schema-utils: 3.3.0 - webpack: 5.103.0(@swc/core@1.15.4) + webpack: 5.105.2(@swc/core@1.15.11) optionalDependencies: - file-loader: 6.2.0(webpack@5.103.0(@swc/core@1.15.4)) + file-loader: 6.2.0(webpack@5.105.2(@swc/core@1.15.11)) url-template@2.0.8: {} - use-sync-external-store@1.6.0(react@19.2.3): + use-sync-external-store@1.6.0(react@19.2.4): dependencies: - react: 19.2.3 + react: 19.2.4 util-deprecate@1.0.2: {} @@ -13310,7 +13609,7 @@ snapshots: dependencies: xml-name-validator: 5.0.0 - watchpack@2.4.4: + watchpack@2.5.1: dependencies: glob-to-regexp: 0.4.1 graceful-fs: 4.2.11 @@ -13323,13 +13622,13 @@ snapshots: webidl-conversions@3.0.1: {} - webidl-conversions@8.0.0: {} + webidl-conversions@8.0.1: {} webpack-bundle-analyzer@4.10.2: dependencies: '@discoveryjs/json-ext': 0.5.7 - acorn: 8.15.0 - acorn-walk: 8.3.4 + acorn: 8.16.0 + acorn-walk: 8.3.5 commander: 7.2.0 debounce: 1.2.1 escape-string-regexp: 4.0.0 @@ -13343,23 +13642,25 @@ snapshots: - bufferutil - utf-8-validate - webpack-dev-middleware@7.4.5(webpack@5.103.0(@swc/core@1.15.4)): + webpack-dev-middleware@7.4.5(tslib@2.8.1)(webpack@5.105.2(@swc/core@1.15.11)): dependencies: colorette: 2.0.20 - memfs: 4.51.1 + memfs: 4.56.10(tslib@2.8.1) mime-types: 3.0.2 on-finished: 2.4.1 range-parser: 1.2.1 schema-utils: 4.3.3 optionalDependencies: - webpack: 5.103.0(@swc/core@1.15.4) + webpack: 5.105.2(@swc/core@1.15.11) + transitivePeerDependencies: + - tslib - webpack-dev-server@5.2.2(debug@4.4.3)(webpack@5.103.0(@swc/core@1.15.4)): + webpack-dev-server@5.2.3(debug@4.4.3)(tslib@2.8.1)(webpack@5.105.2(@swc/core@1.15.11)): dependencies: '@types/bonjour': 3.5.13 '@types/connect-history-api-fallback': 1.5.4 '@types/express': 4.17.25 - '@types/express-serve-static-core': 4.19.7 + '@types/express-serve-static-core': 4.19.8 '@types/serve-index': 1.9.4 '@types/serve-static': 1.15.10 '@types/sockjs': 0.3.36 @@ -13374,22 +13675,23 @@ snapshots: graceful-fs: 4.2.11 http-proxy-middleware: 2.0.9(@types/express@4.17.25)(debug@4.4.3) ipaddr.js: 2.3.0 - launch-editor: 2.12.0 + launch-editor: 2.13.0 open: 10.2.0 p-retry: 6.2.1 schema-utils: 4.3.3 - selfsigned: 2.4.1 - serve-index: 1.9.1 + selfsigned: 5.5.0 + serve-index: 1.9.2 sockjs: 0.3.24 spdy: 4.0.2 - webpack-dev-middleware: 7.4.5(webpack@5.103.0(@swc/core@1.15.4)) - ws: 8.18.3 + webpack-dev-middleware: 7.4.5(tslib@2.8.1)(webpack@5.105.2(@swc/core@1.15.11)) + ws: 8.19.0 optionalDependencies: - webpack: 5.103.0(@swc/core@1.15.4) + webpack: 5.105.2(@swc/core@1.15.11) transitivePeerDependencies: - bufferutil - debug - supports-color + - tslib - utf-8-validate webpack-merge@5.10.0: @@ -13404,9 +13706,9 @@ snapshots: flat: 5.0.2 wildcard: 2.0.1 - webpack-sources@3.3.3: {} + webpack-sources@3.3.4: {} - webpack@5.103.0(@swc/core@1.15.4): + webpack@5.105.2(@swc/core@1.15.11): dependencies: '@types/eslint-scope': 3.7.7 '@types/estree': 1.0.8 @@ -13414,12 +13716,12 @@ snapshots: '@webassemblyjs/ast': 1.14.1 '@webassemblyjs/wasm-edit': 1.14.1 '@webassemblyjs/wasm-parser': 1.14.1 - acorn: 8.15.0 - acorn-import-phases: 1.0.4(acorn@8.15.0) + acorn: 8.16.0 + acorn-import-phases: 1.0.4(acorn@8.16.0) browserslist: 4.28.1 chrome-trace-event: 1.0.4 - enhanced-resolve: 5.18.4 - es-module-lexer: 1.7.0 + enhanced-resolve: 5.19.0 + es-module-lexer: 2.0.0 eslint-scope: 5.1.1 events: 3.3.0 glob-to-regexp: 0.4.1 @@ -13430,15 +13732,15 @@ snapshots: neo-async: 2.6.2 schema-utils: 4.3.3 tapable: 2.3.0 - terser-webpack-plugin: 5.3.16(@swc/core@1.15.4)(webpack@5.103.0(@swc/core@1.15.4)) - watchpack: 2.4.4 - webpack-sources: 3.3.3 + terser-webpack-plugin: 5.3.16(@swc/core@1.15.11)(webpack@5.105.2(@swc/core@1.15.11)) + watchpack: 2.5.1 + webpack-sources: 3.3.4 transitivePeerDependencies: - '@swc/core' - esbuild - uglify-js - webpackbar@6.0.1(webpack@5.103.0(@swc/core@1.15.4)): + webpackbar@6.0.1(webpack@5.105.2(@swc/core@1.15.11)): dependencies: ansi-escapes: 4.3.2 chalk: 4.1.2 @@ -13447,7 +13749,7 @@ snapshots: markdown-table: 2.0.0 pretty-time: 1.1.0 std-env: 3.10.0 - webpack: 5.103.0(@swc/core@1.15.4) + webpack: 5.105.2(@swc/core@1.15.11) wrap-ansi: 7.0.0 websocket-driver@0.7.4: @@ -13464,10 +13766,15 @@ snapshots: whatwg-mimetype@4.0.0: {} - whatwg-url@15.1.0: + whatwg-mimetype@5.0.0: {} + + whatwg-url@16.0.1: dependencies: + '@exodus/bytes': 1.14.1 tr46: 6.0.0 - webidl-conversions: 8.0.0 + webidl-conversions: 8.0.1 + transitivePeerDependencies: + - '@noble/hashes' whatwg-url@5.0.0: dependencies: @@ -13505,17 +13812,17 @@ snapshots: ws@7.5.10: {} - ws@8.18.3: {} + ws@8.19.0: {} wsl-utils@0.1.0: dependencies: - is-wsl: 3.1.0 + is-wsl: 3.1.1 xdg-basedir@5.1.0: {} xml-js@1.6.11: dependencies: - sax: 1.4.3 + sax: 1.4.4 xml-name-validator@5.0.0: {} @@ -13545,6 +13852,4 @@ snapshots: yocto-queue@1.2.2: {} - zod@4.1.13: {} - zwitch@2.0.4: {} diff --git a/docs/versioned_docs/version-3.10/92-development/woodpecker-architecture.png b/docs/versioned_docs/version-3.10/92-development/woodpecker-architecture.png deleted file mode 100644 index 22f6a054a..000000000 Binary files a/docs/versioned_docs/version-3.10/92-development/woodpecker-architecture.png and /dev/null differ diff --git a/docs/versioned_docs/version-3.11/20-usage/40-secrets.md b/docs/versioned_docs/version-3.11/20-usage/40-secrets.md index 6cdaef519..a38599635 100644 --- a/docs/versioned_docs/version-3.11/20-usage/40-secrets.md +++ b/docs/versioned_docs/version-3.11/20-usage/40-secrets.md @@ -106,7 +106,7 @@ woodpecker-cli repo secret add \ Create the secret and limit it to a single image: ```diff - woodpecker-cli secret add \ + woodpecker-cli repo secret add \ --repository octocat/hello-world \ + --image woodpeckerci/plugin-s3 \ --name aws_access_key_id \ diff --git a/docs/versioned_docs/version-3.12/30-administration/05-installation/20-helm-chart.md b/docs/versioned_docs/version-3.12/30-administration/05-installation/20-helm-chart.md index d421f8959..54a14eddb 100644 --- a/docs/versioned_docs/version-3.12/30-administration/05-installation/20-helm-chart.md +++ b/docs/versioned_docs/version-3.12/30-administration/05-installation/20-helm-chart.md @@ -3,8 +3,7 @@ Woodpecker provides a [Helm chart](https://github.com/woodpecker-ci/helm) for Kubernetes environments: ```bash -helm repo add woodpecker oci://ghcr.io/woodpecker-ci/helm -helm install woodpecker woodpecker/woodpecker +helm install woodpecker oci://ghcr.io/woodpecker-ci/helm/woodpecker --version ``` ## Metrics diff --git a/docs/versioned_docs/version-3.10/10-intro/index.md b/docs/versioned_docs/version-3.13/10-intro/index.md similarity index 100% rename from docs/versioned_docs/version-3.10/10-intro/index.md rename to docs/versioned_docs/version-3.13/10-intro/index.md diff --git a/docs/versioned_docs/version-3.10/20-usage/10-intro.md b/docs/versioned_docs/version-3.13/20-usage/10-intro.md similarity index 100% rename from docs/versioned_docs/version-3.10/20-usage/10-intro.md rename to docs/versioned_docs/version-3.13/20-usage/10-intro.md diff --git a/docs/versioned_docs/version-3.10/20-usage/100-troubleshooting.md b/docs/versioned_docs/version-3.13/20-usage/100-troubleshooting.md similarity index 100% rename from docs/versioned_docs/version-3.10/20-usage/100-troubleshooting.md rename to docs/versioned_docs/version-3.13/20-usage/100-troubleshooting.md diff --git a/docs/versioned_docs/version-3.10/20-usage/15-terminology/architecture.excalidraw b/docs/versioned_docs/version-3.13/20-usage/15-terminology/architecture.excalidraw similarity index 100% rename from docs/versioned_docs/version-3.10/20-usage/15-terminology/architecture.excalidraw rename to docs/versioned_docs/version-3.13/20-usage/15-terminology/architecture.excalidraw diff --git a/docs/versioned_docs/version-3.10/20-usage/15-terminology/architecture.svg b/docs/versioned_docs/version-3.13/20-usage/15-terminology/architecture.svg similarity index 100% rename from docs/versioned_docs/version-3.10/20-usage/15-terminology/architecture.svg rename to docs/versioned_docs/version-3.13/20-usage/15-terminology/architecture.svg diff --git a/docs/versioned_docs/version-3.10/20-usage/15-terminology/index.md b/docs/versioned_docs/version-3.13/20-usage/15-terminology/index.md similarity index 100% rename from docs/versioned_docs/version-3.10/20-usage/15-terminology/index.md rename to docs/versioned_docs/version-3.13/20-usage/15-terminology/index.md diff --git a/docs/versioned_docs/version-3.10/20-usage/15-terminology/pipeline-workflow-step.excalidraw b/docs/versioned_docs/version-3.13/20-usage/15-terminology/pipeline-workflow-step.excalidraw similarity index 100% rename from docs/versioned_docs/version-3.10/20-usage/15-terminology/pipeline-workflow-step.excalidraw rename to docs/versioned_docs/version-3.13/20-usage/15-terminology/pipeline-workflow-step.excalidraw diff --git a/docs/versioned_docs/version-3.10/20-usage/15-terminology/pipeline-workflow-step.svg b/docs/versioned_docs/version-3.13/20-usage/15-terminology/pipeline-workflow-step.svg similarity index 100% rename from docs/versioned_docs/version-3.10/20-usage/15-terminology/pipeline-workflow-step.svg rename to docs/versioned_docs/version-3.13/20-usage/15-terminology/pipeline-workflow-step.svg diff --git a/docs/versioned_docs/version-3.10/20-usage/20-workflow-syntax.md b/docs/versioned_docs/version-3.13/20-usage/20-workflow-syntax.md similarity index 99% rename from docs/versioned_docs/version-3.10/20-usage/20-workflow-syntax.md rename to docs/versioned_docs/version-3.13/20-usage/20-workflow-syntax.md index 386a1bcec..f97d87e4f 100644 --- a/docs/versioned_docs/version-3.10/20-usage/20-workflow-syntax.md +++ b/docs/versioned_docs/version-3.13/20-usage/20-workflow-syntax.md @@ -393,7 +393,7 @@ when: #### `path` :::info -Path conditions are applied only to **push** and **pull_request** events. This feature is currently available for all forges except Bitbucket Cloud. +Path conditions are applied only to **push** and **pull_request** events. ::: Execute a step only on a pipeline with certain files being changed: diff --git a/docs/versioned_docs/version-3.10/20-usage/25-workflows.md b/docs/versioned_docs/version-3.13/20-usage/25-workflows.md similarity index 100% rename from docs/versioned_docs/version-3.10/20-usage/25-workflows.md rename to docs/versioned_docs/version-3.13/20-usage/25-workflows.md diff --git a/docs/versioned_docs/version-3.10/20-usage/30-matrix-workflows.md b/docs/versioned_docs/version-3.13/20-usage/30-matrix-workflows.md similarity index 100% rename from docs/versioned_docs/version-3.10/20-usage/30-matrix-workflows.md rename to docs/versioned_docs/version-3.13/20-usage/30-matrix-workflows.md diff --git a/docs/versioned_docs/version-3.10/20-usage/40-secrets.md b/docs/versioned_docs/version-3.13/20-usage/40-secrets.md similarity index 100% rename from docs/versioned_docs/version-3.10/20-usage/40-secrets.md rename to docs/versioned_docs/version-3.13/20-usage/40-secrets.md diff --git a/docs/versioned_docs/version-3.10/20-usage/41-registries.md b/docs/versioned_docs/version-3.13/20-usage/41-registries.md similarity index 100% rename from docs/versioned_docs/version-3.10/20-usage/41-registries.md rename to docs/versioned_docs/version-3.13/20-usage/41-registries.md diff --git a/docs/versioned_docs/version-3.10/20-usage/45-cron.md b/docs/versioned_docs/version-3.13/20-usage/45-cron.md similarity index 100% rename from docs/versioned_docs/version-3.10/20-usage/45-cron.md rename to docs/versioned_docs/version-3.13/20-usage/45-cron.md diff --git a/docs/versioned_docs/version-3.10/20-usage/50-environment.md b/docs/versioned_docs/version-3.13/20-usage/50-environment.md similarity index 100% rename from docs/versioned_docs/version-3.10/20-usage/50-environment.md rename to docs/versioned_docs/version-3.13/20-usage/50-environment.md diff --git a/docs/versioned_docs/version-3.10/20-usage/51-plugins/20-creating-plugins.md b/docs/versioned_docs/version-3.13/20-usage/51-plugins/20-creating-plugins.md similarity index 100% rename from docs/versioned_docs/version-3.10/20-usage/51-plugins/20-creating-plugins.md rename to docs/versioned_docs/version-3.13/20-usage/51-plugins/20-creating-plugins.md diff --git a/docs/versioned_docs/version-3.10/20-usage/51-plugins/51-overview.md b/docs/versioned_docs/version-3.13/20-usage/51-plugins/51-overview.md similarity index 100% rename from docs/versioned_docs/version-3.10/20-usage/51-plugins/51-overview.md rename to docs/versioned_docs/version-3.13/20-usage/51-plugins/51-overview.md diff --git a/docs/versioned_docs/version-3.10/20-usage/51-plugins/_category_.yaml b/docs/versioned_docs/version-3.13/20-usage/51-plugins/_category_.yaml similarity index 100% rename from docs/versioned_docs/version-3.10/20-usage/51-plugins/_category_.yaml rename to docs/versioned_docs/version-3.13/20-usage/51-plugins/_category_.yaml diff --git a/docs/versioned_docs/version-3.10/20-usage/60-services.md b/docs/versioned_docs/version-3.13/20-usage/60-services.md similarity index 100% rename from docs/versioned_docs/version-3.10/20-usage/60-services.md rename to docs/versioned_docs/version-3.13/20-usage/60-services.md diff --git a/docs/versioned_docs/version-3.10/20-usage/70-volumes.md b/docs/versioned_docs/version-3.13/20-usage/70-volumes.md similarity index 100% rename from docs/versioned_docs/version-3.10/20-usage/70-volumes.md rename to docs/versioned_docs/version-3.13/20-usage/70-volumes.md diff --git a/docs/versioned_docs/version-3.13/20-usage/72-extensions/40-configuration-extension.md b/docs/versioned_docs/version-3.13/20-usage/72-extensions/40-configuration-extension.md new file mode 100644 index 000000000..c8f41ea48 --- /dev/null +++ b/docs/versioned_docs/version-3.13/20-usage/72-extensions/40-configuration-extension.md @@ -0,0 +1,159 @@ +# Configuration extension + +The configuration extension can be used to modify or generate Woodpeckers pipeline configurations. You can configure an HTTP endpoint in the repository settings in the extensions tab. + +Using such an extension can be useful if you want to: + + + +- Preprocess the original configuration file with something like Go templating +- Convert custom attributes to Woodpecker attributes +- Add defaults to the configuration like default steps +- Convert configuration files from a totally different format like Gitlab CI config, Starlark, Jsonnet, ... +- Centralize configuration for multiple repositories in one place + +## Security + +:::warning +As Woodpecker will pass private information like tokens and will execute the returned configuration, it is extremely important to secure the external extension. Therefore Woodpecker signs every request. Read more about it in the [security section](./index.md#security). +::: + +## Global configuration + +In addition to the ability to configure the extension per repository, you can also configure a global endpoint in the Woodpecker server configuration. This can be useful if you want to use the extension for all repositories. Be careful if +you share your Woodpecker server with others as they will also use your configuration extension. + +The global configuration will be called before the repository specific configuration extension if both are configured. + +```ini title="Server" +WOODPECKER_CONFIG_SERVICE_ENDPOINT=https://example.com/ciconfig +``` + +## How it works + +When a pipeline is triggered Woodpecker will fetch the pipeline configuration from the repository, then make a HTTP POST request to the configured extension with a JSON payload containing some data like the repository, pipeline information and the current config files retrieved from the repository. The extension can then send back modified or even new pipeline configurations following Woodpeckers official yaml format that should be used. + +### Request + +The extension receives an HTTP POST request with the following JSON payload: + +```ts +class Request { + repo: Repo; + pipeline: Pipeline; + netrc: Netrc; +} +``` + +Checkout the following models for more information: + +- [repo model](https://github.com/woodpecker-ci/woodpecker/blob/main/server/model/repo.go) +- [pipeline model](https://github.com/woodpecker-ci/woodpecker/blob/main/server/model/pipeline.go) +- [netrc model](https://github.com/woodpecker-ci/woodpecker/blob/main/server/model/netrc.go) + +:::tip +The `netrc` data is pretty powerful as it contains credentials to access the repository. You can use this to fetch files or other information (like changed files, issues) from the repository using the forge api or even clone the repository. +::: + +Example request: + +```json +// Please check the latest structure in the models mentioned above. +// This example is likely outdated. + +{ + "repo": { + "id": 100, + "uid": "", + "user_id": 0, + "namespace": "", + "name": "woodpecker-test-pipeline", + "slug": "", + "scm": "git", + "git_http_url": "", + "git_ssh_url": "", + "link": "", + "default_branch": "", + "private": true, + "visibility": "private", + "active": true, + "config": "", + "trusted": false, + "protected": false, + "ignore_forks": false, + "ignore_pulls": false, + "cancel_pulls": false, + "timeout": 60, + "counter": 0, + "synced": 0, + "created": 0, + "updated": 0, + "version": 0 + }, + "pipeline": { + "author": "myUser", + "author_avatar": "https://myforge.com/avatars/d6b3f7787a685fcdf2a44e2c685c7e03", + "author_email": "my@email.com", + "branch": "main", + "changed_files": ["some-filename.txt"], + "commit": "2fff90f8d288a4640e90f05049fe30e61a14fd50", + "created_at": 0, + "deploy_to": "", + "enqueued_at": 0, + "error": "", + "event": "push", + "finished_at": 0, + "id": 0, + "link_url": "https://myforge.com/myUser/woodpecker-testpipe/commit/2fff90f8d288a4640e90f05049fe30e61a14fd50", + "message": "test old config\n", + "number": 0, + "parent": 0, + "ref": "refs/heads/main", + "refspec": "", + "clone_url": "", + "reviewed_at": 0, + "reviewed_by": "", + "sender": "myUser", + "signed": false, + "started_at": 0, + "status": "", + "timestamp": 1645962783, + "title": "", + "updated_at": 0, + "verified": false + }, + "netrc": { + "machine": "myforge.com", + "login": "myUser", + "password": "myPassword", + "type": "forge" + } +} +``` + +### Response + +The extension should respond with a JSON payload containing the new configuration files in Woodpecker's official YAML format. +If the extension wants to keep the existing configuration files, it can respond with HTTP status `204 No Content`. + +```ts +class Response { + configs: { + name: string; // filename of the configuration file + data: string; // content of the configuration file + }[]; +} +``` + +Example response: + +```json +{ + "configs": [ + { + "name": "central-override", + "data": "steps:\n - name: backend\n image: alpine\n commands:\n - echo \"Hello there from ConfigAPI\"\n" + } + ] +} +``` diff --git a/docs/versioned_docs/version-3.13/20-usage/72-extensions/_category_.yaml b/docs/versioned_docs/version-3.13/20-usage/72-extensions/_category_.yaml new file mode 100644 index 000000000..9c351c633 --- /dev/null +++ b/docs/versioned_docs/version-3.13/20-usage/72-extensions/_category_.yaml @@ -0,0 +1,7 @@ +label: 'Extensions' +# position: 3 +collapsible: true +collapsed: true +link: + type: 'doc' + id: 'index' diff --git a/docs/versioned_docs/version-3.13/20-usage/72-extensions/index.md b/docs/versioned_docs/version-3.13/20-usage/72-extensions/index.md new file mode 100644 index 000000000..e30cb53f4 --- /dev/null +++ b/docs/versioned_docs/version-3.13/20-usage/72-extensions/index.md @@ -0,0 +1,34 @@ +# Extensions + +Woodpecker allows you to replace internal logic with external extensions by using pre-defined http endpoints. + +There is currently one type of extension available: + +- [Configuration extension](./40-configuration-extension.md) to modify or generate pipeline configurations on the fly. + +## Security + +:::warning +You need to trust the extensions as they are receiving private information like secrets and tokens and might return harmful +data like malicious pipeline configurations that could be executed. +::: + +To prevent your extensions from such attacks, Woodpecker is signing all HTTP requests using [HTTP signatures](https://tools.ietf.org/html/draft-cavage-http-signatures). Woodpecker therefore uses a public-private ed25519 key pair. +To verify the requests your extension has to verify the signature of all request using the public key with some library like [httpsign](https://github.com/yaronf/httpsign). +You can get the public Woodpecker key by opening `http://my-woodpecker.tld/api/signature/public-key` or by visiting the Woodpecker UI, going to you repo settings and opening the extensions page. + +## Example extensions + +A simplistic service providing endpoints for a config and secrets extension can be found here: [https://github.com/woodpecker-ci/example-extensions](https://github.com/woodpecker-ci/example-extensions) + +## Configuration + +To prevent extensions from calling local services by default only external hosts / ip-addresses are allowed. You can change this behavior by setting the `WOODPECKER_EXTENSIONS_ALLOWED_HOSTS` environment variable. You can use a comma separated list of: + +- Built-in networks: + - `loopback`: 127.0.0.0/8 for IPv4 and ::1/128 for IPv6, localhost is included. + - `private`: RFC 1918 (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16) and RFC 4193 (FC00::/7). Also called LAN/Intranet. + - `external`: A valid non-private unicast IP, you can access all hosts on public internet. + - `*`: All hosts are allowed. +- CIDR list: `1.2.3.0/8` for IPv4 and `2001:db8::/32` for IPv6 +- (Wildcard) hosts: `example.com`, `*.example.com`, `192.168.100.*` diff --git a/docs/versioned_docs/version-3.10/20-usage/72-linter.md b/docs/versioned_docs/version-3.13/20-usage/72-linter.md similarity index 100% rename from docs/versioned_docs/version-3.10/20-usage/72-linter.md rename to docs/versioned_docs/version-3.13/20-usage/72-linter.md diff --git a/docs/versioned_docs/version-3.10/20-usage/75-project-settings.md b/docs/versioned_docs/version-3.13/20-usage/75-project-settings.md similarity index 100% rename from docs/versioned_docs/version-3.10/20-usage/75-project-settings.md rename to docs/versioned_docs/version-3.13/20-usage/75-project-settings.md diff --git a/docs/versioned_docs/version-3.10/20-usage/80-badges.md b/docs/versioned_docs/version-3.13/20-usage/80-badges.md similarity index 54% rename from docs/versioned_docs/version-3.10/20-usage/80-badges.md rename to docs/versioned_docs/version-3.13/20-usage/80-badges.md index 1bee62a58..44ea89460 100644 --- a/docs/versioned_docs/version-3.10/20-usage/80-badges.md +++ b/docs/versioned_docs/version-3.13/20-usage/80-badges.md @@ -15,4 +15,10 @@ The status badge displays the status for the latest build to your default branch +:///api/badges//status.svg?branch= ``` -Please note status badges do not include pull request results, since the status of a pull request does not provide an accurate representation of your repository state. +By default status badges do not include pull request results, since the status of a pull request does not provide an accurate representation of your repository state. +If you'd like to respect other or further events, you can add the `events` query parameter, otherwise the badge represents only the state of the last push event: + +```diff +-:///api/badges//status.svg ++:///api/badges//status.svg?events=manual,cron +``` diff --git a/docs/versioned_docs/version-3.10/20-usage/90-advanced-usage.md b/docs/versioned_docs/version-3.13/20-usage/90-advanced-usage.md similarity index 100% rename from docs/versioned_docs/version-3.10/20-usage/90-advanced-usage.md rename to docs/versioned_docs/version-3.13/20-usage/90-advanced-usage.md diff --git a/docs/versioned_docs/version-3.10/20-usage/_category_.yaml b/docs/versioned_docs/version-3.13/20-usage/_category_.yaml similarity index 100% rename from docs/versioned_docs/version-3.10/20-usage/_category_.yaml rename to docs/versioned_docs/version-3.13/20-usage/_category_.yaml diff --git a/docs/versioned_docs/version-3.10/20-usage/cron-settings.png b/docs/versioned_docs/version-3.13/20-usage/cron-settings.png similarity index 100% rename from docs/versioned_docs/version-3.10/20-usage/cron-settings.png rename to docs/versioned_docs/version-3.13/20-usage/cron-settings.png diff --git a/docs/versioned_docs/version-3.10/20-usage/linter-warnings-errors.png b/docs/versioned_docs/version-3.13/20-usage/linter-warnings-errors.png similarity index 100% rename from docs/versioned_docs/version-3.10/20-usage/linter-warnings-errors.png rename to docs/versioned_docs/version-3.13/20-usage/linter-warnings-errors.png diff --git a/docs/versioned_docs/version-3.10/20-usage/pipeline.png b/docs/versioned_docs/version-3.13/20-usage/pipeline.png similarity index 100% rename from docs/versioned_docs/version-3.10/20-usage/pipeline.png rename to docs/versioned_docs/version-3.13/20-usage/pipeline.png diff --git a/docs/versioned_docs/version-3.10/20-usage/project-settings.png b/docs/versioned_docs/version-3.13/20-usage/project-settings.png similarity index 100% rename from docs/versioned_docs/version-3.10/20-usage/project-settings.png rename to docs/versioned_docs/version-3.13/20-usage/project-settings.png diff --git a/docs/versioned_docs/version-3.10/20-usage/repo-new.png b/docs/versioned_docs/version-3.13/20-usage/repo-new.png similarity index 100% rename from docs/versioned_docs/version-3.10/20-usage/repo-new.png rename to docs/versioned_docs/version-3.13/20-usage/repo-new.png diff --git a/docs/versioned_docs/version-3.10/20-usage/secrets-plugins-filter.png b/docs/versioned_docs/version-3.13/20-usage/secrets-plugins-filter.png similarity index 100% rename from docs/versioned_docs/version-3.10/20-usage/secrets-plugins-filter.png rename to docs/versioned_docs/version-3.13/20-usage/secrets-plugins-filter.png diff --git a/docs/versioned_docs/version-3.10/30-administration/00-general.md b/docs/versioned_docs/version-3.13/30-administration/00-general.md similarity index 100% rename from docs/versioned_docs/version-3.10/30-administration/00-general.md rename to docs/versioned_docs/version-3.13/30-administration/00-general.md diff --git a/docs/versioned_docs/version-3.10/30-administration/05-installation/10-docker-compose.md b/docs/versioned_docs/version-3.13/30-administration/05-installation/10-docker-compose.md similarity index 100% rename from docs/versioned_docs/version-3.10/30-administration/05-installation/10-docker-compose.md rename to docs/versioned_docs/version-3.13/30-administration/05-installation/10-docker-compose.md diff --git a/docs/versioned_docs/version-3.10/30-administration/05-installation/20-helm-chart.md b/docs/versioned_docs/version-3.13/30-administration/05-installation/20-helm-chart.md similarity index 77% rename from docs/versioned_docs/version-3.10/30-administration/05-installation/20-helm-chart.md rename to docs/versioned_docs/version-3.13/30-administration/05-installation/20-helm-chart.md index 00f1c8b5d..54a14eddb 100644 --- a/docs/versioned_docs/version-3.10/30-administration/05-installation/20-helm-chart.md +++ b/docs/versioned_docs/version-3.13/30-administration/05-installation/20-helm-chart.md @@ -3,26 +3,10 @@ Woodpecker provides a [Helm chart](https://github.com/woodpecker-ci/helm) for Kubernetes environments: ```bash -helm install woodpecker oci://ghcr.io/woodpecker-ci/helm/woodpecker +helm install woodpecker oci://ghcr.io/woodpecker-ci/helm/woodpecker --version ``` -## Configuration - -To fetch all configurable options with detailed comments: - -```bash -helm show values oci://ghcr.io/woodpecker-ci/helm/woodpecker > values.yaml -``` - -Install using custom values: - -```bash -helm install woodpecker \ - oci://ghcr.io/woodpecker-ci/helm/woodpecker \ - -f values.yaml -``` - -### Metrics +## Metrics To enable metrics gathering, set the following in values.yml: diff --git a/docs/versioned_docs/version-3.10/30-administration/05-installation/30-packages.md b/docs/versioned_docs/version-3.13/30-administration/05-installation/30-packages.md similarity index 100% rename from docs/versioned_docs/version-3.10/30-administration/05-installation/30-packages.md rename to docs/versioned_docs/version-3.13/30-administration/05-installation/30-packages.md diff --git a/docs/versioned_docs/version-3.10/30-administration/05-installation/_category_.yaml b/docs/versioned_docs/version-3.13/30-administration/05-installation/_category_.yaml similarity index 100% rename from docs/versioned_docs/version-3.10/30-administration/05-installation/_category_.yaml rename to docs/versioned_docs/version-3.13/30-administration/05-installation/_category_.yaml diff --git a/docs/versioned_docs/version-3.10/30-administration/10-configuration/10-server.md b/docs/versioned_docs/version-3.13/30-administration/10-configuration/10-server.md similarity index 98% rename from docs/versioned_docs/version-3.10/30-administration/10-configuration/10-server.md rename to docs/versioned_docs/version-3.13/30-administration/10-configuration/10-server.md index 6f975934a..61e67b109 100644 --- a/docs/versioned_docs/version-3.10/30-administration/10-configuration/10-server.md +++ b/docs/versioned_docs/version-3.13/30-administration/10-configuration/10-server.md @@ -1071,6 +1071,15 @@ Specify a configuration service endpoint, see [Configuration Extension](#externa --- +### EXTENSIONS_ALLOWED_HOSTS + +- Name: `WOODPECKER_EXTENSIONS_ALLOWED_HOSTS` +- Default: `external` + +Comma-separated list of hosts that are allowed to be contacted by extensions. Possible values are `loopback`, `private`, `external`, `*` or CIDR list. + +--- + ### FORGE_TIMEOUT - Name: `WOODPECKER_FORGE_TIMEOUT` @@ -1112,7 +1121,11 @@ Disable version check in admin web UI. - Name: `WOODPECKER_LOG_STORE` - Default: `database` -Where to store logs. Possible values: `database` or `file`. +Where to store logs. Possible values: + +- `database`: stores the logs in the database +- `file`: stores logs in JSON files on the files system +- `addon`: uses an [addon](./100-addons.md#log) to store logs --- @@ -1121,7 +1134,10 @@ Where to store logs. Possible values: `database` or `file`. - Name: `WOODPECKER_LOG_STORE_FILE_PATH` - Default: none -Directory to store logs in if [`WOODPECKER_LOG_STORE`](#log_store) is `file`. +If [`WOODPECKER_LOG_STORE`](#log_store) is: + +- `file`: Directory to store logs in +- `addon`: The path to the addon executable --- diff --git a/docs/versioned_docs/version-3.13/30-administration/10-configuration/100-addons.md b/docs/versioned_docs/version-3.13/30-administration/10-configuration/100-addons.md new file mode 100644 index 000000000..12d297e7f --- /dev/null +++ b/docs/versioned_docs/version-3.13/30-administration/10-configuration/100-addons.md @@ -0,0 +1,42 @@ +# Addons + +Addons can be used to extend the Woodpecker server. Currently, they can be used for forges and the log service. + +:::warning +Addon forges are still experimental. Their implementation can change and break at any time. +::: + +:::danger +You must trust the author of the addon forge you are using. They may have access to authentication codes and other potentially sensitive information. +::: + +## Usage + +To use an addon forge, download the correct addon version. + +### Forge + +Use this in your `.env`: + +```ini +WOODPECKER_ADDON_FORGE=/path/to/your/addon/forge/file +``` + +In case you run Woodpecker as container, you probably want to mount the addon binary to `/opt/addons/`. + +#### List of addon forges + +- [Radicle](https://radicle.xyz/): Open source, peer-to-peer code collaboration stack built on Git. Radicle addon for Woodpecker CI can be found at [this repo](https://explorer.radicle.gr/nodes/seed.radicle.gr/rad:z39Cf1XzrvCLRZZJRUZnx9D1fj5ws). + +### Log + +Use this in your `.env`: + +```ini +WOODPECKER_LOG_STORE=addon +WOODPECKER_LOG_STORE_FILE_PATH=/path/to/your/addon/forge/file +``` + +## Developing addon forges + +See [Addons](../../92-development/100-addons.md). diff --git a/docs/versioned_docs/version-3.10/30-administration/10-configuration/11-backends/10-docker.md b/docs/versioned_docs/version-3.13/30-administration/10-configuration/11-backends/10-docker.md similarity index 100% rename from docs/versioned_docs/version-3.10/30-administration/10-configuration/11-backends/10-docker.md rename to docs/versioned_docs/version-3.13/30-administration/10-configuration/11-backends/10-docker.md diff --git a/docs/versioned_docs/version-3.10/30-administration/10-configuration/11-backends/20-kubernetes.md b/docs/versioned_docs/version-3.13/30-administration/10-configuration/11-backends/20-kubernetes.md similarity index 73% rename from docs/versioned_docs/version-3.10/30-administration/10-configuration/11-backends/20-kubernetes.md rename to docs/versioned_docs/version-3.13/30-administration/10-configuration/11-backends/20-kubernetes.md index 8ba332322..7de7054da 100644 --- a/docs/versioned_docs/version-3.10/30-administration/10-configuration/11-backends/20-kubernetes.md +++ b/docs/versioned_docs/version-3.13/30-administration/10-configuration/11-backends/20-kubernetes.md @@ -145,6 +145,100 @@ steps: value: 'value1' effect: 'NoSchedule' tolerationSeconds: 3600 + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: topology.kubernetes.io/zone + operator: In + values: + - eu-central-1a + - eu-central-1b +``` + +### Affinity + +Kubernetes [affinity and anti-affinity](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#affinity-and-anti-affinity) rules allow you to constrain which nodes your pods can be scheduled on based on node labels, or co-locate/spread pods relative to other pods. + +You can configure affinity at two levels: + +1. **Per-step via `backend_options.kubernetes.affinity`** (shown in example above) - requires agent configuration to allow it +2. **Agent-wide via `WOODPECKER_BACKEND_K8S_POD_AFFINITY`** - applies to all pods unless overridden + +#### Agent-wide affinity + +To apply affinity rules to all workflow pods, configure the agent with YAML-formatted affinity: + +```yaml +WOODPECKER_BACKEND_K8S_POD_AFFINITY: | + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: node-role.kubernetes.io/worker + operator: In + values: + - "true" +``` + +By default, per-step affinity settings are **not allowed** for security reasons. To enable them: + +```bash +WOODPECKER_BACKEND_K8S_POD_AFFINITY_ALLOW_FROM_STEP: true +``` + +:::warning +Enabling `WOODPECKER_BACKEND_K8S_POD_AFFINITY_ALLOW_FROM_STEP` in multi-tenant environments allows pipeline authors to control pod placement, which may have security or resource isolation implications. +::: + +When per-step affinity is allowed and specified, it **replaces** the agent-wide affinity entirely (not merged). + +#### Example: agent affinity for co-location + +This example configures all workflow pods within a workflow to be co-located on the same node, while requiring other workflows run on different nodes. + +It uses `matchLabelKeys` to dynamically match pods with the same `woodpecker-ci.org/task-uuid`, and `mismatchLabelKeys` to separating pods with different task UUIDs: + +```yaml +WOODPECKER_BACKEND_K8S_POD_AFFINITY: | + podAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: {} + matchLabelKeys: + - woodpecker-ci.org/task-uuid + topologyKey: "kubernetes.io/hostname" + podAntiAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: {} + mismatchLabelKeys: + - woodpecker-ci.org/task-uuid + topologyKey: "kubernetes.io/hostname" +``` + +:::note +The `matchLabelKeys` and `mismatchLabelKeys` features require Kubernetes v1.29+ (alpha with feature gate `MatchLabelKeysInPodAffinity`) or v1.33+ (beta, enabled by default). These fields allow the Kubernetes API server to dynamically populate label selectors at pod creation time, eliminating the need to hardcode values like `$(WOODPECKER_TASK_UUID)`. +::: + +#### Example: Node affinity for GPU workloads + +Ensure a step runs only on GPU-enabled nodes: + +```yaml +steps: + - name: train-model + image: tensorflow/tensorflow:latest-gpu + backend_options: + kubernetes: + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: accelerator + operator: In + values: + - nvidia-tesla-v100 ``` ### Volumes @@ -153,7 +247,7 @@ To mount volumes a PersistentVolume (PV) and PersistentVolumeClaim (PVC) are nee Persistent volumes must be created manually. Use the Kubernetes [Persistent Volumes](https://kubernetes.io/docs/concepts/storage/persistent-volumes/) documentation as a reference. -_If your PVC is not highly available or NFS-based, you may also need to integrate affinity settings to ensure that your steps are executed on the correct node._ +_If your PVC is not highly available or NFS-based, use the `affinity` settings (documented above) to ensure that your steps are executed on the correct node._ NOTE: If you plan to use this volume in more than one workflow concurrently, make sure you have configured the PVC in `RWX` mode. Keep in mind that this feature must be supported by the used CSI driver: @@ -304,6 +398,36 @@ It configures the address of the Kubernetes API server to connect to. If running the agent within Kubernetes, this will already be set and you don't have to add it manually. +### Headless services + +For each workflow run a [headless services](https://kubernetes.io/docs/concepts/services-networking/service/#headless-services) is created, +and all steps asigned the subdomain that matches the headless service, so any step can reach other steps via DNS by using the step name as hostname. + +Using the headless services, the step pod is connected to directly, so any port on the other step pods can be reached. + +This is useful for some use-cases, like test-containers in a docker-in-docker setup, where the step needs to connect to many ports on the docker host service. + +```yaml +steps: + - name: test + image: docker:cli # use 'docker:-cli' or similar in production + environment: + DOCKER_HOST: 'tcp://docker:2376' + DOCKER_CERT_PATH: '/woodpecker/dind-certs/client' + DOCKER_TLS_VERIFY: '1' + commands: + - docker run hello-world + + - name: docker + image: docker:dind # use 'docker:-dind' or similar in production + detached: true + privileged: true + environment: + DOCKER_TLS_CERTDIR: /woodpecker/dind-certs +``` + +If ports are defined on a service, then woodpecker will create a normal service for the pod, which use hosts override using the services cluster IP. + ## Environment variables These env vars can be set in the `env:` sections of the agent. diff --git a/docs/versioned_docs/version-3.10/30-administration/10-configuration/11-backends/30-local.md b/docs/versioned_docs/version-3.13/30-administration/10-configuration/11-backends/30-local.md similarity index 100% rename from docs/versioned_docs/version-3.10/30-administration/10-configuration/11-backends/30-local.md rename to docs/versioned_docs/version-3.13/30-administration/10-configuration/11-backends/30-local.md diff --git a/docs/versioned_docs/version-3.10/30-administration/10-configuration/11-backends/50-custom.md b/docs/versioned_docs/version-3.13/30-administration/10-configuration/11-backends/50-custom.md similarity index 100% rename from docs/versioned_docs/version-3.10/30-administration/10-configuration/11-backends/50-custom.md rename to docs/versioned_docs/version-3.13/30-administration/10-configuration/11-backends/50-custom.md diff --git a/docs/versioned_docs/version-3.10/30-administration/10-configuration/11-backends/_category_.yaml b/docs/versioned_docs/version-3.13/30-administration/10-configuration/11-backends/_category_.yaml similarity index 100% rename from docs/versioned_docs/version-3.10/30-administration/10-configuration/11-backends/_category_.yaml rename to docs/versioned_docs/version-3.13/30-administration/10-configuration/11-backends/_category_.yaml diff --git a/docs/versioned_docs/version-3.10/30-administration/10-configuration/12-forges/11-overview.md b/docs/versioned_docs/version-3.13/30-administration/10-configuration/12-forges/11-overview.md similarity index 90% rename from docs/versioned_docs/version-3.10/30-administration/10-configuration/12-forges/11-overview.md rename to docs/versioned_docs/version-3.13/30-administration/10-configuration/12-forges/11-overview.md index 5167f4f35..f384cefc4 100644 --- a/docs/versioned_docs/version-3.10/30-administration/10-configuration/12-forges/11-overview.md +++ b/docs/versioned_docs/version-3.13/30-administration/10-configuration/12-forges/11-overview.md @@ -11,6 +11,8 @@ | Event: Deploy¹ | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | | [Event: Pull-Request-Metadata](../../../20-usage/50-environment.md#pull_request_metadata-specific-event-reason-values) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | | [Multiple workflows](../../../20-usage/25-workflows.md) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| [when.path filter](../../../20-usage/20-workflow-syntax.md#path) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | +| [when.path filter](../../../20-usage/20-workflow-syntax.md#path) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | ¹ The deployment event can be triggered for all forges from Woodpecker directly. However, only GitHub can trigger them using webhooks. + +In addition to this, Woodpecker supports [addon forges](../100-addons.md) if the forge you are using does not meet the [Woodpecker requirements](../../../92-development/02-core-ideas.md#forges) or your setup is too specific to be included in the Woodpecker core. diff --git a/docs/versioned_docs/version-3.10/30-administration/10-configuration/12-forges/20-github.md b/docs/versioned_docs/version-3.13/30-administration/10-configuration/12-forges/20-github.md similarity index 100% rename from docs/versioned_docs/version-3.10/30-administration/10-configuration/12-forges/20-github.md rename to docs/versioned_docs/version-3.13/30-administration/10-configuration/12-forges/20-github.md diff --git a/docs/versioned_docs/version-3.10/30-administration/10-configuration/12-forges/30-gitea.md b/docs/versioned_docs/version-3.13/30-administration/10-configuration/12-forges/30-gitea.md similarity index 100% rename from docs/versioned_docs/version-3.10/30-administration/10-configuration/12-forges/30-gitea.md rename to docs/versioned_docs/version-3.13/30-administration/10-configuration/12-forges/30-gitea.md diff --git a/docs/versioned_docs/version-3.10/30-administration/10-configuration/12-forges/35-forgejo.md b/docs/versioned_docs/version-3.13/30-administration/10-configuration/12-forges/35-forgejo.md similarity index 100% rename from docs/versioned_docs/version-3.10/30-administration/10-configuration/12-forges/35-forgejo.md rename to docs/versioned_docs/version-3.13/30-administration/10-configuration/12-forges/35-forgejo.md diff --git a/docs/versioned_docs/version-3.10/30-administration/10-configuration/12-forges/40-gitlab.md b/docs/versioned_docs/version-3.13/30-administration/10-configuration/12-forges/40-gitlab.md similarity index 100% rename from docs/versioned_docs/version-3.10/30-administration/10-configuration/12-forges/40-gitlab.md rename to docs/versioned_docs/version-3.13/30-administration/10-configuration/12-forges/40-gitlab.md diff --git a/docs/versioned_docs/version-3.10/30-administration/10-configuration/12-forges/50-bitbucket.md b/docs/versioned_docs/version-3.13/30-administration/10-configuration/12-forges/50-bitbucket.md similarity index 100% rename from docs/versioned_docs/version-3.10/30-administration/10-configuration/12-forges/50-bitbucket.md rename to docs/versioned_docs/version-3.13/30-administration/10-configuration/12-forges/50-bitbucket.md diff --git a/docs/versioned_docs/version-3.10/30-administration/10-configuration/12-forges/60-bitbucket_datacenter.md b/docs/versioned_docs/version-3.13/30-administration/10-configuration/12-forges/60-bitbucket_datacenter.md similarity index 100% rename from docs/versioned_docs/version-3.10/30-administration/10-configuration/12-forges/60-bitbucket_datacenter.md rename to docs/versioned_docs/version-3.13/30-administration/10-configuration/12-forges/60-bitbucket_datacenter.md diff --git a/docs/versioned_docs/version-3.10/30-administration/10-configuration/12-forges/_category_.yaml b/docs/versioned_docs/version-3.13/30-administration/10-configuration/12-forges/_category_.yaml similarity index 100% rename from docs/versioned_docs/version-3.10/30-administration/10-configuration/12-forges/_category_.yaml rename to docs/versioned_docs/version-3.13/30-administration/10-configuration/12-forges/_category_.yaml diff --git a/docs/versioned_docs/version-3.10/30-administration/10-configuration/12-forges/bitbucket_oauth.png b/docs/versioned_docs/version-3.13/30-administration/10-configuration/12-forges/bitbucket_oauth.png similarity index 100% rename from docs/versioned_docs/version-3.10/30-administration/10-configuration/12-forges/bitbucket_oauth.png rename to docs/versioned_docs/version-3.13/30-administration/10-configuration/12-forges/bitbucket_oauth.png diff --git a/docs/versioned_docs/version-3.10/30-administration/10-configuration/12-forges/bitbucket_permissions.png b/docs/versioned_docs/version-3.13/30-administration/10-configuration/12-forges/bitbucket_permissions.png similarity index 100% rename from docs/versioned_docs/version-3.10/30-administration/10-configuration/12-forges/bitbucket_permissions.png rename to docs/versioned_docs/version-3.13/30-administration/10-configuration/12-forges/bitbucket_permissions.png diff --git a/docs/versioned_docs/version-3.10/30-administration/10-configuration/12-forges/gitea_oauth.gif b/docs/versioned_docs/version-3.13/30-administration/10-configuration/12-forges/gitea_oauth.gif similarity index 100% rename from docs/versioned_docs/version-3.10/30-administration/10-configuration/12-forges/gitea_oauth.gif rename to docs/versioned_docs/version-3.13/30-administration/10-configuration/12-forges/gitea_oauth.gif diff --git a/docs/versioned_docs/version-3.10/30-administration/10-configuration/12-forges/github_oauth.png b/docs/versioned_docs/version-3.13/30-administration/10-configuration/12-forges/github_oauth.png similarity index 100% rename from docs/versioned_docs/version-3.10/30-administration/10-configuration/12-forges/github_oauth.png rename to docs/versioned_docs/version-3.13/30-administration/10-configuration/12-forges/github_oauth.png diff --git a/docs/versioned_docs/version-3.10/30-administration/10-configuration/30-agent.md b/docs/versioned_docs/version-3.13/30-administration/10-configuration/30-agent.md similarity index 95% rename from docs/versioned_docs/version-3.10/30-administration/10-configuration/30-agent.md rename to docs/versioned_docs/version-3.13/30-administration/10-configuration/30-agent.md index 2b88600e0..589c57b83 100644 --- a/docs/versioned_docs/version-3.10/30-administration/10-configuration/30-agent.md +++ b/docs/versioned_docs/version-3.13/30-administration/10-configuration/30-agent.md @@ -155,7 +155,8 @@ Configures the number of parallel workflows. Configures custom labels for the agent, to let workflows filter by it. Use a list of key-value pairs like `key=value,second-key=*`. `*` can be used as a wildcard. -By default, agents provide three additional labels `platform=os/arch`, `hostname=my-agent` and `repo=*` which can be overwritten if needed. +If you use `!` as key prefix it is mandatory for the workflow to have that label set (without !) set and matched. +By default, agents provide four additional labels `platform=os/arch`, `hostname=my-agent`, `backend=my-backend` and `repo=*` which can be overwritten if needed. To learn how labels work, check out the [pipeline syntax page](../../20-usage/20-workflow-syntax.md#labels). --- diff --git a/docs/versioned_docs/version-3.10/30-administration/10-configuration/40-autoscaler.md b/docs/versioned_docs/version-3.13/30-administration/10-configuration/40-autoscaler.md similarity index 100% rename from docs/versioned_docs/version-3.10/30-administration/10-configuration/40-autoscaler.md rename to docs/versioned_docs/version-3.13/30-administration/10-configuration/40-autoscaler.md diff --git a/docs/versioned_docs/version-3.10/30-administration/10-configuration/_category_.yaml b/docs/versioned_docs/version-3.13/30-administration/10-configuration/_category_.yaml similarity index 100% rename from docs/versioned_docs/version-3.10/30-administration/10-configuration/_category_.yaml rename to docs/versioned_docs/version-3.13/30-administration/10-configuration/_category_.yaml diff --git a/docs/versioned_docs/version-3.10/30-administration/10-configuration/new-agent-connected.png b/docs/versioned_docs/version-3.13/30-administration/10-configuration/new-agent-connected.png similarity index 100% rename from docs/versioned_docs/version-3.10/30-administration/10-configuration/new-agent-connected.png rename to docs/versioned_docs/version-3.13/30-administration/10-configuration/new-agent-connected.png diff --git a/docs/versioned_docs/version-3.10/30-administration/10-configuration/new-agent-created.png b/docs/versioned_docs/version-3.13/30-administration/10-configuration/new-agent-created.png similarity index 100% rename from docs/versioned_docs/version-3.10/30-administration/10-configuration/new-agent-created.png rename to docs/versioned_docs/version-3.13/30-administration/10-configuration/new-agent-created.png diff --git a/docs/versioned_docs/version-3.10/30-administration/10-configuration/new-agent-registration.png b/docs/versioned_docs/version-3.13/30-administration/10-configuration/new-agent-registration.png similarity index 100% rename from docs/versioned_docs/version-3.10/30-administration/10-configuration/new-agent-registration.png rename to docs/versioned_docs/version-3.13/30-administration/10-configuration/new-agent-registration.png diff --git a/docs/versioned_docs/version-3.10/30-administration/_category_.yaml b/docs/versioned_docs/version-3.13/30-administration/_category_.yaml similarity index 100% rename from docs/versioned_docs/version-3.10/30-administration/_category_.yaml rename to docs/versioned_docs/version-3.13/30-administration/_category_.yaml diff --git a/docs/versioned_docs/version-3.10/40-cli.md b/docs/versioned_docs/version-3.13/40-cli.md similarity index 70% rename from docs/versioned_docs/version-3.10/40-cli.md rename to docs/versioned_docs/version-3.13/40-cli.md index c9ad961c6..ccf8bc8b6 100644 --- a/docs/versioned_docs/version-3.10/40-cli.md +++ b/docs/versioned_docs/version-3.13/40-cli.md @@ -36,23 +36,23 @@ woodpecker-cli [GLOBAL OPTIONS] [command [COMMAND OPTIONS]] [ARGUMENTS...] **--config, -c**="": path to config file -**--disable-update-check**: disable update check +**--disable-update-check**: disable update check (default: false) **--log-file**="": Output destination for logs. 'stdout' and 'stderr' can be used as special keywords. (default: stderr) **--log-level**="": set logging level (default: info) -**--nocolor**: disable colored debug output, only has effect if pretty output is set too +**--nocolor**: disable colored debug output, only has effect if pretty output is set too (default: false) -**--pretty**: enable pretty-printed debug output +**--pretty**: enable pretty-printed debug output (default: true) **--server, -s**="": server address -**--skip-verify**: skip ssl verification +**--skip-verify**: skip ssl verification (default: false) **--socks-proxy**="": socks proxy address -**--socks-proxy-off**: socks proxy ignored +**--socks-proxy-off**: socks proxy ignored (default: false) **--token, -t**="": server auth token @@ -75,9 +75,7 @@ manage organizations list organizations -**--format**="": format output (deprecated) (default: {{ .Name }}  -Organization ID: {{ .ID }} -) +**--format**="": format output (deprecated) (default: \x1b[33m{{ .Name }} \x1b[0m\nOrganization ID: {{ .ID }}\n) ### registry @@ -103,19 +101,13 @@ remove a registry list registries -**--format**="": format output (deprecated) (default: {{ .Address }}  -Username: {{ .Username }} -Email: {{ .Email }} -) +**--format**="": format output (deprecated) (default: \x1b[33m{{ .Address }} \x1b[0m\nUsername: {{ .Username }}\nEmail: {{ .Email }}\n) #### show show registry information -**--format**="": format output (deprecated) (default: {{ .Address }}  -Username: {{ .Username }} -Email: {{ .Email }} -) +**--format**="": format output (deprecated) (default: \x1b[33m{{ .Address }} \x1b[0m\nUsername: {{ .Username }}\nEmail: {{ .Email }}\n) **--hostname**="": registry hostname (default: docker.io) @@ -139,9 +131,9 @@ manage global secrets add a secret -**--event**="": secret limited to these events (default: []) +**--event**="": secret limited to these events -**--image**="": secret limited to these images (default: []) +**--image**="": secret limited to these images **--name**="": secret name @@ -157,27 +149,13 @@ remove a secret list secrets -**--format**="": format output (deprecated) (default: {{ .Name }}  -Events: {{ list .Events }} -{{- if .Images }} -Images: {{ list .Images }} -{{- else }} -Images: -{{- end }} -) +**--format**="": format output (deprecated) (default: \x1b[33m{{ .Name }} \x1b[0m\nEvents: {{ list .Events }}\n{{- if .Images }}\nImages: {{ list .Images }}\n{{- else }}\nImages: \n{{- end }}\n) #### show show secret information -**--format**="": format output (deprecated) (default: {{ .Name }}  -Events: {{ list .Events }} -{{- if .Images }} -Images: {{ list .Images }} -{{- else }} -Images: -{{- end }} -) +**--format**="": format output (deprecated) (default: \x1b[33m{{ .Name }} \x1b[0m\nEvents: {{ list .Events }}\n{{- if .Images }}\nImages: {{ list .Images }}\n{{- else }}\nImages: \n{{- end }}\n) **--name**="": secret name @@ -185,9 +163,9 @@ Images: update a secret -**--event**="": secret limited to these events (default: []) +**--event**="": secret limited to these events -**--image**="": secret limited to these images (default: []) +**--image**="": secret limited to these images **--name**="": secret name @@ -215,8 +193,33 @@ remove a user show user information -**--format**="": format output (default: User: {{ .Login }} -Email: {{ .Email }}) +**--format**="": format output (default: User: {{ .Login }}\nEmail: {{ .Email }}) + +## context, ctx + +manage contexts + +### list, ls + +list all contexts + +**--output**="": output format (default: table) + +**--output-no-headers**: do not print headers in output (default: false) + +**--output-no-headers**: don't print headers (default: false) + +### use + +set the current context + +### delete, rm + +delete a context + +### rename + +rename a context ## exec @@ -228,7 +231,7 @@ execute a local pipeline **--backend-docker-host**="": path to docker socket or url to the docker server -**--backend-docker-ipv6**: backend docker enable IPV6 +**--backend-docker-ipv6**: backend docker enable IPV6 (default: false) **--backend-docker-limit-cpu-quota**="": impose a cpu quota (default: 0) @@ -244,7 +247,7 @@ execute a local pipeline **--backend-docker-network**="": backend docker network -**--backend-docker-tls-verify**: enable or disable TLS verification for connecting to docker server +**--backend-docker-tls-verify**: enable or disable TLS verification for connecting to docker server (default: true) **--backend-docker-volumes**="": backend docker volumes (comma separated) @@ -254,39 +257,43 @@ execute a local pipeline **--backend-https-proxy**="": if set, pass the environment variable down as "HTTPS_PROXY" to steps -**--backend-k8s-allow-native-secrets**: whether to allow existing Kubernetes secrets to be referenced from steps +**--backend-k8s-allow-native-secrets**: whether to allow existing Kubernetes secrets to be referenced from steps (default: false) **--backend-k8s-namespace**="": backend k8s namespace, if used with WOODPECKER_BACKEND_K8S_NAMESPACE_PER_ORGANIZATION, this will be the prefix for the namespace appended with the organization name. (default: woodpecker) -**--backend-k8s-namespace-per-org**: Whether to enable namespace segregation per organization feature. When enabled, Woodpecker will create the Kubernetes resources to separated Kubernetes namespaces per Woodpecker organization. +**--backend-k8s-namespace-per-org**: Whether to enable namespace segregation per organization feature. When enabled, Woodpecker will create the Kubernetes resources to separated Kubernetes namespaces per Woodpecker organization. (default: false) + +**--backend-k8s-pod-affinity**="": backend k8s Agent-wide worker pod affinity, in YAML format + +**--backend-k8s-pod-affinity-allow-from-step**: whether to allow using affinity from step's backend options (default: false) **--backend-k8s-pod-annotations**="": backend k8s additional Agent-wide worker pod annotations -**--backend-k8s-pod-annotations-allow-from-step**: whether to allow using annotations from step's backend options +**--backend-k8s-pod-annotations-allow-from-step**: whether to allow using annotations from step's backend options (default: false) -**--backend-k8s-pod-image-pull-secret-names**="": backend k8s pull secret names for private registries (default: []) +**--backend-k8s-pod-image-pull-secret-names**="": backend k8s pull secret names for private registries **--backend-k8s-pod-labels**="": backend k8s additional Agent-wide worker pod labels -**--backend-k8s-pod-labels-allow-from-step**: whether to allow using labels from step's backend options +**--backend-k8s-pod-labels-allow-from-step**: whether to allow using labels from step's backend options (default: false) **--backend-k8s-pod-node-selector**="": backend k8s Agent-wide worker pod node selector **--backend-k8s-pod-tolerations**="": backend k8s Agent-wide worker pod tolerations -**--backend-k8s-pod-tolerations-allow-from-step**: whether to allow using tolerations from step's backend options +**--backend-k8s-pod-tolerations-allow-from-step**: whether to allow using tolerations from step's backend options (default: true) **--backend-k8s-priority-class**="": which kubernetes priority class to assign to created job pods -**--backend-k8s-secctx-nonroot**: `run as non root` Kubernetes security context option +**--backend-k8s-secctx-nonroot**: `run as non root` Kubernetes security context option (default: false) **--backend-k8s-storage-class**="": backend k8s storage class -**--backend-k8s-storage-rwx**: backend k8s storage access mode, should ReadWriteMany (RWX) instead of ReadWriteOnce (RWO) be used? (default: true) +**--backend-k8s-storage-rwx**: backend k8s storage access mode, should ReadWriteMany (RWX) instead of ReadWriteOnce (RWO) be used? (default: true) (default: true) **--backend-k8s-volume-size**="": backend k8s volume size (default 10G) (default: 10G) -**--backend-local-temp-dir**="": set a different temp dir to clone workflows into (default: /tmp) +**--backend-local-temp-dir**="": set a different temp dir to clone workflows into (default: system temporary directory) **--backend-no-proxy**="": if set, pass the environment variable down as "NO_PROXY" to steps @@ -300,7 +307,7 @@ execute a local pipeline **--commit-message**="": Set the metadata environment variable "CI_COMMIT_MESSAGE". -**--commit-pull-labels**="": Set the metadata environment variable "CI_COMMIT_PULL_REQUEST_LABELS". (default: []) +**--commit-pull-labels**="": Set the metadata environment variable "CI_COMMIT_PULL_REQUEST_LABELS". **--commit-pull-milestone**="": Set the metadata environment variable "CI_COMMIT_PULL_REQUEST_MILESTONE". @@ -308,17 +315,17 @@ execute a local pipeline **--commit-refspec**="": Set the metadata environment variable "CI_COMMIT_REFSPEC". -**--commit-release-is-pre**: Set the metadata environment variable "CI_COMMIT_PRERELEASE". +**--commit-release-is-pre**: Set the metadata environment variable "CI_COMMIT_PRERELEASE". (default: false) **--commit-sha**="": Set the metadata environment variable "CI_COMMIT_SHA". -**--env**="": Set the metadata environment variable "CI_ENV". (default: []) +**--env**="": Set the metadata environment variable "CI_ENV". **--forge-type**="": Set the metadata environment variable "CI_FORGE_TYPE". **--forge-url**="": Set the metadata environment variable "CI_FORGE_URL". -**--local**: run from local directory +**--local**: run from local directory (default: true) **--metadata-file**="": path to pipeline metadata file (normally downloaded from UI). Parameters can be adjusted by applying additional cli flags @@ -328,7 +335,7 @@ execute a local pipeline **--netrc-username**="": -**--network**="": external networks (default: []) +**--network**="": external networks **--pipeline-changed-files**="": Set the metadata environment variable "CI_PIPELINE_FILES", either json formatted list of strings, or comma separated string list. @@ -348,7 +355,7 @@ execute a local pipeline **--pipeline-url**="": Set the metadata environment variable "CI_PIPELINE_FORGE_URL". -**--plugins-privileged**="": Allow plugins to run in privileged mode, if environment variable is defined but empty there will be none (default: []) +**--plugins-privileged**="": Allow plugins to run in privileged mode, if environment variable is defined but empty there will be none **--prev-commit-author-avatar**="": Set the metadata environment variable "CI_PREV_COMMIT_AUTHOR_AVATAR". @@ -398,17 +405,17 @@ execute a local pipeline **--repo-remote-id**="": Set the metadata environment variable "CI_REPO_REMOTE_ID". -**--repo-trusted-network**: Set the metadata environment variable "CI_REPO_TRUSTED_NETWORK". +**--repo-trusted-network**: Set the metadata environment variable "CI_REPO_TRUSTED_NETWORK". (default: false) -**--repo-trusted-security**: Set the metadata environment variable "CI_REPO_TRUSTED_SECURITY". +**--repo-trusted-security**: Set the metadata environment variable "CI_REPO_TRUSTED_SECURITY". (default: false) -**--repo-trusted-volumes**: Set the metadata environment variable "CI_REPO_TRUSTED_VOLUMES". +**--repo-trusted-volumes**: Set the metadata environment variable "CI_REPO_TRUSTED_VOLUMES". (default: false) **--repo-url**="": Set the metadata environment variable "CI_REPO_URL". -**--secrets**="": map of secrets, ex. 'secret="val",secret2="value2"' (default: map[]) +**--secrets**="": map of secrets, ex. 'secret="val",secret2="value2"' -**--secrets**="": path to yaml file with secrets map +**--secrets-file**="": path to yaml file with secrets map **--system-host**="": Set the metadata environment variable "CI_SYSTEM_HOST". @@ -420,7 +427,7 @@ execute a local pipeline **--timeout**="": pipeline timeout (default: 1h0m0s) -**--volumes**="": pipeline volumes (default: []) +**--volumes**="": pipeline volumes **--workflow-name**="": Set the metadata environment variable "CI_WORKFLOW_NAME". @@ -434,18 +441,17 @@ execute a local pipeline show information about the current user -**--format**="": format output (deprecated) (default: User: {{ .Login }} -Email: {{ .Email }}) +**--format**="": format output (deprecated) (default: User: {{ .Login }}\nEmail: {{ .Email }}) ## lint lint a pipeline configuration file -**--plugins-privileged**="": allow plugins to run in privileged mode, if set empty, there is no (default: []) +**--plugins-privileged**="": allow plugins to run in privileged mode, if set empty, there is no -**--plugins-trusted-clone**="": plugins that are trusted to handle Git credentials in cloning steps (default: [docker.io/woodpeckerci/plugin-git:2.6.5 docker.io/woodpeckerci/plugin-git quay.io/woodpeckerci/plugin-git]) +**--plugins-trusted-clone**="": plugins that are trusted to handle Git credentials in cloning steps (default: "docker.io/woodpeckerci/plugin-git:2.8.0", "docker.io/woodpeckerci/plugin-git", "quay.io/woodpeckerci/plugin-git") -**--strict**: treat warnings as errors +**--strict**: treat warnings as errors (default: false) ## org @@ -479,10 +485,7 @@ remove a registry list registries -**--format**="": format output (deprecated) (default: {{ .Address }}  -Username: {{ .Username }} -Email: {{ .Email }} -) +**--format**="": format output (deprecated) (default: \x1b[33m{{ .Address }} \x1b[0m\nUsername: {{ .Username }}\nEmail: {{ .Email }}\n) **--organization, --org**="": organization id or full name (e.g. 123 or octocat) @@ -490,10 +493,7 @@ Email: {{ .Email }} show registry information -**--format**="": format output (deprecated) (default: {{ .Address }}  -Username: {{ .Username }} -Email: {{ .Email }} -) +**--format**="": format output (deprecated) (default: \x1b[33m{{ .Address }} \x1b[0m\nUsername: {{ .Username }}\nEmail: {{ .Email }}\n) **--hostname**="": registry hostname (default: docker.io) @@ -519,9 +519,9 @@ manage secrets add a secret -**--event**="": secret limited to these events (default: []) +**--event**="": secret limited to these events -**--image**="": secret limited to these images (default: []) +**--image**="": secret limited to these images **--name**="": secret name @@ -541,14 +541,7 @@ remove a secret list secrets -**--format**="": format output (deprecated) (default: {{ .Name }}  -Events: {{ list .Events }} -{{- if .Images }} -Images: {{ list .Images }} -{{- else }} -Images: -{{- end }} -) +**--format**="": format output (deprecated) (default: \x1b[33m{{ .Name }} \x1b[0m\nEvents: {{ list .Events }}\n{{- if .Images }}\nImages: {{ list .Images }}\n{{- else }}\nImages: \n{{- end }}\n) **--organization, --org**="": organization id or full name (e.g. 123 or octocat) @@ -556,14 +549,7 @@ Images: show secret information -**--format**="": format output (deprecated) (default: {{ .Name }}  -Events: {{ list .Events }} -{{- if .Images }} -Images: {{ list .Images }} -{{- else }} -Images: -{{- end }} -) +**--format**="": format output (deprecated) (default: \x1b[33m{{ .Name }} \x1b[0m\nEvents: {{ list .Events }}\n{{- if .Images }}\nImages: {{ list .Images }}\n{{- else }}\nImages: \n{{- end }}\n) **--name**="": secret name @@ -573,9 +559,9 @@ Images: update a secret -**--event**="": limit secret to these event (default: []) +**--event**="": limit secret to these event -**--image**="": limit secret to these image (default: []) +**--image**="": limit secret to these image **--name**="": secret name @@ -599,9 +585,9 @@ create new pipeline **--output**="": output format (default: table) -**--output-no-headers**: don't print headers +**--output-no-headers**: don't print headers (default: false) -**--var**="": key=value (default: []) +**--var**="": key=value ### decline @@ -615,17 +601,9 @@ trigger a pipeline with the 'deployment' event **--event**="": event filter (default: push) -**--format**="": format output (default: Number: {{ .Number }} -Status: {{ .Status }} -Commit: {{ .Commit }} -Branch: {{ .Branch }} -Ref: {{ .Ref }} -Message: {{ .Message }} -Author: {{ .Author }} -Target: {{ .Deploy }} -) +**--format**="": format output (default: Number: {{ .Number }}\nStatus: {{ .Status }}\nCommit: {{ .Commit }}\nBranch: {{ .Branch }}\nRef: {{ .Ref }}\nMessage: {{ .Message }}\nAuthor: {{ .Author }}\nTarget: {{ .Deploy }}\n) -**--param, -p**="": custom parameters to inject into the step environment. Format: KEY=value (default: []) +**--param, -p**="": custom parameters to inject into the step environment. Format: KEY=value **--status**="": status filter (default: success) @@ -637,15 +615,15 @@ show latest pipeline information **--output**="": output format (default: table) -**--output-no-headers**: don't print headers +**--output-no-headers**: don't print headers (default: false) ### ls show pipeline history -**--after**="": only return pipelines after this date (RFC3339) (default: 0001-01-01 00:00:00 +0000 UTC) +**--after**="": only return pipelines after this date (RFC3339) -**--before**="": only return pipelines before this date (RFC3339) (default: 0001-01-01 00:00:00 +0000 UTC) +**--before**="": only return pipelines before this date (RFC3339) **--branch**="": branch filter @@ -655,7 +633,7 @@ show pipeline history **--output**="": output format (default: table) -**--output-no-headers**: don't print headers +**--output-no-headers**: don't print headers (default: false) **--status**="": status filter @@ -675,37 +653,25 @@ show pipeline logs show pipeline steps -**--format**="": format output (default: {{ .workflow.Name }} > {{ .step.Name }} (#{{ .step.PID }}): -Step: {{ .step.Name }} -Started: {{ .step.Started }} -Stopped: {{ .step.Stopped }} -Type: {{ .step.Type }} -State: {{ .step.State }} -) +**--format**="": format output (default: \x1b[33m{{ .workflow.Name }} > {{ .step.Name }} (#{{ .step.PID }}):\x1b[0m\nStep: {{ .step.Name }}\nStarted: {{ .step.Started }}\nStopped: {{ .step.Stopped }}\nType: {{ .step.Type }}\nState: {{ .step.State }}\n) ### purge purge pipelines -**--dry-run**: disable non-read api calls +**--branch**="": remove pipelines of this branch only + +**--dry-run**: disable non-read api calls (default: false) **--keep-min**="": minimum number of pipelines to keep (default: 10) -**--older-than**="": remove pipelines older than the specified time limit +**--older-than**="": remove pipelines older than the specified time limit (default: 0s) ### queue show pipeline queue -**--format**="": format output (default: {{ .FullName }} #{{ .Number }}  -Status: {{ .Status }} -Event: {{ .Event }} -Commit: {{ .Commit }} -Branch: {{ .Branch }} -Ref: {{ .Ref }} -Author: {{ .Author }} {{ if .Email }}<{{.Email}}>{{ end }} -Message: {{ .Message }} -) +**--format**="": format output (default: \x1b[33m{{ .FullName }} #{{ .Number }} \x1b[0m\nStatus: {{ .Status }}\nEvent: {{ .Event }}\nCommit: {{ .Commit }}\nBranch: {{ .Branch }}\nRef: {{ .Ref }}\nAuthor: {{ .Author }} {{ if .Email }}<{{.Email}}>{{ end }}\nMessage: {{ .Message }}\n) ### show @@ -713,13 +679,13 @@ show pipeline information **--output**="": output format (default: table) -**--output-no-headers**: don't print headers +**--output-no-headers**: don't print headers (default: false) ### start start a pipeline -**--param, -p**="": custom parameters to inject into the step environment. Format: KEY=value (default: []) +**--param, -p**="": custom parameters to inject into the step environment. Format: KEY=value ### stop @@ -747,12 +713,7 @@ add a cron job **--branch**="": cron branch -**--format**="": format output (deprecated) (default: {{ .Name }}  -ID: {{ .ID }} -Branch: {{ .Branch }} -Schedule: {{ .Schedule }} -NextExec: {{ .NextExec }} -) +**--format**="": format output (deprecated) (default: \x1b[33m{{ .Name }} \x1b[0m\nID: {{ .ID }}\nBranch: {{ .Branch }}\nSchedule: {{ .Schedule }}\nNextExec: {{ .NextExec }}\n) **--name**="": cron name @@ -772,12 +733,7 @@ remove a cron job list cron jobs -**--format**="": format output (deprecated) (default: {{ .Name }}  -ID: {{ .ID }} -Branch: {{ .Branch }} -Schedule: {{ .Schedule }} -NextExec: {{ .NextExec }} -) +**--format**="": format output (deprecated) (default: \x1b[33m{{ .Name }} \x1b[0m\nID: {{ .ID }}\nBranch: {{ .Branch }}\nSchedule: {{ .Schedule }}\nNextExec: {{ .NextExec }}\n) **--repository, --repo**="": repository id or full name (e.g. 134 or octocat/hello-world) @@ -785,12 +741,7 @@ NextExec: {{ .NextExec }} show cron job information -**--format**="": format output (deprecated) (default: {{ .Name }}  -ID: {{ .ID }} -Branch: {{ .Branch }} -Schedule: {{ .Schedule }} -NextExec: {{ .NextExec }} -) +**--format**="": format output (deprecated) (default: \x1b[33m{{ .Name }} \x1b[0m\nID: {{ .ID }}\nBranch: {{ .Branch }}\nSchedule: {{ .Schedule }}\nNextExec: {{ .NextExec }}\n) **--id**="": cron id @@ -802,12 +753,7 @@ update a cron job **--branch**="": cron branch -**--format**="": format output (deprecated) (default: {{ .Name }}  -ID: {{ .ID }} -Branch: {{ .Branch }} -Schedule: {{ .Schedule }} -NextExec: {{ .NextExec }} -) +**--format**="": format output (deprecated) (default: \x1b[33m{{ .Name }} \x1b[0m\nID: {{ .ID }}\nBranch: {{ .Branch }}\nSchedule: {{ .Schedule }}\nNextExec: {{ .NextExec }}\n) **--id**="": cron id @@ -821,7 +767,7 @@ NextExec: {{ .NextExec }} list all repos -**--all**: query all repos, including inactive ones +**--all**: query all repos, including inactive ones (default: false) **--format**="": format output (deprecated) @@ -829,7 +775,7 @@ list all repos **--output**="": output format (default: table) -**--output-no-headers**: don't print headers +**--output-no-headers**: don't print headers (default: false) ### registry @@ -859,10 +805,7 @@ remove a registry list registries -**--format**="": format output (deprecated) (default: {{ .Address }}  -Username: {{ .Username }} -Email: {{ .Email }} -) +**--format**="": format output (deprecated) (default: \x1b[33m{{ .Address }} \x1b[0m\nUsername: {{ .Username }}\nEmail: {{ .Email }}\n) **--repository, --repo**="": repository id or full name (e.g. 134 or octocat/hello-world) @@ -870,10 +813,7 @@ Email: {{ .Email }} show registry information -**--format**="": format output (deprecated) (default: {{ .Address }}  -Username: {{ .Username }} -Email: {{ .Email }} -) +**--format**="": format output (deprecated) (default: \x1b[33m{{ .Address }} \x1b[0m\nUsername: {{ .Username }}\nEmail: {{ .Email }}\n) **--hostname**="": registry hostname (default: docker.io) @@ -907,9 +847,9 @@ manage secrets add a secret -**--event**="": limit secret to these events (default: []) +**--event**="": limit secret to these events -**--image**="": limit secret to these images (default: []) +**--image**="": limit secret to these images **--name**="": secret name @@ -929,14 +869,7 @@ remove a secret list secrets -**--format**="": format output (deprecated) (default: {{ .Name }}  -Events: {{ list .Events }} -{{- if .Images }} -Images: {{ list .Images }} -{{- else }} -Images: -{{- end }} -) +**--format**="": format output (deprecated) (default: \x1b[33m{{ .Name }} \x1b[0m\nEvents: {{ list .Events }}\n{{- if .Images }}\nImages: {{ list .Images }}\n{{- else }}\nImages: \n{{- end }}\n) **--repository, --repo**="": repository id or full name (e.g. 134 or octocat/hello-world) @@ -944,14 +877,7 @@ Images: show secret information -**--format**="": format output (deprecated) (default: {{ .Name }}  -Events: {{ list .Events }} -{{- if .Images }} -Images: {{ list .Images }} -{{- else }} -Images: -{{- end }} -) +**--format**="": format output (deprecated) (default: \x1b[33m{{ .Name }} \x1b[0m\nEvents: {{ list .Events }}\n{{- if .Images }}\nImages: {{ list .Images }}\n{{- else }}\nImages: \n{{- end }}\n) **--name**="": secret name @@ -961,9 +887,9 @@ Images: update a secret -**--event**="": limit secret to these events (default: []) +**--event**="": limit secret to these events -**--image**="": limit secret to these images (default: []) +**--image**="": limit secret to these images **--name**="": secret name @@ -977,13 +903,13 @@ show repository information **--output**="": output format (default: table) -**--output-no-headers**: don't print headers +**--output-no-headers**: don't print headers (default: false) ### sync synchronize the repository list -**--format**="": format output (default: {{ .FullName }} (id: {{ .ID }}, forgeRemoteID: {{ .ForgeRemoteID }}, isActive: {{ .IsActive }})) +**--format**="": format output (default: \x1b[33m{{ .FullName }}\x1b[0m (id: {{ .ID }}, forgeRemoteID: {{ .ForgeRemoteID }}, isActive: {{ .IsActive }})) ### update @@ -997,9 +923,13 @@ update a repository **--timeout**="": repository timeout (default: 0s) -**--trusted**: repository is trusted +**--trusted-network**: repository is network trusted (default: false) -**--unsafe**: allow unsafe operations +**--trusted-security**: repository is security trusted (default: false) + +**--trusted-volumes**: repository is volumes trusted (default: false) + +**--unsafe**: allow unsafe operations (default: false) **--visibility**="": repository visibility @@ -1007,6 +937,8 @@ update a repository setup the woodpecker-cli for the first time +**--context, --ctx**="": name for the context (defaults to 'default') + **--server**="": URL of the woodpecker server **--token**="": token to authenticate with the woodpecker server @@ -1015,4 +947,4 @@ setup the woodpecker-cli for the first time update the woodpecker-cli to the latest version -**--force**: force update even if the latest version is already installed +**--force**: force update even if the latest version is already installed (default: false) diff --git a/docs/versioned_docs/version-3.10/92-development/01-getting-started.md b/docs/versioned_docs/version-3.13/92-development/01-getting-started.md similarity index 96% rename from docs/versioned_docs/version-3.10/92-development/01-getting-started.md rename to docs/versioned_docs/version-3.13/92-development/01-getting-started.md index 89e5d960c..ed8020202 100644 --- a/docs/versioned_docs/version-3.10/92-development/01-getting-started.md +++ b/docs/versioned_docs/version-3.13/92-development/01-getting-started.md @@ -20,7 +20,7 @@ Start Woodpecker in Gitpod by clicking on the following badge. You can log in wi ### Install Go -Install Golang (>=1.20) as described by [this guide](https://go.dev/doc/install). +Install Golang as described by [this guide](https://go.dev/doc/install). ### Install make @@ -34,7 +34,7 @@ Install make on: ### Install Node.js & `pnpm` -Install [Node.js (>=20)](https://nodejs.org/en/download/package-manager) if you want to build Woodpecker's UI or documentation. +Install [Node.js](https://nodejs.org/en/download/package-manager) if you want to build Woodpecker's UI or documentation. For dependency installation (`node_modules`) of UI and documentation of Woodpecker the package manager pnpm is used. [This guide](https://pnpm.io/installation) describes the installation of `pnpm`. diff --git a/docs/versioned_docs/version-3.10/92-development/02-core-ideas.md b/docs/versioned_docs/version-3.13/92-development/02-core-ideas.md similarity index 85% rename from docs/versioned_docs/version-3.10/92-development/02-core-ideas.md rename to docs/versioned_docs/version-3.13/92-development/02-core-ideas.md index fce17ab24..2f9570685 100644 --- a/docs/versioned_docs/version-3.10/92-development/02-core-ideas.md +++ b/docs/versioned_docs/version-3.13/92-development/02-core-ideas.md @@ -8,7 +8,7 @@ ## Addons and extensions If you are wondering whether your contribution will be accepted to be merged in the Woodpecker core, or whether it's better to write an -[addon forge](../30-administration/10-configuration/12-forges/100-addon.md), [extension](../30-administration/10-configuration/10-server.md#external-configuration-api) or an +[addon](../30-administration/10-configuration/100-addons.md), [extension](../30-administration/10-configuration/10-server.md#external-configuration-api) or an [external custom backend](../30-administration/10-configuration/11-backends/50-custom.md), please check these points: - Is your change very specific to your setup and unlikely to be used by anyone else? diff --git a/docs/versioned_docs/version-3.10/92-development/03-ui.md b/docs/versioned_docs/version-3.13/92-development/03-ui.md similarity index 100% rename from docs/versioned_docs/version-3.10/92-development/03-ui.md rename to docs/versioned_docs/version-3.13/92-development/03-ui.md diff --git a/docs/versioned_docs/version-3.10/92-development/04-docs.md b/docs/versioned_docs/version-3.13/92-development/04-docs.md similarity index 100% rename from docs/versioned_docs/version-3.10/92-development/04-docs.md rename to docs/versioned_docs/version-3.13/92-development/04-docs.md diff --git a/docs/versioned_docs/version-3.10/92-development/05-architecture.md b/docs/versioned_docs/version-3.13/92-development/05-architecture.md similarity index 100% rename from docs/versioned_docs/version-3.10/92-development/05-architecture.md rename to docs/versioned_docs/version-3.13/92-development/05-architecture.md diff --git a/docs/versioned_docs/version-3.10/92-development/06-conventions.md b/docs/versioned_docs/version-3.13/92-development/06-conventions.md similarity index 100% rename from docs/versioned_docs/version-3.10/92-development/06-conventions.md rename to docs/versioned_docs/version-3.13/92-development/06-conventions.md diff --git a/docs/versioned_docs/version-3.10/92-development/07-guides.md b/docs/versioned_docs/version-3.13/92-development/07-guides.md similarity index 100% rename from docs/versioned_docs/version-3.10/92-development/07-guides.md rename to docs/versioned_docs/version-3.13/92-development/07-guides.md diff --git a/docs/versioned_docs/version-3.10/92-development/08-translations.md b/docs/versioned_docs/version-3.13/92-development/08-translations.md similarity index 100% rename from docs/versioned_docs/version-3.10/92-development/08-translations.md rename to docs/versioned_docs/version-3.13/92-development/08-translations.md diff --git a/docs/versioned_docs/version-3.10/92-development/09-openapi.md b/docs/versioned_docs/version-3.13/92-development/09-openapi.md similarity index 100% rename from docs/versioned_docs/version-3.10/92-development/09-openapi.md rename to docs/versioned_docs/version-3.13/92-development/09-openapi.md diff --git a/docs/versioned_docs/version-3.10/92-development/09-testing.md b/docs/versioned_docs/version-3.13/92-development/09-testing.md similarity index 100% rename from docs/versioned_docs/version-3.10/92-development/09-testing.md rename to docs/versioned_docs/version-3.13/92-development/09-testing.md diff --git a/docs/versioned_docs/version-3.13/92-development/10-packaging.md b/docs/versioned_docs/version-3.13/92-development/10-packaging.md new file mode 100644 index 000000000..415b426a4 --- /dev/null +++ b/docs/versioned_docs/version-3.13/92-development/10-packaging.md @@ -0,0 +1,18 @@ +# Packaging + +If you repackage it, we encourage to build from source, which requires internet connection. + +For offline builds, we also offer a tarball with all vendored dependencies and a pre-built web UI +on the [release page](https://github.com/woodpecker-ci/woodpecker/releases). + +## Distribute web UI in own directory + +If you do not want to embed the web UI in the binary, you can compile a custom root path for the web UI into the binary. + +Add `external_web` to the tags and use the build flag `-X go.woodpecker-ci.org/woodpecker/v3/web.webUIRoot=/some/path` to set a custom path. + +Example: + +```sh +go build -tags 'external_web' -ldflags '-s -w -extldflags "-static" -X go.woodpecker-ci.org/woodpecker/v3/version.Version=3.12.0 -X go.woodpecker-ci.org/woodpecker/v3/web.webUIRoot=/nix/store/maaajlp8h5gy9zyjgfhaipzj07qnnmrl-woodpecker-WebUI-3.12.0' -o dist/woodpecker-server go.woodpecker-ci.org/woodpecker/v3/cmd/server +``` diff --git a/docs/versioned_docs/version-3.10/30-administration/10-configuration/12-forges/100-addon.md b/docs/versioned_docs/version-3.13/92-development/100-addons.md similarity index 54% rename from docs/versioned_docs/version-3.10/30-administration/10-configuration/12-forges/100-addon.md rename to docs/versioned_docs/version-3.13/92-development/100-addons.md index 2434fee06..fe5b62a95 100644 --- a/docs/versioned_docs/version-3.10/30-administration/10-configuration/12-forges/100-addon.md +++ b/docs/versioned_docs/version-3.13/92-development/100-addons.md @@ -1,34 +1,16 @@ -# Custom +# Addons -If the forge you are using does not meet the [Woodpecker requirements](../../../92-development/02-core-ideas.md#forges) or your setup is too specific to be included in the Woodpecker core, you can write an addon forge. +The Woodpecker server supports addons for forges and the log store. :::warning -Addon forges are still experimental. Their implementation can change and break at any time. +Addons are still experimental. Their implementation can change and break at any time. ::: -:::danger -You must trust the author of the addon forge you are using. They may have access to authentication codes and other potentially sensitive information. -::: - -## Usage - -To use an addon forge, download the correct addon version. Then, you can add the following to your configuration: - -```ini -WOODPECKER_ADDON_FORGE=/path/to/your/addon/forge/file -``` - -In case you run Woodpecker as container, you probably want to mount the addon binary to `/opt/addons/`. - -### Bug reports +## Bug reports If you experience bugs, please check which component has the issue. If it's the addon, **do not raise an issue in the main repository**, but rather use the separate addon repositories. To check which component is responsible for the bug, look at the logs. Logs from addons are marked with a special field `addon` containing their addon file name. -## List of addon forges - -- [Radicle](https://radicle.xyz/): Open source, peer-to-peer code collaboration stack built on Git. Radicle addon for Woodpecker CI can be found at [this repo](https://explorer.radicle.gr/nodes/seed.radicle.gr/rad:z39Cf1XzrvCLRZZJRUZnx9D1fj5ws). - -## Creating addon forges +## Creating addons Addons use RPC to communicate to the server and are implemented using the [`go-plugin` library](https://github.com/hashicorp/go-plugin). @@ -38,7 +20,7 @@ This example will use the Go language. Directly import Woodpecker's Go packages (`go.woodpecker-ci.org/woodpecker/v3`) and use the interfaces and types defined there. -In the `main` function, just call `"go.woodpecker-ci.org/woodpecker/v3/server/forge/addon".Serve` with a `"go.woodpecker-ci.org/woodpecker/v3/server/forge".Forge` as argument. +In the `main` function, just call the `Serve` method in the corresponding [addon package](#addon-types) with the service as argument. This will take care of connecting the addon forge to the server. :::note @@ -47,6 +29,8 @@ It is not possible to access global variables from Woodpecker, for example the s ### Example structure +This is an example for a forge addon. + ```go package main @@ -68,3 +52,10 @@ type config struct { // `config` must implement `"go.woodpecker-ci.org/woodpecker/v3/server/forge".Forge`. You must directly use Woodpecker's packages - see imports above. ``` + +### Addon types + +| Type | Addon package | Service interface | +| --------- | ------------------------------------------------------------- | ----------------------------------------------------------------- | +| Forge | `go.woodpecker-ci.org/woodpecker/v3/server/forge/addon` | `"go.woodpecker-ci.org/woodpecker/v3/server/forge".Forge` | +| Log store | `go.woodpecker-ci.org/woodpecker/v3/server/service/log/addon` | `"go.woodpecker-ci.org/woodpecker/v3/server/service/log".Service` | diff --git a/docs/versioned_docs/version-3.10/92-development/_category_.yaml b/docs/versioned_docs/version-3.13/92-development/_category_.yaml similarity index 100% rename from docs/versioned_docs/version-3.10/92-development/_category_.yaml rename to docs/versioned_docs/version-3.13/92-development/_category_.yaml diff --git a/docs/versioned_docs/version-3.10/92-development/ui-proxy.svg b/docs/versioned_docs/version-3.13/92-development/ui-proxy.svg similarity index 100% rename from docs/versioned_docs/version-3.10/92-development/ui-proxy.svg rename to docs/versioned_docs/version-3.13/92-development/ui-proxy.svg diff --git a/docs/versioned_docs/version-3.10/92-development/vscode-debug.png b/docs/versioned_docs/version-3.13/92-development/vscode-debug.png similarity index 100% rename from docs/versioned_docs/version-3.10/92-development/vscode-debug.png rename to docs/versioned_docs/version-3.13/92-development/vscode-debug.png diff --git a/docs/versioned_docs/version-3.10/92-development/vscode-run-test.png b/docs/versioned_docs/version-3.13/92-development/vscode-run-test.png similarity index 100% rename from docs/versioned_docs/version-3.10/92-development/vscode-run-test.png rename to docs/versioned_docs/version-3.13/92-development/vscode-run-test.png diff --git a/docs/docs/92-development/woodpecker-architecture.png b/docs/versioned_docs/version-3.13/92-development/woodpecker-architecture.png similarity index 100% rename from docs/docs/92-development/woodpecker-architecture.png rename to docs/versioned_docs/version-3.13/92-development/woodpecker-architecture.png diff --git a/docs/versioned_sidebars/version-3.10-sidebars.json b/docs/versioned_sidebars/version-3.13-sidebars.json similarity index 100% rename from docs/versioned_sidebars/version-3.10-sidebars.json rename to docs/versioned_sidebars/version-3.13-sidebars.json diff --git a/docs/versions.json b/docs/versions.json index 2988f8fd6..71a63593a 100644 --- a/docs/versions.json +++ b/docs/versions.json @@ -1 +1 @@ -["3.12", "3.11", "3.10", "2.8"] +["3.13", "3.12", "3.11", "2.8"] diff --git a/flake.lock b/flake.lock index 0af0e6e70..f38179a2f 100644 --- a/flake.lock +++ b/flake.lock @@ -20,11 +20,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1760366283, - "narHash": "sha256-JCVy7OnkRzAmX3Em8NMnilEI8bGYNKUyxP4TU9AKeek=", + "lastModified": 1770781623, + "narHash": "sha256-RYEMTlGCVc67pxVxjOlGd8w6fpF7Bur7gKL88FB0WTs=", "owner": "nixos", "repo": "nixpkgs", - "rev": "78c9baf72eea1e60a52faf255741ffa257799757", + "rev": "c05d2232d2feaa4c7a07f1168606917402868195", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index e225048b7..543d8e534 100644 --- a/flake.nix +++ b/flake.nix @@ -15,7 +15,7 @@ devShells.default = with pkgs; let - go = go_1_24; + go = go_1_25; in pkgs.mkShell { buildInputs = [ @@ -45,6 +45,9 @@ protoc-gen-go protoc-gen-go-grpc gcc + + # docs + graphviz ]; CFLAGS = "-I${pkgs.glibc.dev}/include"; LDFLAGS = "-L${pkgs.glibc}/lib"; diff --git a/go.mod b/go.mod index a33cf2cf1..aa5ad4ea9 100644 --- a/go.mod +++ b/go.mod @@ -4,42 +4,41 @@ go 1.25.0 require ( al.essio.dev/pkg/shellescape v1.6.0 - code.gitea.io/sdk/gitea v0.22.1 + code.gitea.io/sdk/gitea v0.23.2 codeberg.org/6543/go-yaml2json v1.0.0 codeberg.org/6543/xyaml v1.1.0 codeberg.org/mvdkleijn/forgejo-sdk/forgejo/v2 v2.2.0 github.com/6543/logfile-open v1.2.1 github.com/adrg/xdg v0.5.3 - github.com/bmatcuk/doublestar/v4 v4.9.1 + github.com/bmatcuk/doublestar/v4 v4.10.0 github.com/cenkalti/backoff/v5 v5.0.3 github.com/charmbracelet/huh v0.8.0 github.com/charmbracelet/huh/spinner v0.0.0-20240327025511-ec643317aa10 github.com/containerd/errdefs v1.0.0 github.com/distribution/reference v0.6.0 - github.com/docker/cli v29.1.3+incompatible + github.com/docker/cli v29.2.1+incompatible github.com/docker/docker v28.5.2+incompatible github.com/docker/go-connections v0.6.0 github.com/docker/go-units v0.5.0 github.com/drone/envsubst v1.0.3 - github.com/expr-lang/expr v1.17.7 + github.com/expr-lang/expr v1.17.8 github.com/fsnotify/fsnotify v1.9.0 github.com/gdgvda/cron v0.6.0 github.com/getkin/kin-openapi v0.133.0 github.com/gin-gonic/gin v1.11.0 github.com/gitsight/go-vcsurl v1.0.1 github.com/go-sql-driver/mysql v1.9.3 - github.com/go-viper/mapstructure/v2 v2.4.0 - github.com/golang-jwt/jwt/v5 v5.3.0 - github.com/google/go-github/v80 v80.0.0 - github.com/google/tink/go v1.7.0 + github.com/go-viper/mapstructure/v2 v2.5.0 + github.com/golang-jwt/jwt/v5 v5.3.1 + github.com/google/go-github/v83 v83.0.0 github.com/hashicorp/go-hclog v1.6.3 github.com/hashicorp/go-plugin v1.7.0 github.com/jellydator/ttlcache/v3 v3.4.0 github.com/joho/godotenv v1.5.1 github.com/json-iterator/go v1.1.12 github.com/kinbiko/jsonassert v1.2.0 - github.com/lib/pq v1.10.9 - github.com/mattn/go-sqlite3 v1.14.32 + github.com/lib/pq v1.11.2 + github.com/mattn/go-sqlite3 v1.14.34 github.com/migueleliasweb/go-github-mock v1.5.0 github.com/moby/term v0.5.2 github.com/muesli/termenv v0.16.0 @@ -51,25 +50,27 @@ require ( github.com/swaggo/files v1.0.1 github.com/swaggo/gin-swagger v1.6.1 github.com/swaggo/swag v1.16.6 + github.com/tink-crypto/tink-go/v2 v2.6.0 github.com/urfave/cli-docs/v3 v3.1.1-0.20251022123016-72b87d11c482 - github.com/urfave/cli/v3 v3.6.1 + github.com/urfave/cli/v3 v3.6.2 github.com/xeipuuv/gojsonschema v1.2.0 github.com/yaronf/httpsign v0.4.1 github.com/zalando/go-keyring v0.2.6 - gitlab.com/gitlab-org/api/client-go v1.9.1 + gitlab.com/gitlab-org/api/client-go v1.41.0 go.uber.org/multierr v1.11.0 - golang.org/x/crypto v0.46.0 - golang.org/x/net v0.48.0 - golang.org/x/oauth2 v0.34.0 + golang.org/x/crypto v0.48.0 + golang.org/x/image v0.36.0 + golang.org/x/net v0.50.0 + golang.org/x/oauth2 v0.35.0 golang.org/x/sync v0.19.0 - golang.org/x/term v0.38.0 - golang.org/x/text v0.32.0 - google.golang.org/grpc v1.77.0 + golang.org/x/term v0.40.0 + golang.org/x/text v0.34.0 + google.golang.org/grpc v1.79.1 google.golang.org/protobuf v1.36.11 gopkg.in/yaml.v3 v3.0.1 - k8s.io/api v0.35.0 - k8s.io/apimachinery v0.35.0 - k8s.io/client-go v0.35.0 + k8s.io/api v0.35.1 + k8s.io/apimachinery v0.35.1 + k8s.io/client-go v0.35.1 sigs.k8s.io/yaml v1.6.0 src.techknowlogick.com/xormigrate v1.7.1 xorm.io/builder v0.3.13 @@ -77,7 +78,7 @@ require ( ) require ( - filippo.io/edwards25519 v1.1.0 // indirect + filippo.io/edwards25519 v1.2.0 // indirect github.com/42wim/httpsig v1.2.3 // indirect github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect github.com/KyleBanks/depth v1.2.1 // indirect @@ -127,13 +128,13 @@ require ( github.com/go-playground/validator/v10 v10.27.0 // indirect github.com/goccy/go-json v0.10.5 // indirect github.com/goccy/go-yaml v1.18.0 // indirect - github.com/godbus/dbus/v5 v5.2.0 // indirect + github.com/godbus/dbus/v5 v5.2.2 // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/google/gnostic-models v0.7.0 // indirect github.com/google/go-cmp v0.7.0 // indirect github.com/google/go-github/v73 v73.0.0 // indirect - github.com/google/go-querystring v1.1.0 // indirect + github.com/google/go-querystring v1.2.0 // indirect github.com/google/uuid v1.6.0 // indirect github.com/gorilla/mux v1.8.1 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect @@ -184,8 +185,8 @@ require ( github.com/prometheus/client_model v0.6.2 // indirect github.com/prometheus/common v0.66.1 // indirect github.com/prometheus/procfs v0.16.1 // indirect - github.com/quic-go/qpack v0.5.1 // indirect - github.com/quic-go/quic-go v0.55.0 // indirect + github.com/quic-go/qpack v0.6.0 // indirect + github.com/quic-go/quic-go v0.57.0 // indirect github.com/rivo/uniseg v0.4.7 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/segmentio/asm v1.2.1 // indirect @@ -205,19 +206,18 @@ require ( github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 // indirect - go.opentelemetry.io/otel v1.38.0 // indirect + go.opentelemetry.io/otel v1.39.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.28.0 // indirect - go.opentelemetry.io/otel/metric v1.38.0 // indirect - go.opentelemetry.io/otel/trace v1.38.0 // indirect + go.opentelemetry.io/otel/metric v1.39.0 // indirect + go.opentelemetry.io/otel/trace v1.39.0 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/arch v0.20.0 // indirect - golang.org/x/mod v0.30.0 // indirect - golang.org/x/sys v0.39.0 // indirect + golang.org/x/mod v0.32.0 // indirect + golang.org/x/sys v0.41.0 // indirect golang.org/x/time v0.14.0 // indirect - golang.org/x/tools v0.39.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20251022142026-3a174f9686a8 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 // indirect + golang.org/x/tools v0.41.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 // indirect gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gotest.tools/v3 v3.5.2 // indirect diff --git a/go.sum b/go.sum index b11595377..663b6ce4e 100644 --- a/go.sum +++ b/go.sum @@ -1,15 +1,15 @@ al.essio.dev/pkg/shellescape v1.6.0 h1:NxFcEqzFSEVCGN2yq7Huv/9hyCEGVa/TncnOOBBeXHA= al.essio.dev/pkg/shellescape v1.6.0/go.mod h1:6sIqp7X2P6mThCQ7twERpZTuigpr6KbZWtls1U8I890= -code.gitea.io/sdk/gitea v0.22.1 h1:7K05KjRORyTcTYULQ/AwvlVS6pawLcWyXZcTr7gHFyA= -code.gitea.io/sdk/gitea v0.22.1/go.mod h1:yyF5+GhljqvA30sRDreoyHILruNiy4ASufugzYg0VHM= +code.gitea.io/sdk/gitea v0.23.2 h1:iJB1FDmLegwfwjX8gotBDHdPSbk/ZR8V9VmEJaVsJYg= +code.gitea.io/sdk/gitea v0.23.2/go.mod h1:yyF5+GhljqvA30sRDreoyHILruNiy4ASufugzYg0VHM= codeberg.org/6543/go-yaml2json v1.0.0 h1:heGqo9VEi7gY2yNqjj7X4ADs5nzlFIbGsJtgYDLrnig= codeberg.org/6543/go-yaml2json v1.0.0/go.mod h1:mz61q14LWF4ZABrgMEDMmk3t9dPi6zgR1uBh2VKV2RQ= codeberg.org/6543/xyaml v1.1.0 h1:0PWTy8OUqshshjrrnAXFWXSPUEa8R49DIh2ah07SxFc= codeberg.org/6543/xyaml v1.1.0/go.mod h1:jI7afXLZUxeL4rNNsG1SlHh78L+gma9lK1bIebyFZwA= codeberg.org/mvdkleijn/forgejo-sdk/forgejo/v2 v2.2.0 h1:HTCWpzyWQOHDWt3LzI6/d2jvUDsw/vgGRWm/8BTvcqI= codeberg.org/mvdkleijn/forgejo-sdk/forgejo/v2 v2.2.0/go.mod h1:ZglEEDj+qkxYUb+SQIeqGtFxQrbaMYqIOgahNKb7uxs= -filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= -filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +filippo.io/edwards25519 v1.2.0 h1:crnVqOiS4jqYleHd9vaKZ+HKtHfllngJIiOpNpoJsjo= +filippo.io/edwards25519 v1.2.0/go.mod h1:xzAOLCNug/yB62zG1bQ8uziwrIqIuxhctzJT18Q77mc= gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:lSA0F4e9A2NcQSqGqTOXqu2aRi/XEQxDCBwM8yJtE6s= gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:EXuID2Zs0pAQhH8yz+DNjUbjppKQzKFAn28TMYPB6IU= gitee.com/travelliu/dm v1.8.11192/go.mod h1:DHTzyhCrM843x9VdKVbZ+GKXGRbKM2sJ4LxihRxShkE= @@ -44,8 +44,8 @@ github.com/aymanbagabas/go-udiff v0.3.1 h1:LV+qyBQ2pqe0u42ZsUEtPiCaUoqgA9gYRDs3v github.com/aymanbagabas/go-udiff v0.3.1/go.mod h1:G0fsKmG+P6ylD0r6N/KgQD/nWzgfnl8ZBcNLgcbrw8E= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/bmatcuk/doublestar/v4 v4.9.1 h1:X8jg9rRZmJd4yRy7ZeNDRnM+T3ZfHv15JiBJ/avrEXE= -github.com/bmatcuk/doublestar/v4 v4.9.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= +github.com/bmatcuk/doublestar/v4 v4.10.0 h1:zU9WiOla1YA122oLM6i4EXvGW62DvKZVxIe6TYWexEs= +github.com/bmatcuk/doublestar/v4 v4.10.0/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= github.com/bufbuild/protocompile v0.14.1 h1:iA73zAf/fyljNjQKwYzUHD6AD4R8KMasmwa/FBatYVw= github.com/bufbuild/protocompile v0.14.1/go.mod h1:ppVdAIhbr2H8asPk6k4pY7t9zB1OU5DoEw9xY/FUi1c= github.com/bytedance/sonic v1.14.0 h1:/OfKt8HFw0kh2rj8N0F6C/qPGRESq0BbaNZgcNXXzQQ= @@ -125,8 +125,8 @@ github.com/denisenkom/go-mssqldb v0.12.3/go.mod h1:k0mtMFOnU+AihqFxPMiF05rtiDror github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= -github.com/docker/cli v29.1.3+incompatible h1:+kz9uDWgs+mAaIZojWfFt4d53/jv0ZUOOoSh5ZnH36c= -github.com/docker/cli v29.1.3+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/cli v29.2.1+incompatible h1:n3Jt0QVCN65eiVBoUTZQM9mcQICCJt3akW4pKAbKdJg= +github.com/docker/cli v29.2.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/docker v28.5.2+incompatible h1:DBX0Y0zAjZbSrm1uzOkdr1onVghKaftjlSWt4AFexzM= github.com/docker/docker v28.5.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker-credential-helpers v0.8.0 h1:YQFtbBQb4VrpoPxhFuzEBPQ9E16qz5SpHLS+uswaCp8= @@ -146,8 +146,8 @@ github.com/emicklei/go-restful/v3 v3.12.2 h1:DhwDP0vY3k8ZzE0RunuJy8GhNpPL6zqLkDf github.com/emicklei/go-restful/v3 v3.12.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4= github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM= -github.com/expr-lang/expr v1.17.7 h1:Q0xY/e/2aCIp8g9s/LGvMDCC5PxYlvHgDZRQ4y16JX8= -github.com/expr-lang/expr v1.17.7/go.mod h1:8/vRC7+7HBzESEqt5kKpYXxrxkr31SaO8r40VO/1IT4= +github.com/expr-lang/expr v1.17.8 h1:W1loDTT+0PQf5YteHSTpju2qfUfNoBt4yw9+wOEU9VM= +github.com/expr-lang/expr v1.17.8/go.mod h1:8/vRC7+7HBzESEqt5kKpYXxrxkr31SaO8r40VO/1IT4= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= @@ -208,8 +208,8 @@ github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1v github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= -github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= -github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= +github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro= +github.com/go-viper/mapstructure/v2 v2.5.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/goccy/go-json v0.8.1/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= @@ -217,11 +217,11 @@ github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PU github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw= github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/godbus/dbus/v5 v5.2.0 h1:3WexO+U+yg9T70v9FdHr9kCxYlazaAXUhx2VMkbfax8= -github.com/godbus/dbus/v5 v5.2.0/go.mod h1:3AAv2+hPq5rdnr5txxxRwiGjPXamgoIHgz9FPBfOp3c= +github.com/godbus/dbus/v5 v5.2.2 h1:TUR3TgtSVDmjiXOgAAyaZbYmIeP3DPkld3jgKGV8mXQ= +github.com/godbus/dbus/v5 v5.2.2/go.mod h1:3AAv2+hPq5rdnr5txxxRwiGjPXamgoIHgz9FPBfOp3c= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= -github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo= -github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= +github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY= +github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA= github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= @@ -246,17 +246,17 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/go-github/v73 v73.0.0 h1:aR+Utnh+Y4mMkS+2qLQwcQ/cF9mOTpdwnzlaw//rG24= github.com/google/go-github/v73 v73.0.0/go.mod h1:fa6w8+/V+edSU0muqdhCVY7Beh1M8F1IlQPZIANKIYw= -github.com/google/go-github/v80 v80.0.0 h1:BTyk3QOHekrk5VF+jIGz1TNEsmeoQG9K/UWaaP+EWQs= -github.com/google/go-github/v80 v80.0.0/go.mod h1:pRo4AIMdHW83HNMGfNysgSAv0vmu+/pkY8nZO9FT9Yo= -github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= -github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= +github.com/google/go-github/v83 v83.0.0 h1:Ydy4gAfqxrnFUwXAuKl/OMhhGa0KtMtnJ3EozIIuHT0= +github.com/google/go-github/v83 v83.0.0/go.mod h1:gbqarhK37mpSu8Xy7sz21ITtznvzouyHSAajSaYCHe8= +github.com/google/go-querystring v1.2.0 h1:yhqkPbu2/OH+V9BfpCVPZkNmUXhb2gBxJArfhIxNtP0= +github.com/google/go-querystring v1.2.0/go.mod h1:8IFJqpSRITyJ8QhQ13bmbeMBDfmeEJZD5A0egEOmkqU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo= github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J0b1vyeLSOYI8bm5wbJM/8yDe8= @@ -264,13 +264,13 @@ github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= -github.com/google/tink/go v1.7.0 h1:6Eox8zONGebBFcCBqkVmt60LaWZa6xg1cl/DwAh/J1w= -github.com/google/tink/go v1.7.0/go.mod h1:GAUOd+QE3pgj9q8VKIGTCP33c/B7eb4NhxLcgTJZStM= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= +github.com/graph-gophers/graphql-go v1.8.0 h1:NT05/H+PdH1/PONExlUycnhULYHBy98dxV63WYc0Ng8= +github.com/graph-gophers/graphql-go v1.8.0/go.mod h1:23olKZ7duEvHlF/2ELEoSZaY1aNPfShjP782SOoNTyM= github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0= github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= @@ -389,8 +389,8 @@ github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= -github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lib/pq v1.11.2 h1:x6gxUeu39V0BHZiugWe8LXZYZ+Utk7hSJGThs8sdzfs= +github.com/lib/pq v1.11.2/go.mod h1:/p+8NSbOcwzAEI7wiMXFlgydTwcgTr3OSKMsD2BitpA= github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= @@ -415,8 +415,8 @@ github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6T github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= -github.com/mattn/go-sqlite3 v1.14.32 h1:JD12Ag3oLy1zQA+BNn74xRgaBbdhbNIDYvQUEuuErjs= -github.com/mattn/go-sqlite3 v1.14.32/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +github.com/mattn/go-sqlite3 v1.14.34 h1:3NtcvcUnFBPsuRcno8pUtupspG/GM+9nZ88zgJcp6Zk= +github.com/mattn/go-sqlite3 v1.14.34/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/migueleliasweb/go-github-mock v1.5.0 h1:dIr6vgVz8QY9sDiDopWxk6pDw4d7K/xIcCk/NQe4ajM= github.com/migueleliasweb/go-github-mock v1.5.0/go.mod h1:/DUmhXkxrgVlDOVBqGoUXkV4w0ms5n1jDQHotYm135o= github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= @@ -499,10 +499,10 @@ github.com/prometheus/common v0.66.1 h1:h5E0h5/Y8niHc5DlaLlWLArTQI7tMrsfQjHV+d9Z github.com/prometheus/common v0.66.1/go.mod h1:gcaUsgf3KfRSwHY4dIMXLPV0K/Wg1oZ8+SbZk/HH/dA= github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= -github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI= -github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg= -github.com/quic-go/quic-go v0.55.0 h1:zccPQIqYCXDt5NmcEabyYvOnomjs8Tlwl7tISjJh9Mk= -github.com/quic-go/quic-go v0.55.0/go.mod h1:DR51ilwU1uE164KuWXhinFcKWGlEjzys2l8zUl5Ss1U= +github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8= +github.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9qMDZII= +github.com/quic-go/quic-go v0.57.0 h1:AsSSrrMs4qI/hLrKlTH/TGQeTMY0ib1pAOX7vA3AdqE= +github.com/quic-go/quic-go v0.57.0/go.mod h1:ly4QBAjHA2VhdnxhojRsCUOeJwKYg+taDlos92xb1+s= github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= @@ -562,6 +562,8 @@ github.com/swaggo/swag v1.16.6 h1:qBNcx53ZaX+M5dxVyTrgQ0PJ/ACK+NzhwcbieTt+9yI= github.com/swaggo/swag v1.16.6/go.mod h1:ngP2etMK5a0P3QBizic5MEwpRmluJZPHjXcMoj4Xesg= github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE= github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= +github.com/tink-crypto/tink-go/v2 v2.6.0 h1:+KHNBHhWH33Vn+igZWcsgdEPUxKwBMEe0QC60t388v4= +github.com/tink-crypto/tink-go/v2 v2.6.0/go.mod h1:2WbBA6pfNsAfBwDCggboaHeB2X29wkU8XHtGwh2YIk8= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go/codec v1.3.0 h1:Qd2W2sQawAfG8XSvzwhBeoGq71zXOC/Q1E9y/wUcsUA= @@ -570,8 +572,8 @@ github.com/urfave/cli-docs/v3 v3.1.1-0.20251022123016-72b87d11c482 h1:xlSy8R55vu github.com/urfave/cli-docs/v3 v3.1.1-0.20251022123016-72b87d11c482/go.mod h1:cjSVza4yCaqQet06zO6QhYqXQYjGRqbUj8zok6mHDRU= github.com/urfave/cli/v2 v2.25.3 h1:VJkt6wvEBOoSjPFQvOkv6iWIrsJyCrKGtCtxXWwmGeY= github.com/urfave/cli/v2 v2.25.3/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc= -github.com/urfave/cli/v3 v3.6.1 h1:j8Qq8NyUawj/7rTYdBGrxcH7A/j7/G8Q5LhWEW4G3Mo= -github.com/urfave/cli/v3 v3.6.1/go.mod h1:ysVLtOEmg2tOy6PknnYVhDoouyC/6N42TMeoMzskhso= +github.com/urfave/cli/v3 v3.6.2 h1:lQuqiPrZ1cIz8hz+HcrG0TNZFxU70dPZ3Yl+pSrH9A8= +github.com/urfave/cli/v3 v3.6.2/go.mod h1:ysVLtOEmg2tOy6PknnYVhDoouyC/6N42TMeoMzskhso= github.com/valyala/fastjson v1.6.4 h1:uAUNq9Z6ymTgGhcm0UynUAB6tlbakBrz6CQFax3BXVQ= github.com/valyala/fastjson v1.6.4/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY= github.com/woodsbury/decimal128 v1.3.0 h1:8pffMNWIlC0O5vbyHWFZAt5yWvWcrHA+3ovIIjVWss0= @@ -597,26 +599,26 @@ github.com/zalando/go-keyring v0.2.6 h1:r7Yc3+H+Ux0+M72zacZoItR3UDxeWfKTcabvkI8u github.com/zalando/go-keyring v0.2.6/go.mod h1:2TCrxYrbUNYfNS/Kgy/LSrkSQzZ5UPVH85RwfczwvcI= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= -gitlab.com/gitlab-org/api/client-go v1.9.1 h1:tZm+URa36sVy8UCEHQyGGJ8COngV4YqMHpM6k9O5tK8= -gitlab.com/gitlab-org/api/client-go v1.9.1/go.mod h1:71yTJk1lnHCWcZLvM5kPAXzeJ2fn5GjaoV8gTOPd4ME= +gitlab.com/gitlab-org/api/client-go v1.41.0 h1:qSWU5zSO9SbY7BUBIUCJ9nowN3adxdZguZWWfO8icLI= +gitlab.com/gitlab-org/api/client-go v1.41.0/go.mod h1:xS4YrDOA5gcM+aDQ+uiQ9TparIEgfCiEzFA7TChGZPY= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 h1:TT4fX+nBOA/+LUkobKGW1ydGcn+G3vRw9+g5HwCphpk= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8= -go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= -go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= +go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48= +go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 h1:3Q/xZUyC1BBkualc9ROb4G8qkH90LXEIICcs5zv1OYY= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0/go.mod h1:s75jGIWA9OfCMzF0xr+ZgfrB5FEbbV7UuYo32ahUiFI= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.28.0 h1:j9+03ymgYhPKmeXGk5Zu+cIZOlVzd9Zv7QIiyItjFBU= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.28.0/go.mod h1:Y5+XiUG4Emn1hTfciPzGPJaSI+RpDts6BnCIir0SLqk= -go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= -go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= -go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= -go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= -go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= -go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= -go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= -go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= +go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0= +go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs= +go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18= +go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE= +go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8= +go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew= +go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI= +go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA= go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= @@ -656,17 +658,19 @@ golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= -golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= -golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= +golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts= +golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos= golang.org/x/exp v0.0.0-20250813145105-42675adae3e6 h1:SbTAbRFnd5kjQXbczszQ0hdk3ctwYf3qBNH9jIsGclE= golang.org/x/exp v0.0.0-20250813145105-42675adae3e6/go.mod h1:4QTo5u+SEIbbKW1RacMZq1YEfOBqeXa19JeshGi+zc4= +golang.org/x/image v0.36.0 h1:Iknbfm1afbgtwPTmHnS2gTM/6PPZfH+z2EFuOkSbqwc= +golang.org/x/image v0.36.0/go.mod h1:YsWD2TyyGKiIX1kZlu9QfKIsQ4nAAK9bdgdrIsE7xy4= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk= -golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc= +golang.org/x/mod v0.32.0 h1:9F4d3PHLljb6x//jOyokMv3eX+YDeepZSEo3mFJy93c= +golang.org/x/mod v0.32.0/go.mod h1:SgipZ/3h2Ci89DlEtEXWUk/HteuRin+HHhN+WbNhguU= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -680,10 +684,10 @@ golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= -golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= -golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw= -golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= +golang.org/x/net v0.50.0 h1:ucWh9eiCGyDR3vtzso0WMQinm2Dnt8cFMuQa9K33J60= +golang.org/x/net v0.50.0/go.mod h1:UgoSli3F/pBgdJBHCTc+tp3gmrU4XswgGRgtnwWTfyM= +golang.org/x/oauth2 v0.35.0 h1:Mv2mzuHuZuY2+bkyWXIHMfhNdJAdwW3FuWeCPYN5GVQ= +golang.org/x/oauth2 v0.35.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -723,14 +727,14 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= -golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= +golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q= -golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg= +golang.org/x/term v0.40.0 h1:36e4zGLqU4yhjlmxEaagx2KuYbJq3EwY8K943ZsHcvg= +golang.org/x/term v0.40.0/go.mod h1:w2P8uVp06p2iyKKuvXIm7N/y0UCRt3UfJTfZ7oOpglM= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -738,8 +742,8 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= -golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= +golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk= +golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA= golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -754,8 +758,8 @@ golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ= -golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ= +golang.org/x/tools v0.41.0 h1:a9b8iMweWG+S0OBnlU36rzLp20z1Rp10w+IY2czHTQc= +golang.org/x/tools v0.41.0/go.mod h1:XSY6eDqxVNiYgezAVqqCeihT4j1U2CCsqvH3WhQpnlg= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -764,12 +768,12 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= -google.golang.org/genproto/googleapis/api v0.0.0-20251022142026-3a174f9686a8 h1:mepRgnBZa07I4TRuomDE4sTIYieg/osKmzIf4USdWS4= -google.golang.org/genproto/googleapis/api v0.0.0-20251022142026-3a174f9686a8/go.mod h1:fDMmzKV90WSg1NbozdqrE64fkuTv6mlq2zxo9ad+3yo= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 h1:M1rk8KBnUsBDg1oPGHNCxG4vc1f49epmTO7xscSajMk= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= -google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= -google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= +google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217 h1:fCvbg86sFXwdrl5LgVcTEvNC+2txB5mgROGmRL5mrls= +google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:+rXWjjaukWZun3mLfjmVnQi18E1AsFbDN9QdJ5YXLto= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 h1:gRkg/vSppuSQoDjxyiGfN4Upv/h/DQmIR10ZU8dh4Ww= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= +google.golang.org/grpc v1.79.1 h1:zGhSi45ODB9/p3VAawt9a+O/MULLl9dpizzNNpq7flY= +google.golang.org/grpc v1.79.1/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -804,12 +808,12 @@ gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q= gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -k8s.io/api v0.35.0 h1:iBAU5LTyBI9vw3L5glmat1njFK34srdLmktWwLTprlY= -k8s.io/api v0.35.0/go.mod h1:AQ0SNTzm4ZAczM03QH42c7l3bih1TbAXYo0DkF8ktnA= -k8s.io/apimachinery v0.35.0 h1:Z2L3IHvPVv/MJ7xRxHEtk6GoJElaAqDCCU0S6ncYok8= -k8s.io/apimachinery v0.35.0/go.mod h1:jQCgFZFR1F4Ik7hvr2g84RTJSZegBc8yHgFWKn//hns= -k8s.io/client-go v0.35.0 h1:IAW0ifFbfQQwQmga0UdoH0yvdqrbwMdq9vIFEhRpxBE= -k8s.io/client-go v0.35.0/go.mod h1:q2E5AAyqcbeLGPdoRB+Nxe3KYTfPce1Dnu1myQdqz9o= +k8s.io/api v0.35.1 h1:0PO/1FhlK/EQNVK5+txc4FuhQibV25VLSdLMmGpDE/Q= +k8s.io/api v0.35.1/go.mod h1:28uR9xlXWml9eT0uaGo6y71xK86JBELShLy4wR1XtxM= +k8s.io/apimachinery v0.35.1 h1:yxO6gV555P1YV0SANtnTjXYfiivaTPvCTKX6w6qdDsU= +k8s.io/apimachinery v0.35.1/go.mod h1:jQCgFZFR1F4Ik7hvr2g84RTJSZegBc8yHgFWKn//hns= +k8s.io/client-go v0.35.1 h1:+eSfZHwuo/I19PaSxqumjqZ9l5XiTEKbIaJ+j1wLcLM= +k8s.io/client-go v0.35.1/go.mod h1:1p1KxDt3a0ruRfc/pG4qT/3oHmUj1AhSHEcxNSGg+OA= k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 h1:Y3gxNAuB0OBLImH611+UDZcmKS3g6CthxToOb37KgwE= diff --git a/nfpm/agent.yaml b/nfpm/agent.yaml index ca934dd6a..b19a6a8a8 100644 --- a/nfpm/agent.yaml +++ b/nfpm/agent.yaml @@ -3,7 +3,7 @@ arch: amd64 platform: linux version: ${VERSION_NUMBER} description: Woodpecker Agent -homepage: https://github.com/woodpecker-ci/woodpecker +homepage: https://woodpecker-ci.org/ license: Apache 2.0 maintainer: Woodpecker Authors section: daemon/system @@ -14,3 +14,8 @@ contents: dst: /usr/local/lib/systemd/system/woodpecker-agent.service - src: ./nfpm/woodpecker-agent.env.example dst: /etc/woodpecker/woodpecker-agent.env.example + - dst: /var/lib/woodpecker/ + type: dir + file_info: + owner: woodpecker + group: woodpecker diff --git a/nfpm/cli.yaml b/nfpm/cli.yaml index 3f7bc2429..462ac9584 100644 --- a/nfpm/cli.yaml +++ b/nfpm/cli.yaml @@ -3,7 +3,7 @@ arch: amd64 platform: linux version: ${VERSION_NUMBER} description: Woodpecker CLI -homepage: https://github.com/woodpecker-ci/woodpecker +homepage: https://woodpecker-ci.org/ license: Apache 2.0 maintainer: Woodpecker Authors section: utils diff --git a/nfpm/server.yaml b/nfpm/server.yaml index 4b472befc..17f9e6a47 100644 --- a/nfpm/server.yaml +++ b/nfpm/server.yaml @@ -3,7 +3,7 @@ arch: amd64 platform: linux version: ${VERSION_NUMBER} description: Woodpecker Server -homepage: https://github.com/woodpecker-ci/woodpecker +homepage: https://woodpecker-ci.org/ license: Apache 2.0 maintainer: Woodpecker Authors section: daemon/system @@ -14,3 +14,8 @@ contents: dst: /usr/local/lib/systemd/system/woodpecker-server.service - src: ./nfpm/woodpecker-server.env.example dst: /etc/woodpecker/woodpecker-server.env.example + - dst: /var/lib/woodpecker/ + type: dir + file_info: + owner: woodpecker + group: woodpecker diff --git a/nfpm/woodpecker-agent.env.example b/nfpm/woodpecker-agent.env.example index 59c13c968..462ef2ca3 100644 --- a/nfpm/woodpecker-agent.env.example +++ b/nfpm/woodpecker-agent.env.example @@ -1,7 +1,7 @@ # Example for a woodpecker-agent.env file # Check the documentation for the agent: -# https://woodpecker-ci.org/docs/administration/agent-config +# https://woodpecker-ci.org/docs/administration/configuration/agent # Add all required environment variables for your setup in the form of VARIABLE=value VARIABLE=value diff --git a/nfpm/woodpecker-server.env.example b/nfpm/woodpecker-server.env.example index 32418c677..9df2ca0ce 100644 --- a/nfpm/woodpecker-server.env.example +++ b/nfpm/woodpecker-server.env.example @@ -1,7 +1,7 @@ # Example for a woodpecker-server.env file # Check the documentation for the server: -# https://woodpecker-ci.org/docs/administration/server-config +# https://woodpecker-ci.org/docs/administration/configuration/server # Add all required environment variables for your setup in the form of VARIABLE=value VARIABLE=value diff --git a/nfpm/woodpecker-server.service b/nfpm/woodpecker-server.service index 3968ee5d5..8e3f42159 100644 --- a/nfpm/woodpecker-server.service +++ b/nfpm/woodpecker-server.service @@ -1,6 +1,6 @@ [Unit] Description=WoodpeckerCI server -Documentation=https://woodpecker-ci.org/docs/administration/server-config +Documentation=https://woodpecker-ci.org/docs/administration/configuration/server Requires=network.target After=network.target ConditionFileNotEmpty=/etc/woodpecker/woodpecker-server.env diff --git a/pipeline/backend/common/script_posix.go b/pipeline/backend/common/script_posix.go index 221648784..03b772d2a 100644 --- a/pipeline/backend/common/script_posix.go +++ b/pipeline/backend/common/script_posix.go @@ -35,11 +35,11 @@ func generateScriptPosix(commands []string, workDir string) string { } for _, command := range commands { - buf.WriteString(fmt.Sprintf( + fmt.Fprintf(&buf, traceScript, shellescape.Quote(command), command, - )) + ) } return buf.String() diff --git a/pipeline/backend/common/script_win.go b/pipeline/backend/common/script_win.go index 8fb40044f..5507e3f11 100644 --- a/pipeline/backend/common/script_win.go +++ b/pipeline/backend/common/script_win.go @@ -34,11 +34,11 @@ func generateScriptWindows(commands []string, workDir string) string { for _, command := range commands { escaped := fmt.Sprintf("%q", command) escaped = strings.ReplaceAll(escaped, "$", `\$`) - buf.WriteString(fmt.Sprintf( + fmt.Fprintf(&buf, traceScriptWin, escaped, command, - )) + ) } return buf.String() diff --git a/pipeline/backend/docker/docker.go b/pipeline/backend/docker/docker.go index 8a48fdd72..057284c26 100644 --- a/pipeline/backend/docker/docker.go +++ b/pipeline/backend/docker/docker.go @@ -16,6 +16,8 @@ package docker import ( "context" + "errors" + "fmt" "io" "net/http" "os" @@ -35,12 +37,15 @@ import ( "github.com/moby/term" "github.com/rs/zerolog/log" "github.com/urfave/cli/v3" + "golang.org/x/sync/errgroup" backend "go.woodpecker-ci.org/woodpecker/v3/pipeline/backend/types" "go.woodpecker-ci.org/woodpecker/v3/shared/httputil" "go.woodpecker-ci.org/woodpecker/v3/shared/utils" ) +var containerKillTimeout = 5 // seconds + type docker struct { client client.APIClient info system.Info @@ -304,13 +309,24 @@ func (e *docker) DestroyStep(ctx context.Context, step *backend.Step, taskUUID s log.Trace().Str("taskUUID", taskUUID).Msgf("stop step %s", step.Name) containerName := toContainerName(step) + var stopErr error - if err := e.client.ContainerKill(ctx, containerName, "9"); err != nil && !isErrContainerNotFoundOrNotRunning(err) { - return err + // we first signal to the container to stop ... + if err := e.client.ContainerStop(ctx, containerName, container.StopOptions{ + Timeout: &containerKillTimeout, + }); err != nil && !isErrContainerNotFoundOrNotRunning(err) { + // we do not return error yet as we try to kill it first + stopErr = fmt.Errorf("could not stop container '%s': %w", step.Name, err) } + // ... and if stop does not work just force kill it + if err := e.client.ContainerKill(ctx, containerName, "9"); err != nil && !isErrContainerNotFoundOrNotRunning(err) { + return errors.Join(stopErr, fmt.Errorf("could not kill container '%s': %w", step.Name, err)) + } + + // now we clean up files left if err := e.client.ContainerRemove(ctx, containerName, removeOpts); err != nil && !isErrContainerNotFoundOrNotRunning(err) { - return err + return fmt.Errorf("could not remove container '%s': %w", step.Name, err) } return nil @@ -319,17 +335,20 @@ func (e *docker) DestroyStep(ctx context.Context, step *backend.Step, taskUUID s func (e *docker) DestroyWorkflow(ctx context.Context, conf *backend.Config, taskUUID string) error { log.Trace().Str("taskUUID", taskUUID).Msgf("delete workflow environment") + errWG := errgroup.Group{} + for _, stage := range conf.Stages { for _, step := range stage.Steps { - containerName := toContainerName(step) - if err := e.client.ContainerKill(ctx, containerName, "9"); err != nil && !isErrContainerNotFoundOrNotRunning(err) { - log.Error().Err(err).Msgf("could not kill container '%s'", step.Name) - } - if err := e.client.ContainerRemove(ctx, containerName, removeOpts); err != nil && !isErrContainerNotFoundOrNotRunning(err) { - log.Error().Err(err).Msgf("could not remove container '%s'", step.Name) - } + errWG.Go(func() error { + return e.DestroyStep(ctx, step, taskUUID) + }) } } + + if err := errWG.Wait(); err != nil { + log.Error().Err(err).Msgf("could not destroy all containers") + } + if err := e.client.VolumeRemove(ctx, conf.Volume, true); err != nil { log.Error().Err(err).Msgf("could not remove volume '%s'", conf.Volume) } @@ -349,8 +368,13 @@ func isErrContainerNotFoundOrNotRunning(err error) bool { // Error response from daemon: Cannot kill container: ...: No such container: ... // Error response from daemon: Cannot kill container: ...: Container ... is not running" // Error response from podman daemon: can only kill running containers. ... is in state exited + // Error response from daemon: removal of container ... is already in progress // Error: No such container: ... - return err != nil && (strings.Contains(err.Error(), "No such container") || strings.Contains(err.Error(), "is not running") || strings.Contains(err.Error(), "can only kill running containers")) + return err != nil && + (strings.Contains(err.Error(), "No such container") || + strings.Contains(err.Error(), "is not running") || + strings.Contains(err.Error(), "can only kill running containers") || + (strings.Contains(err.Error(), "removal of container") && strings.Contains(err.Error(), "is already in progress"))) } // normalizeArchType converts the arch type reported by docker info into diff --git a/pipeline/backend/dummy/dummy.go b/pipeline/backend/dummy/dummy.go index 650b63dcb..69eb8d5aa 100644 --- a/pipeline/backend/dummy/dummy.go +++ b/pipeline/backend/dummy/dummy.go @@ -200,7 +200,7 @@ func (e *dummy) DestroyStep(_ context.Context, step *backend.Step, taskUUID stri _, exist := e.kv.Load("task_" + taskUUID) if !exist { - return fmt.Errorf("expect env of workflow %s to exist but found none to destroy", taskUUID) + return nil } // check state diff --git a/pipeline/backend/dummy/dummy_test.go b/pipeline/backend/dummy/dummy_test.go index c0d78d656..90a3555b3 100644 --- a/pipeline/backend/dummy/dummy_test.go +++ b/pipeline/backend/dummy/dummy_test.go @@ -47,9 +47,6 @@ func TestSmalPipelineDummyRun(t *testing.T) { _, err = dummyEngine.WaitStep(ctx, step, nonExistWorkflowID) assert.Error(t, err) - - err = dummyEngine.DestroyStep(ctx, step, nonExistWorkflowID) - assert.Error(t, err) }) t.Run("step exec successfully", func(t *testing.T) { diff --git a/pipeline/backend/local/clone.go b/pipeline/backend/local/clone.go index 11b4a8ad2..30c072d8c 100644 --- a/pipeline/backend/local/clone.go +++ b/pipeline/backend/local/clone.go @@ -47,7 +47,7 @@ func (e *local) loadClone() { } // setupClone prepare the clone environment before exec. -func (e *local) setupClone(state *workflowState) error { +func (e *local) setupClone(ctx context.Context, state *workflowState) error { if e.pluginGitBinary != "" { state.pluginGitBinary = e.pluginGitBinary return nil @@ -58,7 +58,7 @@ func (e *local) setupClone(state *workflowState) error { if e.os == "windows" { state.pluginGitBinary += ".exe" } - return e.downloadLatestGitPluginBinary(state.pluginGitBinary) + return e.downloadLatestGitPluginBinary(ctx, state.pluginGitBinary) } // execClone executes a clone-step locally. @@ -67,7 +67,7 @@ func (e *local) execClone(ctx context.Context, step *types.Step, state *workflow return fmt.Errorf("check for git clone capabilities failed: %w", err) } - if err := e.setupClone(state); err != nil { + if err := e.setupClone(ctx, state); err != nil { return fmt.Errorf("setup clone step failed: %w", err) } @@ -137,7 +137,7 @@ func (e *local) writeNetRC(step *types.Step, state *workflowState) (string, erro // downloadLatestGitPluginBinary download the latest plugin-git binary based on runtime OS and Arch // and saves it to dest. -func (e *local) downloadLatestGitPluginBinary(dest string) error { +func (e *local) downloadLatestGitPluginBinary(ctx context.Context, dest string) error { type asset struct { Name string BrowserDownloadURL string `json:"browser_download_url"` @@ -148,7 +148,7 @@ func (e *local) downloadLatestGitPluginBinary(dest string) error { } // get latest release - req, _ := http.NewRequest(http.MethodGet, "https://api.github.com/repos/woodpecker-ci/plugin-git/releases/latest", nil) + req, _ := http.NewRequestWithContext(ctx, http.MethodGet, "https://api.github.com/repos/woodpecker-ci/plugin-git/releases/latest", nil) req.Header.Set("Accept", "application/vnd.github+json") req.Header.Set("X-GitHub-Api-Version", "2022-11-28") resp, err := http.DefaultClient.Do(req) @@ -164,11 +164,15 @@ func (e *local) downloadLatestGitPluginBinary(dest string) error { for _, at := range rel.Assets { if strings.Contains(at.Name, e.os) && strings.Contains(at.Name, e.arch) { - resp2, err := http.Get(at.BrowserDownloadURL) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, at.BrowserDownloadURL, nil) + if err != nil { + return err + } + assetResp, err := http.DefaultClient.Do(req) if err != nil { return fmt.Errorf("could not download plugin-git: %w", err) } - defer resp2.Body.Close() + defer assetResp.Body.Close() file, err := os.Create(dest) if err != nil { @@ -176,7 +180,7 @@ func (e *local) downloadLatestGitPluginBinary(dest string) error { } defer file.Close() - if _, err := io.Copy(file, resp2.Body); err != nil { + if _, err := io.Copy(file, assetResp.Body); err != nil { return fmt.Errorf("could not download plugin-git: %w", err) } if err := os.Chmod(dest, 0o755); err != nil { diff --git a/pipeline/backend/local/command.go b/pipeline/backend/local/command.go index 099b9d3c4..e1956e5db 100644 --- a/pipeline/backend/local/command.go +++ b/pipeline/backend/local/command.go @@ -39,7 +39,7 @@ func (e *local) execCommands(ctx context.Context, step *types.Step, state *workf // Prepare commands // TODO: support `entrypoint` from pipeline config - args, err := e.genCmdByShell(step.Image, step.Commands) + args, err := e.genCmdByShell(step.Image, step.Commands, state.baseDir) if err != nil { return fmt.Errorf("could not convert commands into args: %w", err) } @@ -77,7 +77,7 @@ func checkShellExistence(shell string) error { return err } -func (e *local) genCmdByShell(shell string, cmdList []string) (args []string, err error) { +func (e *local) genCmdByShell(shell string, cmdList []string, baseDir string) (args []string, err error) { if len(cmdList) == 0 { return nil, ErrNoCmdSet } @@ -116,7 +116,7 @@ func (e *local) genCmdByShell(shell string, cmdList []string) (args []string, er script += fmt.Sprintf("@%s\n", cmd) script += "@IF NOT %ERRORLEVEL% == 0 exit %ERRORLEVEL%\n" } - cmd, err := os.CreateTemp(e.tempDir, "*.cmd") + cmd, err := os.CreateTemp(baseDir, "*.cmd") if err != nil { return nil, err } diff --git a/pipeline/backend/local/command_test.go b/pipeline/backend/local/command_test.go index 4a4afdc8a..24c848272 100644 --- a/pipeline/backend/local/command_test.go +++ b/pipeline/backend/local/command_test.go @@ -29,18 +29,18 @@ func TestGenCmdByShell(t *testing.T) { e := local{tempDir: tmpDir} t.Run("error cases", func(t *testing.T) { - args, err := e.genCmdByShell("", []string{"echo hi"}) + args, err := e.genCmdByShell("", []string{"echo hi"}, t.TempDir()) assert.Nil(t, args) assert.ErrorIs(t, err, ErrNoShellSet) - args, err = e.genCmdByShell("sh", []string{}) + args, err = e.genCmdByShell("sh", []string{}, t.TempDir()) assert.Nil(t, args) assert.ErrorIs(t, err, ErrNoCmdSet) }) t.Run("windows shells", func(t *testing.T) { t.Run("cmd", func(t *testing.T) { - args, err := e.genCmdByShell("cmd.exe", []string{"echo hi", "call build.bat"}) + args, err := e.genCmdByShell("cmd.exe", []string{"echo hi", "call build.bat"}, t.TempDir()) require.NoError(t, err) require.Len(t, args, 2) assert.Equal(t, "/c", args[0]) @@ -60,7 +60,7 @@ func TestGenCmdByShell(t *testing.T) { }) t.Run("powershell", func(t *testing.T) { - args, err := e.genCmdByShell("powershell", []string{"Write-Host 'test'", "echo test"}) + args, err := e.genCmdByShell("powershell", []string{"Write-Host 'test'", "echo test"}, t.TempDir()) require.NoError(t, err) require.Len(t, args, 4) assert.EqualValues(t, []string{"-noprofile", "-noninteractive", "-c"}, []string{args[0], args[1], args[2]}) @@ -69,7 +69,7 @@ Write-Host 'test' echo '+ echo test' echo test`, args[3]) - args, err = e.genCmdByShell("pwsh", []string{"Get-Process"}) + args, err = e.genCmdByShell("pwsh", []string{"Get-Process"}, t.TempDir()) require.NoError(t, err) assert.Len(t, args, 4) assert.Equal(t, "-noprofile", args[0]) @@ -77,7 +77,7 @@ echo test`, args[3]) }) t.Run("unix shells", func(t *testing.T) { - args, err := e.genCmdByShell("sh", []string{"echo hello", "pwd"}) + args, err := e.genCmdByShell("sh", []string{"echo hello", "pwd"}, t.TempDir()) require.NoError(t, err) assert.Len(t, args, 3) assert.Equal(t, "-e", args[0]) @@ -85,20 +85,20 @@ echo test`, args[3]) assert.Contains(t, args[2], "echo hello") assert.Contains(t, args[2], "pwd") - args, err = e.genCmdByShell("bash", []string{"ls -la"}) + args, err = e.genCmdByShell("bash", []string{"ls -la"}, t.TempDir()) require.NoError(t, err) assert.Len(t, args, 3) assert.Equal(t, "-e", args[0]) assert.Equal(t, "-c", args[1]) - args, err = e.genCmdByShell("zsh", []string{"echo test"}) + args, err = e.genCmdByShell("zsh", []string{"echo test"}, t.TempDir()) require.NoError(t, err) assert.Len(t, args, 3) assert.Equal(t, "-e", args[0]) }) t.Run("fish shell", func(t *testing.T) { - args, err := e.genCmdByShell("fish", []string{"echo test", "ls"}) + args, err := e.genCmdByShell("fish", []string{"echo test", "ls"}, t.TempDir()) require.NoError(t, err) assert.Len(t, args, 2) assert.Equal(t, "-c", args[0]) @@ -107,7 +107,7 @@ echo test`, args[3]) }) t.Run("nu shell", func(t *testing.T) { - args, err := e.genCmdByShell("nu", []string{"echo test"}) + args, err := e.genCmdByShell("nu", []string{"echo test"}, t.TempDir()) require.NoError(t, err) assert.Len(t, args, 2) assert.Equal(t, "--commands", args[0]) @@ -115,7 +115,7 @@ echo test`, args[3]) }) t.Run("command escaping", func(t *testing.T) { - args, err := e.genCmdByShell("cmd", []string{"echo 'test with | pipe'", "echo 'test & ampersand'\n\necho new line"}) + args, err := e.genCmdByShell("cmd", []string{"echo 'test with | pipe'", "echo 'test & ampersand'\n\necho new line"}, t.TempDir()) require.NoError(t, err) content, err := os.ReadFile(args[1]) require.NoError(t, err) @@ -132,7 +132,7 @@ echo new line }) t.Run("shell with .exe suffix", func(t *testing.T) { - args, err := e.genCmdByShell("bash.exe", []string{"echo test"}) + args, err := e.genCmdByShell("bash.exe", []string{"echo test"}, t.TempDir()) require.NoError(t, err) assert.Len(t, args, 3) assert.Equal(t, "-e", args[0]) diff --git a/pipeline/backend/local/local.go b/pipeline/backend/local/local.go index 9a8716e4b..f6c13a2ef 100644 --- a/pipeline/backend/local/local.go +++ b/pipeline/backend/local/local.go @@ -171,14 +171,27 @@ func (e *local) StartStep(ctx context.Context, step *types.Step, taskUUID string } } -func (e *local) WaitStep(_ context.Context, step *types.Step, taskUUID string) (*types.State, error) { +func (e *local) WaitStep(ctx context.Context, step *types.Step, taskUUID string) (*types.State, error) { log.Trace().Str("taskUUID", taskUUID).Msgf("wait for step %s", step.Name) + stepState := &types.State{ + Exited: true, + } + + if err := ctx.Err(); err != nil { + stepState.Error = err + return stepState, nil + } + state, err := e.getStepState(taskUUID, step.UUID) if err != nil { return nil, err } + if state.cmd == nil { + return nil, errors.New("exec: step command not set up") + } + // normally we use cmd.Wait() to wait for *exec.Cmd, but cmd.StdoutPipe() tells us not // as Wait() would close the io pipe even if not all logs where read and send back // so we have to do use the underlying functions @@ -190,13 +203,19 @@ func (e *local) WaitStep(_ context.Context, step *types.Step, taskUUID string) ( if err != nil { return nil, err } - state.cmd.ProcessState = cmdState + if cmdState == nil { + return nil, errors.New("exec: cmd state after Wait() can not be nil but is") + } + stepState.ExitCode = cmdState.ExitCode() + // can be nil if step got canceled + if state.cmd != nil { + state.cmd.ProcessState = cmdState + } + } else { + stepState.ExitCode = state.cmd.ProcessState.ExitCode() } - return &types.State{ - Exited: true, - ExitCode: state.cmd.ProcessState.ExitCode(), - }, err + return stepState, err } func (e *local) TailStep(_ context.Context, step *types.Step, taskUUID string) (io.ReadCloser, error) { @@ -212,18 +231,28 @@ func (e *local) TailStep(_ context.Context, step *types.Step, taskUUID string) ( func (e *local) DestroyStep(_ context.Context, step *types.Step, taskUUID string) error { state, err := e.getStepState(taskUUID, step.UUID) if err != nil { + if errors.Is(err, ErrStepStateNotFound) { + return nil + } return err } // As WaitStep can not use cmd.Wait() witch ensures the process already finished and // the io pipe is closed on process end, we make sure it is done. - _ = state.output.Close() - state.output = nil - _ = state.cmd.Cancel() - state.cmd = nil - workflowState, _ := e.getWorkflowState(taskUUID) - workflowState.stepState.Delete(step.UUID) + if state.output != nil { + _ = state.output.Close() + state.output = nil + } + if state.cmd != nil { + _ = state.cmd.Cancel() + state.cmd = nil + } + workflowState, err := e.getWorkflowState(taskUUID) + if err != nil { + return err + } + workflowState.stepState.Delete(step.UUID) return nil } @@ -237,11 +266,16 @@ func (e *local) DestroyWorkflow(_ context.Context, _ *types.Config, taskUUID str // clean up steps not cleaned up because of context cancel or detached function state.stepState.Range(func(_, value any) bool { - state, _ := value.(*stepState) - _ = state.output.Close() - state.output = nil - _ = state.cmd.Cancel() - state.cmd = nil + if state, ok := value.(*stepState); ok && state != nil { + if state.output != nil { + _ = state.output.Close() + state.output = nil + } + if state.cmd != nil { + _ = state.cmd.Cancel() + state.cmd = nil + } + } return true }) @@ -264,7 +298,7 @@ func (e *local) getWorkflowState(taskUUID string) (*workflowState, error) { } s, ok := state.(*workflowState) - if !ok { + if !ok || s == nil { return nil, fmt.Errorf("could not parse state: %v", state) } @@ -283,7 +317,7 @@ func (e *local) getStepState(taskUUID, stepUUID string) (*stepState, error) { } s, ok := state.(*stepState) - if !ok { + if !ok || s == nil { return nil, fmt.Errorf("could not parse state: %v", state) } diff --git a/pipeline/backend/types/backend.go b/pipeline/backend/types/backend.go index 229174c1d..0877c422a 100644 --- a/pipeline/backend/types/backend.go +++ b/pipeline/backend/types/backend.go @@ -142,6 +142,7 @@ type Backend interface { // - Clean up step-specific resources (containers, processes) // - Close any open log streams // - Not affect other steps in the same or other workflows + // - Must not fail if already invoked once // // Must be safe to call even if StartStep failed or the step was never started. // This function must be thread-safe for concurrent calls. diff --git a/pipeline/backend/types/state.go b/pipeline/backend/types/state.go index 3dc8b711b..9f4ff1b33 100644 --- a/pipeline/backend/types/state.go +++ b/pipeline/backend/types/state.go @@ -16,11 +16,14 @@ package types // State defines a container state. type State struct { + // Unix start time + Started int64 `json:"started"` // Container exit code ExitCode int `json:"exit_code"` // Container exited, true or false Exited bool `json:"exited"` // Container is oom killed, true or false + // TODO (6024): well known errors as string enum into ./errors.go OOMKilled bool `json:"oom_killed"` // Container error Error error diff --git a/pipeline/errors/error.go b/pipeline/errors/error.go deleted file mode 100644 index 4adf7fc62..000000000 --- a/pipeline/errors/error.go +++ /dev/null @@ -1,71 +0,0 @@ -package errors - -import ( - "errors" - - "go.uber.org/multierr" - - "go.woodpecker-ci.org/woodpecker/v3/pipeline/errors/types" -) - -type LinterErrorData struct { - File string `json:"file"` - Field string `json:"field"` -} - -type DeprecationErrorData struct { - File string `json:"file"` - Field string `json:"field"` - Docs string `json:"docs"` -} - -type BadHabitErrorData struct { - File string `json:"file"` - Field string `json:"field"` - Docs string `json:"docs"` -} - -func GetLinterData(e *types.PipelineError) *LinterErrorData { - if e.Type != types.PipelineErrorTypeLinter { - return nil - } - - if data, ok := e.Data.(*LinterErrorData); ok { - return data - } - - return nil -} - -func GetPipelineErrors(err error) []*types.PipelineError { - var pipelineErrors []*types.PipelineError - for _, _err := range multierr.Errors(err) { - var err *types.PipelineError - if errors.As(_err, &err) { - pipelineErrors = append(pipelineErrors, err) - } else { - pipelineErrors = append(pipelineErrors, &types.PipelineError{ - Message: _err.Error(), - Type: types.PipelineErrorTypeGeneric, - }) - } - } - - return pipelineErrors -} - -func HasBlockingErrors(err error) bool { - if err == nil { - return false - } - - errs := GetPipelineErrors(err) - - for _, err := range errs { - if !err.IsWarning { - return true - } - } - - return false -} diff --git a/pipeline/errors/linter.go b/pipeline/errors/linter.go new file mode 100644 index 000000000..9bd7d5d3b --- /dev/null +++ b/pipeline/errors/linter.go @@ -0,0 +1,83 @@ +// Copyright 2023 Woodpecker Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package errors + +import ( + "errors" + + "go.uber.org/multierr" +) + +type LinterErrorData struct { + File string `json:"file"` + Field string `json:"field"` +} + +type DeprecationErrorData struct { + File string `json:"file"` + Field string `json:"field"` + Docs string `json:"docs"` +} + +type BadHabitErrorData struct { + File string `json:"file"` + Field string `json:"field"` + Docs string `json:"docs"` +} + +func GetLinterData(e *PipelineError) *LinterErrorData { + if e.Type != PipelineErrorTypeLinter { + return nil + } + + if data, ok := e.Data.(*LinterErrorData); ok { + return data + } + + return nil +} + +func GetPipelineErrors(err error) []*PipelineError { + var pipelineErrors []*PipelineError + for _, _err := range multierr.Errors(err) { + var err *PipelineError + if errors.As(_err, &err) { + pipelineErrors = append(pipelineErrors, err) + } else { + pipelineErrors = append(pipelineErrors, &PipelineError{ + Message: _err.Error(), + Type: PipelineErrorTypeGeneric, + }) + } + } + + return pipelineErrors +} + +func HasBlockingErrors(err error) bool { + if err == nil { + return false + } + + errs := GetPipelineErrors(err) + + for _, err := range errs { + if !err.IsWarning { + return true + } + } + + return false +} diff --git a/pipeline/errors/error_test.go b/pipeline/errors/linter_test.go similarity index 60% rename from pipeline/errors/error_test.go rename to pipeline/errors/linter_test.go index a1658a797..df6a72bec 100644 --- a/pipeline/errors/error_test.go +++ b/pipeline/errors/linter_test.go @@ -1,3 +1,17 @@ +// Copyright 2023 Woodpecker Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package errors_test import ( @@ -8,7 +22,6 @@ import ( "go.uber.org/multierr" pipeline_errors "go.woodpecker-ci.org/woodpecker/v3/pipeline/errors" - "go.woodpecker-ci.org/woodpecker/v3/pipeline/errors/types" ) func TestGetPipelineErrors(t *testing.T) { @@ -17,7 +30,7 @@ func TestGetPipelineErrors(t *testing.T) { tests := []struct { title string err error - expected []*types.PipelineError + expected []*pipeline_errors.PipelineError }{ { title: "nil error", @@ -26,10 +39,10 @@ func TestGetPipelineErrors(t *testing.T) { }, { title: "warning", - err: &types.PipelineError{ + err: &pipeline_errors.PipelineError{ IsWarning: true, }, - expected: []*types.PipelineError{ + expected: []*pipeline_errors.PipelineError{ { IsWarning: true, }, @@ -37,10 +50,10 @@ func TestGetPipelineErrors(t *testing.T) { }, { title: "pipeline error", - err: &types.PipelineError{ + err: &pipeline_errors.PipelineError{ IsWarning: false, }, - expected: []*types.PipelineError{ + expected: []*pipeline_errors.PipelineError{ { IsWarning: false, }, @@ -49,14 +62,14 @@ func TestGetPipelineErrors(t *testing.T) { { title: "multiple warnings", err: multierr.Combine( - &types.PipelineError{ + &pipeline_errors.PipelineError{ IsWarning: true, }, - &types.PipelineError{ + &pipeline_errors.PipelineError{ IsWarning: true, }, ), - expected: []*types.PipelineError{ + expected: []*pipeline_errors.PipelineError{ { IsWarning: true, }, @@ -68,15 +81,15 @@ func TestGetPipelineErrors(t *testing.T) { { title: "multiple errors and warnings", err: multierr.Combine( - &types.PipelineError{ + &pipeline_errors.PipelineError{ IsWarning: true, }, - &types.PipelineError{ + &pipeline_errors.PipelineError{ IsWarning: false, }, errors.New("some error"), ), - expected: []*types.PipelineError{ + expected: []*pipeline_errors.PipelineError{ { IsWarning: true, }, @@ -84,7 +97,7 @@ func TestGetPipelineErrors(t *testing.T) { IsWarning: false, }, { - Type: types.PipelineErrorTypeGeneric, + Type: pipeline_errors.PipelineErrorTypeGeneric, IsWarning: false, Message: "some error", }, @@ -112,14 +125,14 @@ func TestHasBlockingErrors(t *testing.T) { }, { title: "warning", - err: &types.PipelineError{ + err: &pipeline_errors.PipelineError{ IsWarning: true, }, expected: false, }, { title: "pipeline error", - err: &types.PipelineError{ + err: &pipeline_errors.PipelineError{ IsWarning: false, }, expected: true, @@ -127,10 +140,10 @@ func TestHasBlockingErrors(t *testing.T) { { title: "multiple warnings", err: multierr.Combine( - &types.PipelineError{ + &pipeline_errors.PipelineError{ IsWarning: true, }, - &types.PipelineError{ + &pipeline_errors.PipelineError{ IsWarning: true, }, ), @@ -139,10 +152,10 @@ func TestHasBlockingErrors(t *testing.T) { { title: "multiple errors and warnings", err: multierr.Combine( - &types.PipelineError{ + &pipeline_errors.PipelineError{ IsWarning: true, }, - &types.PipelineError{ + &pipeline_errors.PipelineError{ IsWarning: false, }, errors.New("some error"), diff --git a/pipeline/errors/types/errors.go b/pipeline/errors/pipeline.go similarity index 66% rename from pipeline/errors/types/errors.go rename to pipeline/errors/pipeline.go index caa85c08e..ad8351e07 100644 --- a/pipeline/errors/types/errors.go +++ b/pipeline/errors/pipeline.go @@ -1,4 +1,18 @@ -package types +// Copyright 2024 Woodpecker Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package errors import ( "fmt" diff --git a/pipeline/error.go b/pipeline/errors/runtime.go similarity index 98% rename from pipeline/error.go rename to pipeline/errors/runtime.go index d2b39c335..774fc79cb 100644 --- a/pipeline/error.go +++ b/pipeline/errors/runtime.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package pipeline +package errors import ( "errors" diff --git a/pipeline/frontend/metadata/environment.go b/pipeline/frontend/metadata/environment.go index 49455af10..3b1331ce4 100644 --- a/pipeline/frontend/metadata/environment.go +++ b/pipeline/frontend/metadata/environment.go @@ -97,8 +97,8 @@ func (m *Metadata) Environ() map[string]string { setNonEmptyEnvVar(params, "CI_COMMIT_AUTHOR", commit.Author.Name) setNonEmptyEnvVar(params, "CI_COMMIT_AUTHOR_EMAIL", commit.Author.Email) setNonEmptyEnvVar(params, "CI_COMMIT_AUTHOR_AVATAR", commit.Author.Avatar) - if pipeline.Event == EventTag || pipeline.Event == EventRelease || pipeline.Event == EventDeploy || strings.HasPrefix(pipeline.Commit.Ref, "refs/tags/") { - setNonEmptyEnvVar(params, "CI_COMMIT_TAG", strings.TrimPrefix(pipeline.Commit.Ref, "refs/tags/")) + if p, f := strings.CutPrefix(pipeline.Commit.Ref, "refs/tags/"); f { + setNonEmptyEnvVar(params, "CI_COMMIT_TAG", p) } if pipeline.Event == EventRelease { setNonEmptyEnvVar(params, "CI_COMMIT_PRERELEASE", strconv.FormatBool(pipeline.Commit.IsPrerelease)) diff --git a/pipeline/frontend/metadata/environment_test.go b/pipeline/frontend/metadata/environment_test.go new file mode 100644 index 000000000..154aa76a5 --- /dev/null +++ b/pipeline/frontend/metadata/environment_test.go @@ -0,0 +1,74 @@ +// Copyright 2026 Woodpecker Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package metadata + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestEnviron(t *testing.T) { + m := Metadata{ + Sys: System{Name: "wp"}, + Curr: Pipeline{ + Event: EventRelease, + Commit: Commit{ + Ref: "refs/tags/v1.2.3", + IsPrerelease: true, + }, + }, + Prev: Pipeline{ + Event: EventPullMetadata, + Commit: Commit{ + Refspec: "branch-a:branch-b", + }, + }, + } + + envs := m.Environ() + assert.Equal(t, "wp", envs["CI"]) + assert.Equal(t, "release", envs["CI_PIPELINE_EVENT"]) + assert.Equal(t, "pull_request_metadata", envs["CI_PREV_PIPELINE_EVENT"]) + assert.Equal(t, "true", envs["CI_COMMIT_PRERELEASE"]) + assert.Equal(t, "branch-a", envs["CI_PREV_COMMIT_SOURCE_BRANCH"]) + assert.Equal(t, "branch-b", envs["CI_PREV_COMMIT_TARGET_BRANCH"]) + assert.Equal(t, "[]", envs["CI_PIPELINE_FILES"]) + assert.Equal(t, "v1.2.3", envs["CI_COMMIT_TAG"]) + + m = Metadata{ + Sys: System{Name: "wp"}, + Curr: Pipeline{ + Event: EventPull, + Commit: Commit{ + ChangedFiles: []string{"readme", "license"}, + Refspec: "branch-a:branch-b", + }, + }, + Prev: Pipeline{ + Event: EventPull, + Commit: Commit{ + Refspec: "branch-a:branch-b", + }, + }, + } + + envs = m.Environ() + + _, ok := envs["CI_COMMIT_TAG"] + assert.False(t, ok) + + assert.Equal(t, `["readme","license"]`, envs["CI_PIPELINE_FILES"]) +} diff --git a/pipeline/frontend/metadata/substitution_test.go b/pipeline/frontend/metadata/substitution_test.go index 34b2c5d8f..771cba470 100644 --- a/pipeline/frontend/metadata/substitution_test.go +++ b/pipeline/frontend/metadata/substitution_test.go @@ -21,27 +21,13 @@ import ( ) func TestEnvVarSubst(t *testing.T) { - testCases := []struct { - name string - yaml string - environ map[string]string - want string - }{{ - name: "simple substitution", - yaml: `steps: + result, err := EnvVarSubst(`steps: step1: - image: ${HELLO_IMAGE}`, - environ: map[string]string{"HELLO_IMAGE": "hello-world"}, - want: `steps: + image: ${HELLO_IMAGE} + command: echo ${NEWLINE}`, map[string]string{"HELLO_IMAGE": "hello-world", "NEWLINE": "some env\nwith newline"}) + assert.NoError(t, err) + assert.EqualValues(t, `steps: step1: - image: hello-world`, - }} - - for _, testCase := range testCases { - t.Run(testCase.name, func(t *testing.T) { - result, err := EnvVarSubst(testCase.yaml, testCase.environ) - assert.NoError(t, err) - assert.EqualValues(t, testCase.want, result) - }) - } + image: hello-world + command: echo "some env\nwith newline"`, result) } diff --git a/pipeline/frontend/yaml/linter/error.go b/pipeline/frontend/yaml/linter/error.go index 96c96ddc0..b267773c9 100644 --- a/pipeline/frontend/yaml/linter/error.go +++ b/pipeline/frontend/yaml/linter/error.go @@ -15,15 +15,14 @@ package linter import ( - "go.woodpecker-ci.org/woodpecker/v3/pipeline/errors" - errorTypes "go.woodpecker-ci.org/woodpecker/v3/pipeline/errors/types" + pipeline_errors "go.woodpecker-ci.org/woodpecker/v3/pipeline/errors" ) -func newLinterError(message, file, field string, isWarning bool) *errorTypes.PipelineError { - return &errorTypes.PipelineError{ - Type: errorTypes.PipelineErrorTypeLinter, +func newLinterError(message, file, field string, isWarning bool) *pipeline_errors.PipelineError { + return &pipeline_errors.PipelineError{ + Type: pipeline_errors.PipelineErrorTypeLinter, Message: message, - Data: &errors.LinterErrorData{File: file, Field: field}, + Data: &pipeline_errors.LinterErrorData{File: file, Field: field}, IsWarning: isWarning, } } diff --git a/pipeline/frontend/yaml/linter/linter.go b/pipeline/frontend/yaml/linter/linter.go index bb7970f48..0a560dfd3 100644 --- a/pipeline/frontend/yaml/linter/linter.go +++ b/pipeline/frontend/yaml/linter/linter.go @@ -20,8 +20,7 @@ import ( "codeberg.org/6543/xyaml" "go.uber.org/multierr" - "go.woodpecker-ci.org/woodpecker/v3/pipeline/errors" - errorTypes "go.woodpecker-ci.org/woodpecker/v3/pipeline/errors/types" + pipeline_errors "go.woodpecker-ci.org/woodpecker/v3/pipeline/errors" "go.woodpecker-ci.org/woodpecker/v3/pipeline/frontend/yaml/linter/schema" "go.woodpecker-ci.org/woodpecker/v3/pipeline/frontend/yaml/types" "go.woodpecker-ci.org/woodpecker/v3/pipeline/frontend/yaml/utils" @@ -235,20 +234,8 @@ func (l *Linter) lintSettings(config *WorkflowConfig, c *types.Container, field return nil } -func (l *Linter) lintContainerDeprecations(config *WorkflowConfig, c *types.Container, field string) (err error) { - if len(c.Secrets) != 0 { - err = multierr.Append(err, &errorTypes.PipelineError{ - Type: errorTypes.PipelineErrorTypeDeprecation, - Message: "Usage of `secrets` is deprecated, use `environment` in combination with `from_secret`", - Data: errors.DeprecationErrorData{ - File: config.File, - Field: fmt.Sprintf("%s.%s.secrets", field, c.Name), - Docs: "https://woodpecker-ci.org/docs/usage/secrets#use-secrets-in-settings-and-environment", - }, - }) - } - - return err +func (l *Linter) lintContainerDeprecations(config *WorkflowConfig, c *types.Container, field string) error { + return nil } func (l *Linter) lintTrusted(config *WorkflowConfig, c *types.Container, area string) error { @@ -357,10 +344,10 @@ func (l *Linter) lintBadHabits(config *WorkflowConfig) (err error) { } } if field != "" { - err = multierr.Append(err, &errorTypes.PipelineError{ - Type: errorTypes.PipelineErrorTypeBadHabit, + err = multierr.Append(err, &pipeline_errors.PipelineError{ + Type: pipeline_errors.PipelineErrorTypeBadHabit, Message: "Set an event filter for all steps or the entire workflow on all items of the `when` block", - Data: errors.BadHabitErrorData{ + Data: pipeline_errors.BadHabitErrorData{ File: config.File, Field: field, Docs: "https://woodpecker-ci.org/docs/usage/linter#event-filter-for-all-steps", diff --git a/pipeline/frontend/yaml/linter/linter_test.go b/pipeline/frontend/yaml/linter/linter_test.go index 836b44e0a..8223042bf 100644 --- a/pipeline/frontend/yaml/linter/linter_test.go +++ b/pipeline/frontend/yaml/linter/linter_test.go @@ -18,6 +18,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "go.woodpecker-ci.org/woodpecker/v3/pipeline/errors" "go.woodpecker-ci.org/woodpecker/v3/pipeline/frontend/yaml" @@ -177,14 +178,6 @@ func TestLintErrors(t *testing.T) { from: "{steps: { build: { image: golang, settings: { test: 'true' } } }, when: { branch: main, event: push }, clone: { git: { image: some-other/plugin-git:v1.1.0 } } }", want: "Specified clone image does not match allow list, netrc is not injected", }, - { - from: "steps: { build: { image: golang, secrets: [ { source: mysql_username, target: mysql_username } ] } }", - want: "Usage of `secrets` is deprecated, use `environment` in combination with `from_secret`", - }, - { - from: "steps: { build: { image: golang, secrets: [ 'mysql_username' ] } }", - want: "Usage of `secrets` is deprecated, use `environment` in combination with `from_secret`", - }, { from: "steps: { build: { image: golang }, publish: { image: golang, depends_on: [ binary ] } }", want: "One or more of the specified dependencies do not exist", @@ -193,7 +186,7 @@ func TestLintErrors(t *testing.T) { for _, test := range testdata { conf, err := yaml.ParseString(test.from) - assert.NoError(t, err) + require.NoError(t, err) lerr := linter.New().Lint([]*linter.WorkflowConfig{{ File: test.from, diff --git a/pipeline/frontend/yaml/linter/schema/.woodpecker/test-service.yaml b/pipeline/frontend/yaml/linter/schema/.woodpecker/test-service.yaml index 16429df75..bc4c350a7 100644 --- a/pipeline/frontend/yaml/linter/schema/.woodpecker/test-service.yaml +++ b/pipeline/frontend/yaml/linter/schema/.woodpecker/test-service.yaml @@ -8,6 +8,15 @@ steps: services: database: image: mysql + ports: + - 3306 + environment: + MYSQL_DATABASE: test + MYSQL_ALLOW_EMPTY_PASSWORD: 'yes' + cache: image: redis + failure: ignore directory: /tmp/ + ports: + - '6379' diff --git a/pipeline/frontend/yaml/linter/schema/schema.json b/pipeline/frontend/yaml/linter/schema/schema.json index 51e1bed7c..5b20b1ee0 100644 --- a/pipeline/frontend/yaml/linter/schema/schema.json +++ b/pipeline/frontend/yaml/linter/schema/schema.json @@ -879,6 +879,12 @@ "volumes": { "$ref": "#/definitions/step_volumes" }, + "failure": { + "description": "How to handle the failure of this step. Read more: https://woodpecker-ci.org/docs/usage/services#stopping", + "type": "string", + "enum": ["fail", "ignore"], + "default": "fail" + }, "backend_options": { "$ref": "#/definitions/step_backend_options" }, diff --git a/pipeline/frontend/yaml/matrix/matrix.go b/pipeline/frontend/yaml/matrix/matrix.go index a48ad31d8..7616f07fb 100644 --- a/pipeline/frontend/yaml/matrix/matrix.go +++ b/pipeline/frontend/yaml/matrix/matrix.go @@ -19,7 +19,7 @@ import ( "codeberg.org/6543/xyaml" - errorTypes "go.woodpecker-ci.org/woodpecker/v3/pipeline/errors/types" + pipeline_errors "go.woodpecker-ci.org/woodpecker/v3/pipeline/errors" ) const ( @@ -116,7 +116,7 @@ func parse(raw []byte) (Matrix, error) { Matrix map[string][]string }{} if err := xyaml.Unmarshal(raw, &data); err != nil { - return nil, &errorTypes.PipelineError{Message: err.Error(), Type: errorTypes.PipelineErrorTypeCompiler} + return nil, &pipeline_errors.PipelineError{Message: err.Error(), Type: pipeline_errors.PipelineErrorTypeCompiler} } return data.Matrix, nil } @@ -129,7 +129,7 @@ func parseList(raw []byte) ([]Axis, error) { }{} if err := xyaml.Unmarshal(raw, &data); err != nil { - return nil, &errorTypes.PipelineError{Message: err.Error(), Type: errorTypes.PipelineErrorTypeCompiler} + return nil, &pipeline_errors.PipelineError{Message: err.Error(), Type: pipeline_errors.PipelineErrorTypeCompiler} } return data.Matrix.Include, nil } diff --git a/pipeline/frontend/yaml/parse_test.go b/pipeline/frontend/yaml/parse_test.go index d8aa1bd80..962d99bcb 100644 --- a/pipeline/frontend/yaml/parse_test.go +++ b/pipeline/frontend/yaml/parse_test.go @@ -53,6 +53,11 @@ func TestParse(t *testing.T) { assert.False(t, out.SkipClone) }) + t.Run("Should fail on invalid yaml", func(t *testing.T) { + _, err := ParseString("notvalid") + assert.Error(t, err) + }) + t.Run("Should handle simple yaml anchors", func(t *testing.T) { out, err := ParseString(simpleYamlAnchors) assert.NoError(t, err) @@ -150,14 +155,10 @@ pipeline: ` workflow1, err := ParseString(sampleYamlPipeline) - if !assert.NoError(t, err) { - return - } + require.NoError(t, err) workflow2, err := ParseString(sampleYamlPipelineLegacyIgnore) - if !assert.NoError(t, err) { - return - } + require.NoError(t, err) assert.EqualValues(t, workflow1, workflow2) assert.Len(t, workflow1.Steps.ContainerList, 1) @@ -183,7 +184,6 @@ steps: - go test build: image: golang - network_mode: container:name commands: - go build when: @@ -191,7 +191,8 @@ steps: depends_on: [] notify: image: slack - channel: dev + settings: + channel: dev when: event: failure services: @@ -248,14 +249,10 @@ steps: func TestReSerialize(t *testing.T) { work1, err := ParseString(sampleVarYaml) - if !assert.NoError(t, err) { - t.Fail() - } + require.NoError(t, err) - workBin, err := yaml.Marshal(work1) - if !assert.NoError(t, err) { - t.Fail() - } + work1Bin, err := yaml.Marshal(work1) + require.NoError(t, err) assert.EqualValues(t, `steps: - name: notify_fail @@ -282,7 +279,54 @@ func TestReSerialize(t *testing.T) { DRIVER: next PLATFORM: linux skip_clone: false -`, string(workBin)) +`, string(work1Bin)) + + work2, err := ParseString(sampleYaml) + require.NoError(t, err) + + workBin2, err := yaml.Marshal(work2) + require.NoError(t, err) + + // TODO: fix "steps.[1].depends_on: []" to be re-serialized! + assert.EqualValues(t, `when: + - event: + - tester + - tester2 + - branch: tester +workspace: + base: /go + path: src/github.com/octocat/hello-world +steps: + - name: test + image: golang + commands: + - go install + - go test + - name: build + image: golang + commands: go build + when: + event: push + - name: notify + image: slack + settings: + channel: dev + when: + event: failure +services: + - name: database + image: mysql +labels: + com.example.team: frontend + com.example.type: build +depends_on: + - lint + - test +runs_on: + - success + - failure +skip_clone: false +`, string(workBin2)) } func TestSlice(t *testing.T) { diff --git a/pipeline/frontend/yaml/types/base/slice_test.go b/pipeline/frontend/yaml/types/base/slice_test.go index d00f1a1d0..c22d8cc50 100644 --- a/pipeline/frontend/yaml/types/base/slice_test.go +++ b/pipeline/frontend/yaml/types/base/slice_test.go @@ -36,7 +36,7 @@ func TestStringOrSliceYaml(t *testing.T) { assert.Equal(t, StringOrSlice{"bar", "baz"}, s.Foo) d, err := yaml.Marshal(&s) - assert.Nil(t, err) + assert.NoError(t, err) s2 := StructStringOrSlice{} assert.NoError(t, yaml.Unmarshal(d, &s2)) diff --git a/pipeline/frontend/yaml/types/container.go b/pipeline/frontend/yaml/types/container.go index 1fc333d27..d77f6abf4 100644 --- a/pipeline/frontend/yaml/types/container.go +++ b/pipeline/frontend/yaml/types/container.go @@ -15,120 +15,52 @@ package types import ( - "fmt" - - "gopkg.in/yaml.v3" - "go.woodpecker-ci.org/woodpecker/v3/pipeline/frontend/yaml/constraint" "go.woodpecker-ci.org/woodpecker/v3/pipeline/frontend/yaml/types/base" "go.woodpecker-ci.org/woodpecker/v3/pipeline/frontend/yaml/utils" ) -type ( - // ContainerList denotes an ordered collection of containers. - ContainerList struct { - ContainerList []*Container - } +// Container defines a container. +type Container struct { + // common + Name string `yaml:"name,omitempty"` + Image string `yaml:"image,omitempty"` + Pull bool `yaml:"pull,omitempty"` + Commands base.StringOrSlice `yaml:"commands,omitempty"` + Entrypoint base.StringOrSlice `yaml:"entrypoint,omitempty"` + Directory string `yaml:"directory,omitempty"` + Settings map[string]any `yaml:"settings,omitempty"` + Environment map[string]any `yaml:"environment,omitempty"` + // flow control + DependsOn base.StringOrSlice `yaml:"depends_on,omitempty"` + When constraint.When `yaml:"when,omitempty"` + Failure string `yaml:"failure,omitempty"` + Detached bool `yaml:"detach,omitempty"` + // state + Volumes Volumes `yaml:"volumes,omitempty"` + // network + Ports []string `yaml:"ports,omitempty"` + DNS base.StringOrSlice `yaml:"dns,omitempty"` + DNSSearch base.StringOrSlice `yaml:"dns_search,omitempty"` + // backend specific + BackendOptions map[string]any `yaml:"backend_options,omitempty"` - // Container defines a container. - Container struct { - // common - Name string `yaml:"name,omitempty"` - Image string `yaml:"image,omitempty"` - Pull bool `yaml:"pull,omitempty"` - Commands base.StringOrSlice `yaml:"commands,omitempty"` - Entrypoint base.StringOrSlice `yaml:"entrypoint,omitempty"` - Directory string `yaml:"directory,omitempty"` - Settings map[string]any `yaml:"settings,omitempty"` - Environment map[string]any `yaml:"environment,omitempty"` - // flow control - DependsOn base.StringOrSlice `yaml:"depends_on,omitempty"` - When constraint.When `yaml:"when,omitempty"` - Failure string `yaml:"failure,omitempty"` - Detached bool `yaml:"detach,omitempty"` - // state - Volumes Volumes `yaml:"volumes,omitempty"` - // network - Ports []string `yaml:"ports,omitempty"` - DNS base.StringOrSlice `yaml:"dns,omitempty"` - DNSSearch base.StringOrSlice `yaml:"dns_search,omitempty"` - // backend specific - BackendOptions map[string]any `yaml:"backend_options,omitempty"` + // ACTIVE DEVELOPMENT BELOW - // ACTIVE DEVELOPMENT BELOW + // Docker and Kubernetes Specific + Privileged bool `yaml:"privileged,omitempty"` - // Remove after v3.1.0 - Secrets []any `yaml:"secrets,omitempty"` - - // Docker and Kubernetes Specific - Privileged bool `yaml:"privileged,omitempty"` - - // Undocumented - Devices []string `yaml:"devices,omitempty"` - ExtraHosts []string `yaml:"extra_hosts,omitempty"` - NetworkMode string `yaml:"network_mode,omitempty"` - Tmpfs []string `yaml:"tmpfs,omitempty"` - } -) - -// UnmarshalYAML implements the Unmarshaler interface. -func (c *ContainerList) UnmarshalYAML(value *yaml.Node) error { - switch value.Kind { - // We support maps ... - case yaml.MappingNode: - c.ContainerList = make([]*Container, 0, len(value.Content)/2+1) - // We cannot use decode on specific values - // since if we try to load from a map, the order - // will not be kept. Therefor use value.Content - // and take the map values i%2=1 - for i, n := range value.Content { - if i%2 == 1 { - container := &Container{} - if err := n.Decode(container); err != nil { - return err - } - - if container.Name == "" { - container.Name = fmt.Sprintf("%v", value.Content[i-1].Value) - } - - c.ContainerList = append(c.ContainerList, container) - } - } - - // ... and lists - case yaml.SequenceNode: - c.ContainerList = make([]*Container, 0, len(value.Content)) - for i, n := range value.Content { - container := &Container{} - if err := n.Decode(container); err != nil { - return err - } - - if container.Name == "" { - container.Name = fmt.Sprintf("step-%d", i) - } - - c.ContainerList = append(c.ContainerList, container) - } - - default: - return fmt.Errorf("yaml node type[%d]: '%s' not supported", value.Kind, value.Tag) - } - - return nil -} - -// MarshalYAML implements custom Yaml marshaling. -func (c ContainerList) MarshalYAML() (any, error) { - return c.ContainerList, nil + // Undocumented + Devices []string `yaml:"devices,omitempty"` + ExtraHosts []string `yaml:"extra_hosts,omitempty"` + NetworkMode string `yaml:"network_mode,omitempty"` + Tmpfs []string `yaml:"tmpfs,omitempty"` } func (c *Container) IsPlugin() bool { return len(c.Commands) == 0 && len(c.Entrypoint) == 0 && - len(c.Environment) == 0 && - len(c.Secrets) == 0 + len(c.Environment) == 0 } func (c *Container) IsTrustedCloneImage(trustedClonePlugins []string) bool { diff --git a/pipeline/frontend/yaml/types/container_list.go b/pipeline/frontend/yaml/types/container_list.go new file mode 100644 index 000000000..49e7b284b --- /dev/null +++ b/pipeline/frontend/yaml/types/container_list.go @@ -0,0 +1,79 @@ +// Copyright 2026 Woodpecker Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package types + +import ( + "fmt" + + "gopkg.in/yaml.v3" +) + +// ContainerList contains ordered collection of containers. +type ContainerList struct { + ContainerList []*Container +} + +// UnmarshalYAML implements the Unmarshaler interface. +func (c *ContainerList) UnmarshalYAML(value *yaml.Node) error { + switch value.Kind { + // We support maps ... + case yaml.MappingNode: + c.ContainerList = make([]*Container, 0, len(value.Content)/2+1) + // We cannot use decode on specific values + // since if we try to load from a map, the order + // will not be kept. Therefor use value.Content + // and take the map values i%2=1 + for i, n := range value.Content { + if i%2 == 1 { + container := &Container{} + if err := n.Decode(container); err != nil { + return err + } + + if container.Name == "" { + container.Name = fmt.Sprintf("%v", value.Content[i-1].Value) + } + + c.ContainerList = append(c.ContainerList, container) + } + } + + // ... and lists + case yaml.SequenceNode: + c.ContainerList = make([]*Container, 0, len(value.Content)) + for i, n := range value.Content { + container := &Container{} + if err := n.Decode(container); err != nil { + return err + } + + if container.Name == "" { + container.Name = fmt.Sprintf("step-%d", i) + } + + c.ContainerList = append(c.ContainerList, container) + } + + default: + return fmt.Errorf("yaml node type[%d]: '%s' not supported", value.Kind, value.Tag) + } + + return nil +} + +// MarshalYAML implements custom Yaml marshaling. +func (c ContainerList) MarshalYAML() (any, error) { + return c.ContainerList, nil +} diff --git a/pipeline/logger.go b/pipeline/logging/logger.go similarity index 97% rename from pipeline/logger.go rename to pipeline/logging/logger.go index 765a0333b..e7e55f24e 100644 --- a/pipeline/logger.go +++ b/pipeline/logging/logger.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package pipeline +package logging import ( "io" diff --git a/pipeline/pipeline.go b/pipeline/runtime/executor.go similarity index 60% rename from pipeline/pipeline.go rename to pipeline/runtime/executor.go index 622917be2..edf1b0d19 100644 --- a/pipeline/pipeline.go +++ b/pipeline/runtime/executor.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package pipeline +package runtime import ( "context" @@ -21,74 +21,14 @@ import ( "sync" "time" - "github.com/oklog/ulid/v2" - "github.com/rs/zerolog" - "github.com/rs/zerolog/log" "golang.org/x/sync/errgroup" backend "go.woodpecker-ci.org/woodpecker/v3/pipeline/backend/types" - pipelineErrors "go.woodpecker-ci.org/woodpecker/v3/pipeline/errors/types" + pipeline_errors "go.woodpecker-ci.org/woodpecker/v3/pipeline/errors" "go.woodpecker-ci.org/woodpecker/v3/pipeline/frontend/metadata" + "go.woodpecker-ci.org/woodpecker/v3/pipeline/state" ) -// TODO: move runtime into "runtime" subpackage - -type ( - // State defines the pipeline and process state. - State struct { - // Global state of the pipeline. - Pipeline struct { - // Pipeline time started - Started int64 `json:"time"` - // Current pipeline step - Step *backend.Step `json:"step"` - // Current pipeline error state - Error error `json:"error"` - } - - // Current process state. - Process *backend.State - } -) - -// Runtime is a configuration runtime. -type Runtime struct { - err error - spec *backend.Config - engine backend.Backend - started int64 - - ctx context.Context - tracer Tracer - logger Logger - - taskUUID string - - Description map[string]string // The runtime descriptors. -} - -// New returns a new runtime using the specified runtime -// configuration and runtime engine. -func New(spec *backend.Config, opts ...Option) *Runtime { - r := new(Runtime) - r.Description = map[string]string{} - r.spec = spec - r.ctx = context.Background() - r.taskUUID = ulid.Make().String() - for _, opts := range opts { - opts(r) - } - return r -} - -func (r *Runtime) MakeLogger() zerolog.Logger { - logCtx := log.With() - for key, val := range r.Description { - logCtx = logCtx.Str(key, val) - } - return logCtx.Logger() -} - // Run starts the execution of a workflow and waits for it to complete. func (r *Runtime) Run(runnerCtx context.Context) error { logger := r.MakeLogger() @@ -117,12 +57,12 @@ func (r *Runtime) Run(runnerCtx context.Context) error { r.started = time.Now().Unix() if err := r.engine.SetupWorkflow(runnerCtx, r.spec, r.taskUUID); err != nil { - var stepErr *pipelineErrors.ErrInvalidWorkflowSetup + var stepErr *pipeline_errors.ErrInvalidWorkflowSetup if errors.As(err, &stepErr) { - state := new(State) + state := new(state.State) state.Pipeline.Step = stepErr.Step state.Pipeline.Error = stepErr.Err - state.Process = &backend.State{ + state.Process = backend.State{ Error: stepErr.Err, Exited: true, ExitCode: 1, @@ -142,8 +82,8 @@ func (r *Runtime) Run(runnerCtx context.Context) error { for _, stage := range r.spec.Stages { select { case <-r.ctx.Done(): - return ErrCancel - case err := <-r.execAll(stage.Steps): + return pipeline_errors.ErrCancel + case err := <-r.execAll(runnerCtx, stage.Steps): if err != nil { r.err = err } @@ -154,28 +94,30 @@ func (r *Runtime) Run(runnerCtx context.Context) error { } // Updates the current status of a step. +// If processState is nil, we assume the step did not start. +// If step did not started and err exists, it's a step start issue and step is done. func (r *Runtime) traceStep(processState *backend.State, err error, step *backend.Step) error { if r.tracer == nil { // no tracer nothing to trace :) return nil } - if processState == nil { - processState = new(backend.State) - if err != nil { - processState.Error = err - processState.Exited = true - processState.OOMKilled = false - processState.ExitCode = 126 // command invoked cannot be executed. - } - } - - state := new(State) + state := new(state.State) state.Pipeline.Started = r.started state.Pipeline.Step = step - state.Process = processState // empty state.Pipeline.Error = r.err + // We have an error while starting the step + if processState == nil && err != nil { + state.Process = backend.State{ + Error: err, + Exited: true, + OOMKilled: false, + } + } else if processState != nil { + state.Process = *processState + } + if traceErr := r.tracer.Trace(state); traceErr != nil { return traceErr } @@ -183,7 +125,7 @@ func (r *Runtime) traceStep(processState *backend.State, err error, step *backen } // Executes a set of parallel steps. -func (r *Runtime) execAll(steps []*backend.Step) <-chan error { +func (r *Runtime) execAll(runnerCtx context.Context, steps []*backend.Step) <-chan error { var g errgroup.Group done := make(chan error) logger := r.MakeLogger() @@ -226,18 +168,43 @@ func (r *Runtime) execAll(steps []*backend.Step) <-chan error { Str("step", step.Name). Msg("executing") - processState, err := r.exec(step) + // setup exec func in a way it can be detached if needed + // wg will signal once + execAndTrace := func(wg *sync.WaitGroup) error { + processState, err := r.exec(runnerCtx, step, wg) - logger.Debug(). - Str("step", step.Name). - Msg("complete") + logger.Debug(). + Str("step", step.Name). + Msg("complete") - // Return the error after tracing it. - err = r.traceStep(processState, err, step) - if err != nil && step.Failure == metadata.FailureIgnore { - return nil + // normalize context cancel error + if errors.Is(err, context.Canceled) { + err = pipeline_errors.ErrCancel + } + + // Return the error after tracing it. + err = r.traceStep(processState, err, step) + if err != nil && step.Failure == metadata.FailureIgnore { + return nil + } + return err } - return err + + // Report all errors until the setup happened. + // Afterwards errors will be dropped. + if step.Detached { + var wg sync.WaitGroup + wg.Add(1) + var setupErr error + go func() { + setupErr = execAndTrace(&wg) + }() + wg.Wait() + return setupErr + } + + // run blocking + return execAndTrace(nil) }) } @@ -245,18 +212,27 @@ func (r *Runtime) execAll(steps []*backend.Step) <-chan error { done <- g.Wait() close(done) }() + return done } // Executes the step and returns the state and error. -func (r *Runtime) exec(step *backend.Step) (*backend.State, error) { - if err := r.engine.StartStep(r.ctx, step, r.taskUUID); err != nil { +func (r *Runtime) exec(runnerCtx context.Context, step *backend.Step, setupWg *sync.WaitGroup) (*backend.State, error) { + defer func() { + if setupWg != nil { + setupWg.Done() + } + }() + + if err := r.engine.StartStep(r.ctx, step, r.taskUUID); err != nil { //nolint:contextcheck return nil, err } + startTime := time.Now().Unix() + logger := r.MakeLogger() var wg sync.WaitGroup if r.logger != nil { - rc, err := r.engine.TailStep(r.ctx, step, r.taskUUID) + rc, err := r.engine.TailStep(r.ctx, step, r.taskUUID) //nolint:contextcheck if err != nil { return nil, err } @@ -264,7 +240,6 @@ func (r *Runtime) exec(step *backend.Step) (*backend.State, error) { wg.Add(1) go func() { defer wg.Done() - logger := r.MakeLogger() if err := r.logger(step, rc); err != nil { logger.Error().Err(err).Msg("process logging failed") @@ -273,33 +248,46 @@ func (r *Runtime) exec(step *backend.Step) (*backend.State, error) { }() } - // nothing else to do, this is a detached process. - if step.Detached { - return nil, nil + // nothing else to block for detached process. + if setupWg != nil { + setupWg.Done() + // set to nil so the setupWg.Done in defer does not call it a second time + setupWg = nil } // We wait until all data was logged. (Needed for some backends like local as WaitStep kills the log stream) wg.Wait() - waitState, err := r.engine.WaitStep(r.ctx, step, r.taskUUID) + waitState, err := r.engine.WaitStep(r.ctx, step, r.taskUUID) //nolint:contextcheck if err != nil { if errors.Is(err, context.Canceled) { - return waitState, ErrCancel + waitState.Error = pipeline_errors.ErrCancel + } else { + return nil, err } + } + + // It is important to use the runnerCtx here because + // in case the workflow was canceled we still have the docker daemon to stop the container. + if err := r.engine.DestroyStep(runnerCtx, step, r.taskUUID); err != nil { return nil, err } - if err := r.engine.DestroyStep(r.ctx, step, r.taskUUID); err != nil { - return nil, err + // we update with our start time here + waitState.Started = startTime + + // we handle cancel case + if ctxErr := r.ctx.Err(); ctxErr != nil && errors.Is(ctxErr, context.Canceled) { + waitState.Error = pipeline_errors.ErrCancel } if waitState.OOMKilled { - return waitState, &OomError{ + return waitState, &pipeline_errors.OomError{ UUID: step.UUID, Code: waitState.ExitCode, } } else if waitState.ExitCode != 0 { - return waitState, &ExitError{ + return waitState, &pipeline_errors.ExitError{ UUID: step.UUID, Code: waitState.ExitCode, } diff --git a/pipeline/option.go b/pipeline/runtime/option.go similarity index 87% rename from pipeline/option.go rename to pipeline/runtime/option.go index 784cfdbbd..f87d4a108 100644 --- a/pipeline/option.go +++ b/pipeline/runtime/option.go @@ -12,12 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -package pipeline +package runtime import ( "context" backend "go.woodpecker-ci.org/woodpecker/v3/pipeline/backend/types" + "go.woodpecker-ci.org/woodpecker/v3/pipeline/logging" + "go.woodpecker-ci.org/woodpecker/v3/pipeline/tracing" ) // Option configures a runtime option. @@ -31,14 +33,14 @@ func WithBackend(backend backend.Backend) Option { } // WithLogger returns an option configured with a runtime logger. -func WithLogger(logger Logger) Option { +func WithLogger(logger logging.Logger) Option { return func(r *Runtime) { r.logger = logger } } // WithTracer returns an option configured with a runtime tracer. -func WithTracer(tracer Tracer) Option { +func WithTracer(tracer tracing.Tracer) Option { return func(r *Runtime) { r.tracer = tracer } diff --git a/pipeline/runtime/runtime.go b/pipeline/runtime/runtime.go new file mode 100644 index 000000000..5fb197b4a --- /dev/null +++ b/pipeline/runtime/runtime.go @@ -0,0 +1,70 @@ +// Copyright 2023 Woodpecker Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package runtime + +import ( + "context" + + "github.com/oklog/ulid/v2" + "github.com/rs/zerolog" + "github.com/rs/zerolog/log" + + backend "go.woodpecker-ci.org/woodpecker/v3/pipeline/backend/types" + "go.woodpecker-ci.org/woodpecker/v3/pipeline/logging" + "go.woodpecker-ci.org/woodpecker/v3/pipeline/tracing" +) + +// Runtime represents a workflow state executed by a specific backend. +// Each workflow gets its own state configuration at runtime. +type Runtime struct { + err error + spec *backend.Config + engine backend.Backend + started int64 + + // The context a workflow is being executed with. + // All normal (non cleanup) operations must use this. + // Cleanup operations should use the runnerCtx passed to Run() + ctx context.Context + + tracer tracing.Tracer + logger logging.Logger + + taskUUID string + + Description map[string]string // The runtime descriptors. +} + +// New returns a new runtime using the specified runtime +// configuration and runtime engine. +func New(spec *backend.Config, opts ...Option) *Runtime { + r := new(Runtime) + r.Description = map[string]string{} + r.spec = spec + r.ctx = context.Background() + r.taskUUID = ulid.Make().String() + for _, opts := range opts { + opts(r) + } + return r +} + +func (r *Runtime) MakeLogger() zerolog.Logger { + logCtx := log.With() + for key, val := range r.Description { + logCtx = logCtx.Str(key, val) + } + return logCtx.Logger() +} diff --git a/pipeline/shutdown.go b/pipeline/runtime/shutdown.go similarity index 63% rename from pipeline/shutdown.go rename to pipeline/runtime/shutdown.go index b9fd98384..d53cf1c0d 100644 --- a/pipeline/shutdown.go +++ b/pipeline/runtime/shutdown.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package pipeline +package runtime import ( "context" @@ -23,26 +23,15 @@ import ( const shutdownTimeout = time.Second * 5 var ( - shutdownCtx context.Context - shutdownCtxCancel context.CancelFunc - shutdownCtxLock sync.Mutex + shutdownCtx context.Context + shutdownCtxLock sync.Mutex ) func GetShutdownCtx() context.Context { shutdownCtxLock.Lock() defer shutdownCtxLock.Unlock() if shutdownCtx == nil { - shutdownCtx, shutdownCtxCancel = context.WithTimeout(context.Background(), shutdownTimeout) + shutdownCtx, _ = context.WithTimeout(context.Background(), shutdownTimeout) //nolint:govet } return shutdownCtx } - -func CancelShutdown() { - shutdownCtxLock.Lock() - defer shutdownCtxLock.Unlock() - if shutdownCtxCancel == nil { - // we create an canceled context - shutdownCtx, shutdownCtxCancel = context.WithCancel(context.Background()) //nolint:forbidigo - } - shutdownCtxCancel() -} diff --git a/pipeline/error_test.go b/pipeline/state/state.go similarity index 57% rename from pipeline/error_test.go rename to pipeline/state/state.go index 95a264f2e..6a496700e 100644 --- a/pipeline/error_test.go +++ b/pipeline/state/state.go @@ -12,25 +12,26 @@ // See the License for the specific language governing permissions and // limitations under the License. -package pipeline +package state import ( - "testing" - - "github.com/stretchr/testify/assert" + backend "go.woodpecker-ci.org/woodpecker/v3/pipeline/backend/types" ) -func TestExitError(t *testing.T) { - err := ExitError{ - UUID: "14534321", - Code: 255, - } - assert.Equal(t, "uuid=14534321: exit code 255", err.Error()) -} +type ( + // State defines the pipeline and process state. + State struct { + // Global state of the pipeline. + Pipeline struct { + // Pipeline time started + Started int64 `json:"time"` + // Current pipeline step + Step *backend.Step `json:"step"` + // Current pipeline error state + Error error `json:"error"` + } -func TestOomError(t *testing.T) { - err := OomError{ - UUID: "14534321", + // Current process state. + Process backend.State } - assert.Equal(t, "uuid=14534321: received oom kill", err.Error()) -} +) diff --git a/pipeline/tracer.go b/pipeline/tracing/tracer.go similarity index 83% rename from pipeline/tracer.go rename to pipeline/tracing/tracer.go index f48a7c562..77b9f3a7d 100644 --- a/pipeline/tracer.go +++ b/pipeline/tracing/tracer.go @@ -12,30 +12,32 @@ // See the License for the specific language governing permissions and // limitations under the License. -package pipeline +package tracing import ( "strconv" + + "go.woodpecker-ci.org/woodpecker/v3/pipeline/state" ) // Tracer handles process tracing. type Tracer interface { - Trace(*State) error + Trace(*state.State) error } // TraceFunc type is an adapter to allow the use of ordinary // functions as a Tracer. -type TraceFunc func(*State) error +type TraceFunc func(*state.State) error // Trace calls f(state). -func (f TraceFunc) Trace(state *State) error { +func (f TraceFunc) Trace(state *state.State) error { return f(state) } // DefaultTracer provides a tracer that updates the CI_ environment // variables to include the correct timestamp and status. // TODO: find either a new home or better name for this. -var DefaultTracer = TraceFunc(func(state *State) error { +var DefaultTracer = TraceFunc(func(state *state.State) error { if state.Process.Exited { return nil } diff --git a/pipeline/log/utils.go b/pipeline/utils/copy_line_by_line.go similarity index 99% rename from pipeline/log/utils.go rename to pipeline/utils/copy_line_by_line.go index 84a29e946..09cbf9ce6 100644 --- a/pipeline/log/utils.go +++ b/pipeline/utils/copy_line_by_line.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package log +package utils import ( "bufio" diff --git a/pipeline/log/utils_test.go b/pipeline/utils/copy_line_by_line_test.go similarity index 96% rename from pipeline/log/utils_test.go rename to pipeline/utils/copy_line_by_line_test.go index 8b83b67ea..bc63ae984 100644 --- a/pipeline/log/utils_test.go +++ b/pipeline/utils/copy_line_by_line_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package log_test +package utils_test import ( "io" @@ -23,7 +23,7 @@ import ( "github.com/stretchr/testify/assert" - "go.woodpecker-ci.org/woodpecker/v3/pipeline/log" + "go.woodpecker-ci.org/woodpecker/v3/pipeline/utils" ) type testWriter struct { @@ -61,7 +61,7 @@ func TestCopyLineByLine(t *testing.T) { done := make(chan struct{}) go func() { - err := log.CopyLineByLine(testWriter, r, 1024) + err := utils.CopyLineByLine(testWriter, r, 1024) assert.NoError(t, err) close(done) }() @@ -118,7 +118,7 @@ func TestCopyLineByLineSizeLimit(t *testing.T) { go func() { defer wg.Done() - err := log.CopyLineByLine(testWriter, r, 4) + err := utils.CopyLineByLine(testWriter, r, 4) assert.NoError(t, err) }() @@ -161,7 +161,7 @@ func TestStringReader(t *testing.T) { writes: make([]string, 0), } - err := log.CopyLineByLine(testWriter, r, 1024) + err := utils.CopyLineByLine(testWriter, r, 1024) assert.NoError(t, err) writes := testWriter.GetWrites() @@ -179,7 +179,7 @@ func TestCopyLineByLineNewlineCharacter(t *testing.T) { done := make(chan struct{}) go func() { - err := log.CopyLineByLine(testWriter, r, 4) + err := utils.CopyLineByLine(testWriter, r, 4) assert.NoError(t, err) close(done) }() @@ -243,7 +243,7 @@ func TestCopyLineByLineLongLine(t *testing.T) { maxSize := 10 go func() { - err := log.CopyLineByLine(testWriter, r, maxSize) + err := utils.CopyLineByLine(testWriter, r, maxSize) assert.NoError(t, err) close(done) }() @@ -296,7 +296,7 @@ func TestCopyLineByLineWriteChunks(t *testing.T) { maxSize := 8 go func() { - err := log.CopyLineByLine(testWriter, r, maxSize) + err := utils.CopyLineByLine(testWriter, r, maxSize) assert.NoError(t, err) close(done) }() diff --git a/pipeline/rpc/log_entry.go b/rpc/log_entry.go similarity index 100% rename from pipeline/rpc/log_entry.go rename to rpc/log_entry.go diff --git a/pipeline/rpc/log_entry_test.go b/rpc/log_entry_test.go similarity index 100% rename from pipeline/rpc/log_entry_test.go rename to rpc/log_entry_test.go diff --git a/pipeline/rpc/mocks/mock_Peer.go b/rpc/mocks/mock_Peer.go similarity index 96% rename from pipeline/rpc/mocks/mock_Peer.go rename to rpc/mocks/mock_Peer.go index 1205d9737..c66458a8c 100644 --- a/pipeline/rpc/mocks/mock_Peer.go +++ b/rpc/mocks/mock_Peer.go @@ -8,7 +8,7 @@ import ( "context" mock "github.com/stretchr/testify/mock" - "go.woodpecker-ci.org/woodpecker/v3/pipeline/rpc" + "go.woodpecker-ci.org/woodpecker/v3/rpc" ) // NewMockPeer creates a new instance of MockPeer. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. @@ -623,20 +623,29 @@ func (_c *MockPeer_Version_Call) RunAndReturn(run func(c context.Context) (*rpc. } // Wait provides a mock function for the type MockPeer -func (_mock *MockPeer) Wait(c context.Context, workflowID string) error { +func (_mock *MockPeer) Wait(c context.Context, workflowID string) (bool, error) { ret := _mock.Called(c, workflowID) if len(ret) == 0 { panic("no return value specified for Wait") } - var r0 error - if returnFunc, ok := ret.Get(0).(func(context.Context, string) error); ok { + var r0 bool + var r1 error + if returnFunc, ok := ret.Get(0).(func(context.Context, string) (bool, error)); ok { + return returnFunc(c, workflowID) + } + if returnFunc, ok := ret.Get(0).(func(context.Context, string) bool); ok { r0 = returnFunc(c, workflowID) } else { - r0 = ret.Error(0) + r0 = ret.Get(0).(bool) } - return r0 + if returnFunc, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = returnFunc(c, workflowID) + } else { + r1 = ret.Error(1) + } + return r0, r1 } // MockPeer_Wait_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Wait' @@ -669,12 +678,12 @@ func (_c *MockPeer_Wait_Call) Run(run func(c context.Context, workflowID string) return _c } -func (_c *MockPeer_Wait_Call) Return(err error) *MockPeer_Wait_Call { - _c.Call.Return(err) +func (_c *MockPeer_Wait_Call) Return(canceled bool, err error) *MockPeer_Wait_Call { + _c.Call.Return(canceled, err) return _c } -func (_c *MockPeer_Wait_Call) RunAndReturn(run func(c context.Context, workflowID string) error) *MockPeer_Wait_Call { +func (_c *MockPeer_Wait_Call) RunAndReturn(run func(c context.Context, workflowID string) (bool, error)) *MockPeer_Wait_Call { _c.Call.Return(run) return _c } diff --git a/rpc/peer.go b/rpc/peer.go new file mode 100644 index 000000000..e1568f692 --- /dev/null +++ b/rpc/peer.go @@ -0,0 +1,305 @@ +// Copyright 2021 Woodpecker Authors +// Copyright 2011 Drone.IO Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package rpc + +import "context" + +// Peer defines the bidirectional communication interface between Woodpecker agents and servers. +// +// # Architecture and Implementations +// +// The Peer interface is implemented differently on each side of the communication: +// +// - Agent side: Implemented by agent/rpc/client_grpc.go's client struct, which wraps +// a gRPC client connection to make RPC calls to the server. +// +// - Server side: Implemented by server/rpc/rpc.go's RPC struct, which contains the +// business logic and is wrapped by server/rpc/server.go's WoodpeckerServer struct +// to handle incoming gRPC requests. +// +// # Thread Safety and Concurrency +// +// - Implementations must be safe for concurrent calls across different workflows +// - The same Peer instance may be called concurrently from multiple goroutines +// - Each workflow is identified by a unique workflowID string +// - Implementations must properly isolate workflow state using workflowID +// +// # Error Handling Conventions +// +// - Methods return errors for communication failures, validation errors, or server-side issues +// - Errors should not be used for business logic +// - Network/transport errors should be retried by the caller when appropriate +// - Nil error indicates successful operation +// - Context cancellation should return nil or context.Canceled, not a custom error +// - Business logic errors (e.g., workflow not found) return specific error types +// +// # Intended Execution Flow +// +// 1. Agent Lifecycle: +// - Version() checks compatibility with server +// - RegisterAgent() announces agent availability +// - ReportHealth() periodically confirms agent is alive +// - UnregisterAgent() gracefully disconnects agent +// +// 2. Workflow Execution (may happen concurrently for multiple workflows): +// - Next() blocks until server assigns a workflow +// - Init() signals workflow execution has started +// - Wait() (in background goroutine) monitors for cancellation signals +// - Update() reports step state changes as workflow progresses +// - EnqueueLog() streams log output from steps +// - Extend() extends workflow timeout if needed so queue does not reschedule it as retry +// - Done() signals workflow has completed +// +// 3. Cancellation Flow: +// - Server can cancel workflow by releasing Wait() with canceled=true +// - Agent detects cancellation from Wait() return value +// - Agent stops workflow execution and calls Done() with canceled state +type Peer interface { + // Version returns the server and gRPC protocol version information. + // + // This is typically called once during agent initialization to verify + // compatibility between agent and server versions. + // + // Returns: + // - Version with server version string and gRPC protocol version number + // - Error if communication fails or server is unreachable + Version(c context.Context) (*Version, error) + + // Next blocks until the server provides the next workflow to execute from the queue. + // + // This is the primary work-polling mechanism. Agents call this repeatedly in a loop, + // and it blocks until either: + // 1. A workflow matching the filter becomes available + // 2. The context is canceled (agent shutdown, network timeout, etc.) + // + // The filter allows agents to specify capabilities via labels (e.g., platform, + // backend type) so the server only assigns compatible workflows. + // + // Context Handling: + // - This is a long-polling operation that may block for extended periods + // - Implementations MUST check context regularly (not just at entry) + // - When context is canceled, must return nil workflow and nil error + // - Server may send keep-alive signals or periodically return nil to allow reconnection + // + // Returns: + // - Workflow object with ID, Config, and Workflow.Timeout if work is available + // - nil, nil if context is canceled or no work available (retry expected) + // - nil, error if a non-retryable error occurs + Next(c context.Context, f Filter) (*Workflow, error) + + // Wait blocks until the workflow with the given ID completes or is canceled by the server. + // + // This is used by agents to monitor for server-side cancellation signals. Typically + // called in a background goroutine immediately after Init(), running concurrently + // with workflow execution. + // + // The method serves two purposes: + // 1. Signals when server wants to cancel workflow (canceled=true) + // 2. Unblocks when workflow completes normally on agent (canceled=false) + // + // Context Handling: + // - This is a long-running blocking operation for the workflow duration + // - Context cancellation indicates shutdown, not workflow cancellation + // - When context is canceled, should return (false, nil) or (false, ctx.Err()) + // - Must not confuse context cancellation with workflow cancellation signal + // + // Cancellation Flow: + // - Server releases Wait() with canceled=true → agent should stop workflow + // - Agent completes workflow normally → Done() is called → server releases Wait() with canceled=false + // - Agent context canceled → Wait() returns immediately, workflow may continue on agent + // + // Returns: + // - canceled=true, err=nil: Server initiated cancellation, agent should stop workflow + // - canceled=false, err=nil: Workflow completed normally (Wait unblocked by Done call) + // - canceled=false, err!=nil: Communication error, agent should retry or handle error + Wait(c context.Context, workflowID string) (canceled bool, err error) + + // Init signals to the server that the workflow has been initialized and execution has started. + // + // This is called once per workflow immediately after the agent accepts it from Next() + // and before starting step execution. It allows the server to track workflow start time + // and update workflow status to "running". + // + // The WorkflowState should have: + // - Started: Unix timestamp when execution began + // - Finished: 0 (not finished yet) + // - Error: empty string (no error yet) + // - Canceled: false (not canceled yet) + // + // Returns: + // - nil on success + // - error if communication fails or server rejects the state + Init(c context.Context, workflowID string, state WorkflowState) error + + // Done signals to the server that the workflow has completed execution. + // + // This is called once per workflow after all steps have finished (or workflow was canceled). + // It provides the final workflow state including completion time, any errors, and + // cancellation status. + // + // The WorkflowState should have: + // - Started: Unix timestamp when execution began (same as Init) + // - Finished: Unix timestamp when execution completed + // - Error: Error message if workflow failed, empty if successful + // - Canceled: true if workflow was canceled, false otherwise + // + // After Done() is called: + // - Server updates final workflow status in database + // - Server releases any Wait() calls for this workflow + // - Server removes workflow from active queue + // - Server notifies forge of workflow completion + // + // Context Handling: + // - MUST attempt to complete even if workflow context is canceled + // - Often called with a shutdown/cleanup context rather than workflow context + // - Critical for proper cleanup - should retry on transient failures + // + // Returns: + // - nil on success + // - error if communication fails or server rejects the state + Done(c context.Context, workflowID string, state WorkflowState) error + + // Extend extends the timeout for the workflow with the given ID in the task queue. + // + // Agents must call Extend() regularly (e.g., every constant.TaskTimeout / 3) to signal + // that the workflow is still actively executing and prevent premature timeout. + // + // If agents don't call Extend periodically, the workflow will be rescheduled to a new + // agent after the timeout period expires (specified in constant.TaskTimeout). + // + // This acts as a heartbeat mechanism to detect stuck workflow executions. If an agent + // dies or becomes unresponsive, the server will eventually timeout the workflow and + // reassign it. + // + // IMPORTANT: Don't confuse this with Workflow.Timeout returned by Next() - they serve + // different purposes! + // + // Returns: + // - nil on success (timeout was extended) + // - error if communication fails or workflow is not found + Extend(c context.Context, workflowID string) error + + // Update reports step state changes to the server as the workflow progresses. + // + // This is called multiple times per step: + // 1. When step starts (Exited=false, Finished=0) + // 2. When step completes (Exited=true, Finished and ExitCode set) + // 3. Potentially on progress updates if step has long-running operations + // + // The server uses these updates to: + // - Track step execution progress + // - Update UI with real-time status + // - Store step results in database + // - Calculate workflow completion + // + // Context Handling: + // - Failures should be logged but not block workflow execution + // + // Returns: + // - nil on success + // - error if communication fails or server rejects the state + Update(c context.Context, workflowID string, state StepState) error + + // EnqueueLog queues a log entry for delayed batch sending to the server. + // + // Log entries are produced continuously during step execution and need to be + // transmitted efficiently. This method adds logs to an internal queue that + // batches and sends them periodically to reduce network overhead. + // + // The implementation should: + // - Queue the log entry in a memory buffer + // - Batch multiple entries together + // - Send batches periodically (e.g., every second) or when buffer fills + // - Handle backpressure if server is slow or network is congested + // + // Unlike other methods, EnqueueLog: + // - Does NOT take a context parameter (fire-and-forget) + // - Does NOT return an error (never blocks the caller) + // - Does NOT guarantee immediate transmission + // + // Thread Safety: + // - MUST be safe to call concurrently from multiple goroutines + // - May be called concurrently from different steps/workflows + // - Internal queue must be properly synchronized + EnqueueLog(logEntry *LogEntry) + + // RegisterAgent announces this agent to the server and returns an agent ID. + // + // This is called once during agent startup to: + // - Create an agent record in the server database + // - Obtain a unique agent ID for subsequent requests + // - Declare agent capabilities (platform, backend, capacity, labels) + // - Enable server-side agent tracking and monitoring + // + // The AgentInfo should specify: + // - Version: Agent version string (e.g., "v2.0.0") + // - Platform: OS/architecture (e.g., "linux/amd64") + // - Backend: Execution backend (e.g., "docker", "kubernetes") + // - Capacity: Maximum concurrent workflows (e.g., 2) + // - CustomLabels: Additional key-value labels for filtering + // + // Context Handling: + // - Context cancellation indicates agent is aborting startup + // - Should not retry indefinitely - fail fast on persistent errors + // + // Returns: + // - agentID: Unique identifier for this agent (use in subsequent calls) + // - error: If registration fails + RegisterAgent(ctx context.Context, info AgentInfo) (int64, error) + + // UnregisterAgent removes this agent from the server's registry. + // + // This is called during graceful agent shutdown to: + // - Mark agent as offline in server database + // - Allow server to stop assigning workflows to this agent + // - Clean up any agent-specific server resources + // - Provide clean shutdown signal to monitoring systems + // + // After UnregisterAgent: + // - Agent should stop calling Next() for new work + // - Agent should complete any in-progress workflows + // - Agent may call Done() to finish existing workflows + // - Agent should close network connections + // + // Context Handling: + // - MUST attempt to complete even during forced shutdown + // - Often called with a shutdown context (limited time) + // - Failure is logged but should not prevent agent exit + // + // Returns: + // - nil on success + // - error if communication fails + UnregisterAgent(ctx context.Context) error + + // ReportHealth sends a periodic health status update to the server. + // + // This is called regularly (e.g., every 30 seconds) during agent operation to: + // - Prove agent is still alive and responsive + // - Allow server to detect dead or stuck agents + // - Update agent's "last seen" timestamp in database + // - Provide application-level keepalive beyond network keep-alive signals + // + // Health reporting helps the server: + // - Mark unresponsive agents as offline + // - Redistribute work from dead agents + // - Display accurate agent status in UI + // - Trigger alerts for infrastructure issues + // + // Returns: + // - nil on success + // - error if communication fails + ReportHealth(c context.Context) error +} diff --git a/pipeline/rpc/proto/generate.go b/rpc/proto/generate.go similarity index 100% rename from pipeline/rpc/proto/generate.go rename to rpc/proto/generate.go diff --git a/pipeline/rpc/proto/version.go b/rpc/proto/version.go similarity index 96% rename from pipeline/rpc/proto/version.go rename to rpc/proto/version.go index 20e1c9513..ee63ab7cd 100644 --- a/pipeline/rpc/proto/version.go +++ b/rpc/proto/version.go @@ -16,4 +16,4 @@ package proto // Version is the version of the woodpecker.proto file, // IMPORTANT: increased by 1 each time it get changed. -const Version int32 = 14 +const Version int32 = 15 diff --git a/pipeline/rpc/proto/woodpecker.pb.go b/rpc/proto/woodpecker.pb.go similarity index 92% rename from pipeline/rpc/proto/woodpecker.pb.go rename to rpc/proto/woodpecker.pb.go index 562836b0d..f5126303d 100644 --- a/pipeline/rpc/proto/woodpecker.pb.go +++ b/rpc/proto/woodpecker.pb.go @@ -15,8 +15,8 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.10 -// protoc v6.32.1 +// protoc-gen-go v1.36.11 +// protoc v6.33.1 // source: woodpecker.proto package proto @@ -44,6 +44,7 @@ type StepState struct { Exited bool `protobuf:"varint,4,opt,name=exited,proto3" json:"exited,omitempty"` ExitCode int32 `protobuf:"varint,5,opt,name=exit_code,json=exitCode,proto3" json:"exit_code,omitempty"` Error string `protobuf:"bytes,6,opt,name=error,proto3" json:"error,omitempty"` + Canceled bool `protobuf:"varint,7,opt,name=canceled,proto3" json:"canceled,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -120,11 +121,19 @@ func (x *StepState) GetError() string { return "" } +func (x *StepState) GetCanceled() bool { + if x != nil { + return x.Canceled + } + return false +} + type WorkflowState struct { state protoimpl.MessageState `protogen:"open.v1"` - Started int64 `protobuf:"varint,4,opt,name=started,proto3" json:"started,omitempty"` - Finished int64 `protobuf:"varint,5,opt,name=finished,proto3" json:"finished,omitempty"` - Error string `protobuf:"bytes,6,opt,name=error,proto3" json:"error,omitempty"` + Started int64 `protobuf:"varint,1,opt,name=started,proto3" json:"started,omitempty"` + Finished int64 `protobuf:"varint,2,opt,name=finished,proto3" json:"finished,omitempty"` + Error string `protobuf:"bytes,3,opt,name=error,proto3" json:"error,omitempty"` + Canceled bool `protobuf:"varint,4,opt,name=canceled,proto3" json:"canceled,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -180,6 +189,13 @@ func (x *WorkflowState) GetError() string { return "" } +func (x *WorkflowState) GetCanceled() bool { + if x != nil { + return x.Canceled + } + return false +} + type LogEntry struct { state protoimpl.MessageState `protogen:"open.v1"` StepUuid string `protobuf:"bytes,1,opt,name=step_uuid,json=stepUuid,proto3" json:"step_uuid,omitempty"` @@ -1032,6 +1048,50 @@ func (x *RegisterAgentResponse) GetAgentId() int64 { return 0 } +type WaitResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Canceled bool `protobuf:"varint,1,opt,name=canceled,proto3" json:"canceled,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *WaitResponse) Reset() { + *x = WaitResponse{} + mi := &file_woodpecker_proto_msgTypes[19] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *WaitResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*WaitResponse) ProtoMessage() {} + +func (x *WaitResponse) ProtoReflect() protoreflect.Message { + mi := &file_woodpecker_proto_msgTypes[19] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use WaitResponse.ProtoReflect.Descriptor instead. +func (*WaitResponse) Descriptor() ([]byte, []int) { + return file_woodpecker_proto_rawDescGZIP(), []int{19} +} + +func (x *WaitResponse) GetCanceled() bool { + if x != nil { + return x.Canceled + } + return false +} + type AuthRequest struct { state protoimpl.MessageState `protogen:"open.v1"` AgentToken string `protobuf:"bytes,1,opt,name=agent_token,json=agentToken,proto3" json:"agent_token,omitempty"` @@ -1042,7 +1102,7 @@ type AuthRequest struct { func (x *AuthRequest) Reset() { *x = AuthRequest{} - mi := &file_woodpecker_proto_msgTypes[19] + mi := &file_woodpecker_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1054,7 +1114,7 @@ func (x *AuthRequest) String() string { func (*AuthRequest) ProtoMessage() {} func (x *AuthRequest) ProtoReflect() protoreflect.Message { - mi := &file_woodpecker_proto_msgTypes[19] + mi := &file_woodpecker_proto_msgTypes[20] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1067,7 +1127,7 @@ func (x *AuthRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use AuthRequest.ProtoReflect.Descriptor instead. func (*AuthRequest) Descriptor() ([]byte, []int) { - return file_woodpecker_proto_rawDescGZIP(), []int{19} + return file_woodpecker_proto_rawDescGZIP(), []int{20} } func (x *AuthRequest) GetAgentToken() string { @@ -1095,7 +1155,7 @@ type AuthResponse struct { func (x *AuthResponse) Reset() { *x = AuthResponse{} - mi := &file_woodpecker_proto_msgTypes[20] + mi := &file_woodpecker_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1107,7 +1167,7 @@ func (x *AuthResponse) String() string { func (*AuthResponse) ProtoMessage() {} func (x *AuthResponse) ProtoReflect() protoreflect.Message { - mi := &file_woodpecker_proto_msgTypes[20] + mi := &file_woodpecker_proto_msgTypes[21] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1120,7 +1180,7 @@ func (x *AuthResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use AuthResponse.ProtoReflect.Descriptor instead. func (*AuthResponse) Descriptor() ([]byte, []int) { - return file_woodpecker_proto_rawDescGZIP(), []int{20} + return file_woodpecker_proto_rawDescGZIP(), []int{21} } func (x *AuthResponse) GetStatus() string { @@ -1148,18 +1208,20 @@ var File_woodpecker_proto protoreflect.FileDescriptor const file_woodpecker_proto_rawDesc = "" + "\n" + - "\x10woodpecker.proto\x12\x05proto\"\xa9\x01\n" + + "\x10woodpecker.proto\x12\x05proto\"\xc5\x01\n" + "\tStepState\x12\x1b\n" + "\tstep_uuid\x18\x01 \x01(\tR\bstepUuid\x12\x18\n" + "\astarted\x18\x02 \x01(\x03R\astarted\x12\x1a\n" + "\bfinished\x18\x03 \x01(\x03R\bfinished\x12\x16\n" + "\x06exited\x18\x04 \x01(\bR\x06exited\x12\x1b\n" + "\texit_code\x18\x05 \x01(\x05R\bexitCode\x12\x14\n" + - "\x05error\x18\x06 \x01(\tR\x05error\"[\n" + + "\x05error\x18\x06 \x01(\tR\x05error\x12\x1a\n" + + "\bcanceled\x18\a \x01(\bR\bcanceled\"w\n" + "\rWorkflowState\x12\x18\n" + - "\astarted\x18\x04 \x01(\x03R\astarted\x12\x1a\n" + - "\bfinished\x18\x05 \x01(\x03R\bfinished\x12\x14\n" + - "\x05error\x18\x06 \x01(\tR\x05error\"w\n" + + "\astarted\x18\x01 \x01(\x03R\astarted\x12\x1a\n" + + "\bfinished\x18\x02 \x01(\x03R\bfinished\x12\x14\n" + + "\x05error\x18\x03 \x01(\tR\x05error\x12\x1a\n" + + "\bcanceled\x18\x04 \x01(\bR\bcanceled\"w\n" + "\bLogEntry\x12\x1b\n" + "\tstep_uuid\x18\x01 \x01(\tR\bstepUuid\x12\x12\n" + "\x04time\x18\x02 \x01(\x03R\x04time\x12\x12\n" + @@ -1215,7 +1277,9 @@ const file_woodpecker_proto_rawDesc = "" + "\fNextResponse\x12+\n" + "\bworkflow\x18\x01 \x01(\v2\x0f.proto.WorkflowR\bworkflow\"2\n" + "\x15RegisterAgentResponse\x12\x19\n" + - "\bagent_id\x18\x01 \x01(\x03R\aagentId\"I\n" + + "\bagent_id\x18\x01 \x01(\x03R\aagentId\"*\n" + + "\fWaitResponse\x12\x1a\n" + + "\bcanceled\x18\x01 \x01(\bR\bcanceled\"I\n" + "\vAuthRequest\x12\x1f\n" + "\vagent_token\x18\x01 \x01(\tR\n" + "agentToken\x12\x19\n" + @@ -1223,13 +1287,13 @@ const file_woodpecker_proto_rawDesc = "" + "\fAuthResponse\x12\x16\n" + "\x06status\x18\x01 \x01(\tR\x06status\x12\x19\n" + "\bagent_id\x18\x02 \x01(\x03R\aagentId\x12!\n" + - "\faccess_token\x18\x03 \x01(\tR\vaccessToken2\xbb\x04\n" + + "\faccess_token\x18\x03 \x01(\tR\vaccessToken2\xc2\x04\n" + "\n" + "Woodpecker\x121\n" + "\aVersion\x12\f.proto.Empty\x1a\x16.proto.VersionResponse\"\x00\x121\n" + "\x04Next\x12\x12.proto.NextRequest\x1a\x13.proto.NextResponse\"\x00\x12*\n" + - "\x04Init\x12\x12.proto.InitRequest\x1a\f.proto.Empty\"\x00\x12*\n" + - "\x04Wait\x12\x12.proto.WaitRequest\x1a\f.proto.Empty\"\x00\x12*\n" + + "\x04Init\x12\x12.proto.InitRequest\x1a\f.proto.Empty\"\x00\x121\n" + + "\x04Wait\x12\x12.proto.WaitRequest\x1a\x13.proto.WaitResponse\"\x00\x12*\n" + "\x04Done\x12\x12.proto.DoneRequest\x1a\f.proto.Empty\"\x00\x12.\n" + "\x06Extend\x12\x14.proto.ExtendRequest\x1a\f.proto.Empty\"\x00\x12.\n" + "\x06Update\x12\x14.proto.UpdateRequest\x1a\f.proto.Empty\"\x00\x12(\n" + @@ -1238,7 +1302,7 @@ const file_woodpecker_proto_rawDesc = "" + "\x0fUnregisterAgent\x12\f.proto.Empty\x1a\f.proto.Empty\"\x00\x12:\n" + "\fReportHealth\x12\x1a.proto.ReportHealthRequest\x1a\f.proto.Empty\"\x002C\n" + "\x0eWoodpeckerAuth\x121\n" + - "\x04Auth\x12\x12.proto.AuthRequest\x1a\x13.proto.AuthResponse\"\x00B7Z5go.woodpecker-ci.org/woodpecker/v3/pipeline/rpc/protob\x06proto3" + "\x04Auth\x12\x12.proto.AuthRequest\x1a\x13.proto.AuthResponse\"\x00B.Z,go.woodpecker-ci.org/woodpecker/v3/rpc/protob\x06proto3" var ( file_woodpecker_proto_rawDescOnce sync.Once @@ -1252,7 +1316,7 @@ func file_woodpecker_proto_rawDescGZIP() []byte { return file_woodpecker_proto_rawDescData } -var file_woodpecker_proto_msgTypes = make([]protoimpl.MessageInfo, 23) +var file_woodpecker_proto_msgTypes = make([]protoimpl.MessageInfo, 24) var file_woodpecker_proto_goTypes = []any{ (*StepState)(nil), // 0: proto.StepState (*WorkflowState)(nil), // 1: proto.WorkflowState @@ -1273,19 +1337,20 @@ var file_woodpecker_proto_goTypes = []any{ (*VersionResponse)(nil), // 16: proto.VersionResponse (*NextResponse)(nil), // 17: proto.NextResponse (*RegisterAgentResponse)(nil), // 18: proto.RegisterAgentResponse - (*AuthRequest)(nil), // 19: proto.AuthRequest - (*AuthResponse)(nil), // 20: proto.AuthResponse - nil, // 21: proto.Filter.LabelsEntry - nil, // 22: proto.AgentInfo.CustomLabelsEntry + (*WaitResponse)(nil), // 19: proto.WaitResponse + (*AuthRequest)(nil), // 20: proto.AuthRequest + (*AuthResponse)(nil), // 21: proto.AuthResponse + nil, // 22: proto.Filter.LabelsEntry + nil, // 23: proto.AgentInfo.CustomLabelsEntry } var file_woodpecker_proto_depIdxs = []int32{ - 21, // 0: proto.Filter.labels:type_name -> proto.Filter.LabelsEntry + 22, // 0: proto.Filter.labels:type_name -> proto.Filter.LabelsEntry 3, // 1: proto.NextRequest.filter:type_name -> proto.Filter 1, // 2: proto.InitRequest.state:type_name -> proto.WorkflowState 1, // 3: proto.DoneRequest.state:type_name -> proto.WorkflowState 0, // 4: proto.UpdateRequest.state:type_name -> proto.StepState 2, // 5: proto.LogRequest.logEntries:type_name -> proto.LogEntry - 22, // 6: proto.AgentInfo.customLabels:type_name -> proto.AgentInfo.CustomLabelsEntry + 23, // 6: proto.AgentInfo.customLabels:type_name -> proto.AgentInfo.CustomLabelsEntry 14, // 7: proto.RegisterAgentRequest.info:type_name -> proto.AgentInfo 4, // 8: proto.NextResponse.workflow:type_name -> proto.Workflow 12, // 9: proto.Woodpecker.Version:input_type -> proto.Empty @@ -1299,11 +1364,11 @@ var file_woodpecker_proto_depIdxs = []int32{ 15, // 17: proto.Woodpecker.RegisterAgent:input_type -> proto.RegisterAgentRequest 12, // 18: proto.Woodpecker.UnregisterAgent:input_type -> proto.Empty 13, // 19: proto.Woodpecker.ReportHealth:input_type -> proto.ReportHealthRequest - 19, // 20: proto.WoodpeckerAuth.Auth:input_type -> proto.AuthRequest + 20, // 20: proto.WoodpeckerAuth.Auth:input_type -> proto.AuthRequest 16, // 21: proto.Woodpecker.Version:output_type -> proto.VersionResponse 17, // 22: proto.Woodpecker.Next:output_type -> proto.NextResponse 12, // 23: proto.Woodpecker.Init:output_type -> proto.Empty - 12, // 24: proto.Woodpecker.Wait:output_type -> proto.Empty + 19, // 24: proto.Woodpecker.Wait:output_type -> proto.WaitResponse 12, // 25: proto.Woodpecker.Done:output_type -> proto.Empty 12, // 26: proto.Woodpecker.Extend:output_type -> proto.Empty 12, // 27: proto.Woodpecker.Update:output_type -> proto.Empty @@ -1311,7 +1376,7 @@ var file_woodpecker_proto_depIdxs = []int32{ 18, // 29: proto.Woodpecker.RegisterAgent:output_type -> proto.RegisterAgentResponse 12, // 30: proto.Woodpecker.UnregisterAgent:output_type -> proto.Empty 12, // 31: proto.Woodpecker.ReportHealth:output_type -> proto.Empty - 20, // 32: proto.WoodpeckerAuth.Auth:output_type -> proto.AuthResponse + 21, // 32: proto.WoodpeckerAuth.Auth:output_type -> proto.AuthResponse 21, // [21:33] is the sub-list for method output_type 9, // [9:21] is the sub-list for method input_type 9, // [9:9] is the sub-list for extension type_name @@ -1330,7 +1395,7 @@ func file_woodpecker_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_woodpecker_proto_rawDesc), len(file_woodpecker_proto_rawDesc)), NumEnums: 0, - NumMessages: 23, + NumMessages: 24, NumExtensions: 0, NumServices: 2, }, diff --git a/pipeline/rpc/proto/woodpecker.proto b/rpc/proto/woodpecker.proto similarity index 91% rename from pipeline/rpc/proto/woodpecker.proto rename to rpc/proto/woodpecker.proto index 58410f820..b348c0957 100644 --- a/pipeline/rpc/proto/woodpecker.proto +++ b/rpc/proto/woodpecker.proto @@ -15,7 +15,7 @@ syntax = "proto3"; -option go_package = "go.woodpecker-ci.org/woodpecker/v3/pipeline/rpc/proto"; +option go_package = "go.woodpecker-ci.org/woodpecker/v3/rpc/proto"; package proto; // !IMPORTANT! @@ -27,7 +27,7 @@ service Woodpecker { rpc Version (Empty) returns (VersionResponse) {} rpc Next (NextRequest) returns (NextResponse) {} rpc Init (InitRequest) returns (Empty) {} - rpc Wait (WaitRequest) returns (Empty) {} + rpc Wait (WaitRequest) returns (WaitResponse) {} rpc Done (DoneRequest) returns (Empty) {} rpc Extend (ExtendRequest) returns (Empty) {} rpc Update (UpdateRequest) returns (Empty) {} @@ -48,12 +48,14 @@ message StepState { bool exited = 4; int32 exit_code = 5; string error = 6; + bool canceled = 7; } message WorkflowState { - int64 started = 4; - int64 finished = 5; - string error = 6; + int64 started = 1; + int64 finished = 2; + string error = 3; + bool canceled = 4; } message LogEntry { @@ -145,6 +147,10 @@ message RegisterAgentResponse { int64 agent_id = 1; } +message WaitResponse { + bool canceled = 1; +}; + // Woodpecker auth service is a simple service to authenticate agents and acquire a token service WoodpeckerAuth { diff --git a/pipeline/rpc/proto/woodpecker_grpc.pb.go b/rpc/proto/woodpecker_grpc.pb.go similarity index 94% rename from pipeline/rpc/proto/woodpecker_grpc.pb.go rename to rpc/proto/woodpecker_grpc.pb.go index 80dbfb3a1..88ca6e7a9 100644 --- a/pipeline/rpc/proto/woodpecker_grpc.pb.go +++ b/rpc/proto/woodpecker_grpc.pb.go @@ -15,8 +15,8 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: -// - protoc-gen-go-grpc v1.5.1 -// - protoc v6.32.1 +// - protoc-gen-go-grpc v1.6.0 +// - protoc v6.33.1 // source: woodpecker.proto package proto @@ -56,7 +56,7 @@ type WoodpeckerClient interface { Version(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*VersionResponse, error) Next(ctx context.Context, in *NextRequest, opts ...grpc.CallOption) (*NextResponse, error) Init(ctx context.Context, in *InitRequest, opts ...grpc.CallOption) (*Empty, error) - Wait(ctx context.Context, in *WaitRequest, opts ...grpc.CallOption) (*Empty, error) + Wait(ctx context.Context, in *WaitRequest, opts ...grpc.CallOption) (*WaitResponse, error) Done(ctx context.Context, in *DoneRequest, opts ...grpc.CallOption) (*Empty, error) Extend(ctx context.Context, in *ExtendRequest, opts ...grpc.CallOption) (*Empty, error) Update(ctx context.Context, in *UpdateRequest, opts ...grpc.CallOption) (*Empty, error) @@ -104,9 +104,9 @@ func (c *woodpeckerClient) Init(ctx context.Context, in *InitRequest, opts ...gr return out, nil } -func (c *woodpeckerClient) Wait(ctx context.Context, in *WaitRequest, opts ...grpc.CallOption) (*Empty, error) { +func (c *woodpeckerClient) Wait(ctx context.Context, in *WaitRequest, opts ...grpc.CallOption) (*WaitResponse, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) - out := new(Empty) + out := new(WaitResponse) err := c.cc.Invoke(ctx, Woodpecker_Wait_FullMethodName, in, out, cOpts...) if err != nil { return nil, err @@ -193,7 +193,7 @@ type WoodpeckerServer interface { Version(context.Context, *Empty) (*VersionResponse, error) Next(context.Context, *NextRequest) (*NextResponse, error) Init(context.Context, *InitRequest) (*Empty, error) - Wait(context.Context, *WaitRequest) (*Empty, error) + Wait(context.Context, *WaitRequest) (*WaitResponse, error) Done(context.Context, *DoneRequest) (*Empty, error) Extend(context.Context, *ExtendRequest) (*Empty, error) Update(context.Context, *UpdateRequest) (*Empty, error) @@ -212,37 +212,37 @@ type WoodpeckerServer interface { type UnimplementedWoodpeckerServer struct{} func (UnimplementedWoodpeckerServer) Version(context.Context, *Empty) (*VersionResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method Version not implemented") + return nil, status.Error(codes.Unimplemented, "method Version not implemented") } func (UnimplementedWoodpeckerServer) Next(context.Context, *NextRequest) (*NextResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method Next not implemented") + return nil, status.Error(codes.Unimplemented, "method Next not implemented") } func (UnimplementedWoodpeckerServer) Init(context.Context, *InitRequest) (*Empty, error) { - return nil, status.Errorf(codes.Unimplemented, "method Init not implemented") + return nil, status.Error(codes.Unimplemented, "method Init not implemented") } -func (UnimplementedWoodpeckerServer) Wait(context.Context, *WaitRequest) (*Empty, error) { - return nil, status.Errorf(codes.Unimplemented, "method Wait not implemented") +func (UnimplementedWoodpeckerServer) Wait(context.Context, *WaitRequest) (*WaitResponse, error) { + return nil, status.Error(codes.Unimplemented, "method Wait not implemented") } func (UnimplementedWoodpeckerServer) Done(context.Context, *DoneRequest) (*Empty, error) { - return nil, status.Errorf(codes.Unimplemented, "method Done not implemented") + return nil, status.Error(codes.Unimplemented, "method Done not implemented") } func (UnimplementedWoodpeckerServer) Extend(context.Context, *ExtendRequest) (*Empty, error) { - return nil, status.Errorf(codes.Unimplemented, "method Extend not implemented") + return nil, status.Error(codes.Unimplemented, "method Extend not implemented") } func (UnimplementedWoodpeckerServer) Update(context.Context, *UpdateRequest) (*Empty, error) { - return nil, status.Errorf(codes.Unimplemented, "method Update not implemented") + return nil, status.Error(codes.Unimplemented, "method Update not implemented") } func (UnimplementedWoodpeckerServer) Log(context.Context, *LogRequest) (*Empty, error) { - return nil, status.Errorf(codes.Unimplemented, "method Log not implemented") + return nil, status.Error(codes.Unimplemented, "method Log not implemented") } func (UnimplementedWoodpeckerServer) RegisterAgent(context.Context, *RegisterAgentRequest) (*RegisterAgentResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method RegisterAgent not implemented") + return nil, status.Error(codes.Unimplemented, "method RegisterAgent not implemented") } func (UnimplementedWoodpeckerServer) UnregisterAgent(context.Context, *Empty) (*Empty, error) { - return nil, status.Errorf(codes.Unimplemented, "method UnregisterAgent not implemented") + return nil, status.Error(codes.Unimplemented, "method UnregisterAgent not implemented") } func (UnimplementedWoodpeckerServer) ReportHealth(context.Context, *ReportHealthRequest) (*Empty, error) { - return nil, status.Errorf(codes.Unimplemented, "method ReportHealth not implemented") + return nil, status.Error(codes.Unimplemented, "method ReportHealth not implemented") } func (UnimplementedWoodpeckerServer) mustEmbedUnimplementedWoodpeckerServer() {} func (UnimplementedWoodpeckerServer) testEmbeddedByValue() {} @@ -255,7 +255,7 @@ type UnsafeWoodpeckerServer interface { } func RegisterWoodpeckerServer(s grpc.ServiceRegistrar, srv WoodpeckerServer) { - // If the following call pancis, it indicates UnimplementedWoodpeckerServer was + // If the following call panics, it indicates UnimplementedWoodpeckerServer was // embedded by pointer and is nil. This will cause panics if an // unimplemented method is ever invoked, so we test this at initialization // time to prevent it from happening at runtime later due to I/O. @@ -564,7 +564,7 @@ type WoodpeckerAuthServer interface { type UnimplementedWoodpeckerAuthServer struct{} func (UnimplementedWoodpeckerAuthServer) Auth(context.Context, *AuthRequest) (*AuthResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method Auth not implemented") + return nil, status.Error(codes.Unimplemented, "method Auth not implemented") } func (UnimplementedWoodpeckerAuthServer) mustEmbedUnimplementedWoodpeckerAuthServer() {} func (UnimplementedWoodpeckerAuthServer) testEmbeddedByValue() {} @@ -577,7 +577,7 @@ type UnsafeWoodpeckerAuthServer interface { } func RegisterWoodpeckerAuthServer(s grpc.ServiceRegistrar, srv WoodpeckerAuthServer) { - // If the following call pancis, it indicates UnimplementedWoodpeckerAuthServer was + // If the following call panics, it indicates UnimplementedWoodpeckerAuthServer was // embedded by pointer and is nil. This will cause panics if an // unimplemented method is ever invoked, so we test this at initialization // time to prevent it from happening at runtime later due to I/O. diff --git a/pipeline/rpc/peer.go b/rpc/types.go similarity index 59% rename from pipeline/rpc/peer.go rename to rpc/types.go index 6dee992e1..18dc6ca23 100644 --- a/pipeline/rpc/peer.go +++ b/rpc/types.go @@ -1,5 +1,4 @@ -// Copyright 2021 Woodpecker Authors -// Copyright 2011 Drone.IO Inc. +// Copyright 2025 Woodpecker Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -16,8 +15,6 @@ package rpc import ( - "context" - backend "go.woodpecker-ci.org/woodpecker/v3/pipeline/backend/types" ) @@ -35,6 +32,7 @@ type ( Exited bool `json:"exited"` ExitCode int `json:"exit_code"` Error string `json:"error"` + Canceled bool `json:"canceled"` } // WorkflowState defines the workflow state. @@ -42,6 +40,7 @@ type ( Started int64 `json:"started"` Finished int64 `json:"finished"` Error string `json:"error"` + Canceled bool `json:"canceled"` } // Workflow defines the workflow execution details. @@ -65,39 +64,3 @@ type ( CustomLabels map[string]string `json:"custom_labels"` } ) - -// Peer defines a peer-to-peer connection. -type Peer interface { - // Version returns the server- & grpc-version - Version(c context.Context) (*Version, error) - - // Next returns the next workflow in the queue - Next(c context.Context, f Filter) (*Workflow, error) - - // Wait blocks until the workflow is complete - Wait(c context.Context, workflowID string) error - - // Init signals the workflow is initialized - Init(c context.Context, workflowID string, state WorkflowState) error - - // Done signals the workflow is complete - Done(c context.Context, workflowID string, state WorkflowState) error - - // Extend extends the workflow deadline - Extend(c context.Context, workflowID string) error - - // Update updates the step state - Update(c context.Context, workflowID string, state StepState) error - - // EnqueueLog queues the step log entry for delayed sending - EnqueueLog(logEntry *LogEntry) - - // RegisterAgent register our agent to the server - RegisterAgent(ctx context.Context, info AgentInfo) (int64, error) - - // UnregisterAgent unregister our agent from the server - UnregisterAgent(ctx context.Context) error - - // ReportHealth reports health status of the agent to the server - ReportHealth(c context.Context) error -} diff --git a/server/api/badge.go b/server/api/badge.go index ef5a59091..6d5a0e36f 100644 --- a/server/api/badge.go +++ b/server/api/badge.go @@ -30,6 +30,7 @@ import ( "go.woodpecker-ci.org/woodpecker/v3/server/badges" "go.woodpecker-ci.org/woodpecker/v3/server/ccmenu" "go.woodpecker-ci.org/woodpecker/v3/server/model" + "go.woodpecker-ci.org/woodpecker/v3/server/pipeline" "go.woodpecker-ci.org/woodpecker/v3/server/store" "go.woodpecker-ci.org/woodpecker/v3/server/store/types" ) @@ -93,17 +94,64 @@ func GetBadge(c *gin.Context) { } } - pipeline, err := _store.GetPipelineBadge(repo, branch, events) + name := "pipeline" + var status *model.StatusValue = nil + + pl, err := _store.GetPipelineBadge(repo, branch, events) if err != nil { if !errors.Is(err, types.RecordNotExist) { log.Warn().Err(err).Msg("could not get last pipeline for badge") } - pipeline = nil + } else { + status = &pl.Status } // we serve an SVG, so set content type appropriately. c.Writer.Header().Set("Content-Type", "image/svg+xml") - c.String(http.StatusOK, badges.Generate(pipeline)) + + // Allow workflow (and step) specific badges + workflowName := c.Query("workflow") + if len(workflowName) != 0 { + name = workflowName + status = nil + + workflows, err := _store.WorkflowGetTree(pl) + if err == nil { + for _, wf := range workflows { + if wf.Name == workflowName { + stepName := c.Query("step") + if len(stepName) == 0 { + if status != nil { + merged := pipeline.MergeStatusValues(*status, wf.State) + status = &merged + } else { + status = &wf.State + } + continue + } + // If step is explicitly requested + name = workflowName + ": " + stepName + for _, s := range wf.Children { + if s.Name == stepName { + if status != nil { + merged := pipeline.MergeStatusValues(*status, s.State) + status = &merged + } else { + status = &s.State + } + } + } + } + } + } + } + + badge, err := badges.Generate(name, status) + if err != nil { + c.String(http.StatusInternalServerError, "Failed to generate badge.") + } else { + c.String(http.StatusOK, badge) + } } // GetCC diff --git a/server/api/cron.go b/server/api/cron.go index 78b05b6fe..119b22d36 100644 --- a/server/api/cron.go +++ b/server/api/cron.go @@ -128,6 +128,8 @@ func PostCron(c *gin.Context) { CreatorID: user.ID, Schedule: in.Schedule, Branch: in.Branch, + Variables: in.Variables, + Enabled: in.Enabled, } if err := cron.Validate(); err != nil { c.String(http.StatusUnprocessableEntity, "Error inserting cron. validate failed: %s", err) @@ -164,10 +166,10 @@ func PostCron(c *gin.Context) { // @Produce json // @Success 200 {object} Cron // @Tags Repository cron jobs -// @Param Authorization header string true "Insert your personal access token" default(Bearer ) -// @Param repo_id path int true "the repository id" -// @Param cron path string true "the cron job id" -// @Param cronJob body Cron true "the cron job data" +// @Param Authorization header string true "Insert your personal access token" default(Bearer ) +// @Param repo_id path int true "the repository id" +// @Param cron path string true "the cron job id" +// @Param cronJob body CronPatch true "the cron job data" func PatchCron(c *gin.Context) { repo := session.Repo(c) user := session.User(c) @@ -185,7 +187,7 @@ func PatchCron(c *gin.Context) { return } - in := new(model.Cron) + in := new(model.CronPatch) err = c.Bind(in) if err != nil { c.String(http.StatusBadRequest, "Error parsing request. %s", err) @@ -197,26 +199,41 @@ func PatchCron(c *gin.Context) { handleDBError(c, err) return } - if in.Branch != "" { + if in.Branch != nil && *in.Branch != "" { // check if branch exists on forge - _, err := _forge.BranchHead(c, user, repo, in.Branch) + _, err := _forge.BranchHead(c, user, repo, *in.Branch) if err != nil { c.String(http.StatusBadRequest, "Error inserting cron. branch not resolved: %s", err) return } - cron.Branch = in.Branch + cron.Branch = *in.Branch } - if in.Schedule != "" { - cron.Schedule = in.Schedule - nextExec, err := cronScheduler.CalcNewNext(in.Schedule, time.Now()) + if in.Schedule != nil && *in.Schedule != "" { + cron.Schedule = *in.Schedule + nextExec, err := cronScheduler.CalcNewNext(*in.Schedule, time.Now()) if err != nil { c.String(http.StatusBadRequest, "Error inserting cron. schedule could not parsed: %s", err) return } cron.NextExec = nextExec.Unix() } - if in.Name != "" { - cron.Name = in.Name + if in.Name != nil && *in.Name != "" { + cron.Name = *in.Name + } + if in.Enabled != nil { + cron.Enabled = *in.Enabled + // if we re-enable a cron we have to calc NextExec because it was not while disabled + if cron.Enabled { + nextExec, err := cronScheduler.CalcNewNext(*in.Schedule, time.Now()) + if err != nil { + c.String(http.StatusInternalServerError, "Cron schedule could not parsed: %s", err) + return + } + cron.NextExec = nextExec.Unix() + } + } + if in.Variables != nil { + cron.Variables = in.Variables } cron.CreatorID = user.ID diff --git a/server/api/global_secret.go b/server/api/global_secret.go index 1bcc6a825..abea683ff 100644 --- a/server/api/global_secret.go +++ b/server/api/global_secret.go @@ -89,6 +89,7 @@ func PostGlobalSecret(c *gin.Context) { Value: in.Value, Events: in.Events, Images: in.Images, + Note: in.Note, } if err := secret.Validate(); err != nil { c.String(http.StatusBadRequest, "Error inserting global secret. %s", err) @@ -110,13 +111,13 @@ func PostGlobalSecret(c *gin.Context) { // @Produce json // @Success 200 {object} Secret // @Tags Secrets -// @Param Authorization header string true "Insert your personal access token" default(Bearer ) -// @Param secret path string true "the secret's name" -// @Param secretData body Secret true "the secret's data" +// @Param Authorization header string true "Insert your personal access token" default(Bearer ) +// @Param secret path string true "the secret's name" +// @Param secretData body SecretPatch true "the secret's data" func PatchGlobalSecret(c *gin.Context) { name := c.Param("secret") - in := new(model.Secret) + in := new(model.SecretPatch) err := c.Bind(in) if err != nil { c.String(http.StatusBadRequest, "Error parsing secret. %s", err) @@ -129,8 +130,8 @@ func PatchGlobalSecret(c *gin.Context) { handleDBError(c, err) return } - if in.Value != "" { - secret.Value = in.Value + if in.Value != nil && *in.Value != "" { + secret.Value = *in.Value } if in.Events != nil { secret.Events = in.Events @@ -138,6 +139,9 @@ func PatchGlobalSecret(c *gin.Context) { if in.Images != nil { secret.Images = in.Images } + if in.Note != nil { + secret.Note = *in.Note + } if err := secret.Validate(); err != nil { c.String(http.StatusBadRequest, "Error updating global secret. %s", err) diff --git a/server/api/login.go b/server/api/login.go index aaade3a4d..50de2429e 100644 --- a/server/api/login.go +++ b/server/api/login.go @@ -24,8 +24,8 @@ import ( "time" "github.com/gin-gonic/gin" - "github.com/google/tink/go/subtle/random" "github.com/rs/zerolog/log" + "github.com/tink-crypto/tink-go/v2/subtle/random" "go.woodpecker-ci.org/woodpecker/v3/server" "go.woodpecker-ci.org/woodpecker/v3/server/forge" @@ -144,7 +144,9 @@ func HandleAuth(c *gin.Context) { Page: page, PerPage: perPage, }) - if terr != nil { + if errors.Is(terr, forge_types.ErrNotImplemented) { + log.Debug().Msg("Could not fetch membership of user as forge adapter did not implement it") + } else if terr != nil { log.Error().Err(terr).Msgf("cannot verify team membership for %s", userFromForge.Login) c.Redirect(http.StatusSeeOther, server.Config.Server.RootPath+"/login?error=internal_error") return @@ -334,7 +336,6 @@ func updateRepoPermissions(c *gin.Context, user *model.User, _store store.Store, log.Debug().Msgf("synced user permission for user %s and repo %s", user.Login, dbRepo.FullName) perm := forgeRepo.Perm - perm.Repo = dbRepo perm.RepoID = dbRepo.ID perm.UserID = user.ID perm.Synced = time.Now().Unix() diff --git a/server/api/org_secret.go b/server/api/org_secret.go index 47b9dfc53..6c08a3e23 100644 --- a/server/api/org_secret.go +++ b/server/api/org_secret.go @@ -99,6 +99,7 @@ func PostOrgSecret(c *gin.Context) { Value: in.Value, Events: in.Events, Images: in.Images, + Note: in.Note, } if err := secret.Validate(); err != nil { c.String(http.StatusUnprocessableEntity, "Error inserting org %q secret. %s", org.ID, err) @@ -120,15 +121,15 @@ func PostOrgSecret(c *gin.Context) { // @Produce json // @Success 200 {object} Secret // @Tags Organization secrets -// @Param Authorization header string true "Insert your personal access token" default(Bearer ) -// @Param org_id path string true "the org's id" -// @Param secret path string true "the secret's name" -// @Param secretData body Secret true "the update secret data" +// @Param Authorization header string true "Insert your personal access token" default(Bearer ) +// @Param org_id path string true "the org's id" +// @Param secret path string true "the secret's name" +// @Param secretData body SecretPatch true "the update secret data" func PatchOrgSecret(c *gin.Context) { org := session.Org(c) name := c.Param("secret") - in := new(model.Secret) + in := new(model.SecretPatch) if err := c.Bind(in); err != nil { c.String(http.StatusBadRequest, "Error parsing secret. %s", err) return @@ -140,8 +141,8 @@ func PatchOrgSecret(c *gin.Context) { handleDBError(c, err) return } - if in.Value != "" { - secret.Value = in.Value + if in.Value != nil && *in.Value != "" { + secret.Value = *in.Value } if in.Events != nil { secret.Events = in.Events @@ -149,6 +150,9 @@ func PatchOrgSecret(c *gin.Context) { if in.Images != nil { secret.Images = in.Images } + if in.Note != nil { + secret.Note = *in.Note + } if err := secret.Validate(); err != nil { c.String(http.StatusUnprocessableEntity, "Error updating org %q secret. %s", org.ID, err) diff --git a/server/api/pipeline.go b/server/api/pipeline.go index ce3d1396f..23ad8a619 100644 --- a/server/api/pipeline.go +++ b/server/api/pipeline.go @@ -231,7 +231,7 @@ func DeletePipeline(c *gin.Context) { func GetPipeline(c *gin.Context) { _store := store.FromContext(c) if c.Param("number") == "latest" { - GetPipelineLast(c) + GetPipelineLastByBranch(c) return } @@ -255,12 +255,12 @@ func GetPipeline(c *gin.Context) { c.JSON(http.StatusOK, pl) } -func GetPipelineLast(c *gin.Context) { +func GetPipelineLastByBranch(c *gin.Context) { _store := store.FromContext(c) repo := session.Repo(c) branch := c.DefaultQuery("branch", repo.Branch) - pl, err := _store.GetPipelineLast(repo, branch) + pl, err := _store.GetPipelineLastByBranch(repo, branch) if err != nil { handleDBError(c, err) return @@ -493,7 +493,9 @@ func CancelPipeline(c *gin.Context) { return } - if err := pipeline.Cancel(c, _forge, _store, repo, user, pl); err != nil { + if err := pipeline.Cancel(c, _forge, _store, repo, user, pl, &model.CancelInfo{ + CanceledByUser: user.Login, + }); err != nil { handlePipelineErr(c, err) } else { c.Status(http.StatusNoContent) diff --git a/server/api/pipeline_test.go b/server/api/pipeline_test.go index 65bb042bc..31c87bb81 100644 --- a/server/api/pipeline_test.go +++ b/server/api/pipeline_test.go @@ -28,6 +28,7 @@ import ( "go.woodpecker-ci.org/woodpecker/v3/server" forge_mocks "go.woodpecker-ci.org/woodpecker/v3/server/forge/mocks" "go.woodpecker-ci.org/woodpecker/v3/server/model" + "go.woodpecker-ci.org/woodpecker/v3/server/pubsub" manager_mocks "go.woodpecker-ci.org/woodpecker/v3/server/services/mocks" store_mocks "go.woodpecker-ci.org/woodpecker/v3/server/store/mocks" "go.woodpecker-ci.org/woodpecker/v3/server/store/types" @@ -233,3 +234,40 @@ func TestGetPipelineMetadata(t *testing.T) { }) }) } + +func TestCancelPipeline(t *testing.T) { + gin.SetMode(gin.TestMode) + + t.Run("should cancel running pipeline", func(t *testing.T) { + runningPipeline := &model.Pipeline{ + ID: 2, + Number: 2, + Status: model.StatusRunning, + } + + fakeRepo := &model.Repo{ID: 1} + fakeUser := &model.User{Login: "testuser"} + + mockForge := forge_mocks.NewMockForge(t) + mockStore := store_mocks.NewMockStore(t) + mockStore.On("GetPipelineNumber", fakeRepo, int64(2)).Return(runningPipeline, nil) + mockStore.On("WorkflowGetTree", mock.Anything).Return([]*model.Workflow{}, nil) + mockStore.On("UpdatePipeline", mock.Anything).Return(nil) + + mockManager := manager_mocks.NewMockManager(t) + mockManager.On("ForgeFromRepo", fakeRepo).Return(mockForge, nil) + server.Config.Services.Manager = mockManager + server.Config.Services.Pubsub = pubsub.New() + + w := httptest.NewRecorder() + c, _ := gin.CreateTestContext(w) + c.Set("store", mockStore) + c.Set("repo", fakeRepo) + c.Set("user", fakeUser) + c.Params = gin.Params{{Key: "number", Value: "2"}} + + CancelPipeline(c) + + assert.Equal(t, http.StatusNoContent, c.Writer.Status()) + }) +} diff --git a/server/api/repo.go b/server/api/repo.go index be109a043..21224bc25 100644 --- a/server/api/repo.go +++ b/server/api/repo.go @@ -24,11 +24,12 @@ import ( "time" "github.com/gin-gonic/gin" - "github.com/google/tink/go/subtle/random" "github.com/rs/zerolog/log" + "github.com/tink-crypto/tink-go/v2/subtle/random" "go.woodpecker-ci.org/woodpecker/v3/server" "go.woodpecker-ci.org/woodpecker/v3/server/forge" + forge_types "go.woodpecker-ci.org/woodpecker/v3/server/forge/types" "go.woodpecker-ci.org/woodpecker/v3/server/model" "go.woodpecker-ci.org/woodpecker/v3/server/router/middleware/session" "go.woodpecker-ci.org/woodpecker/v3/server/store" @@ -55,6 +56,8 @@ func PostRepo(c *gin.Context) { return } + forge.Refresh(c, _forge, _store, user) + forgeRemoteID := model.ForgeRemoteID(c.Query("forge_remote_id")) if !forgeRemoteID.IsValid() { c.String(http.StatusBadRequest, "No forge_remote_id provided") @@ -191,7 +194,6 @@ func PostRepo(c *gin.Context) { repo.Perm.Synced = time.Now().Unix() repo.Perm.UserID = user.ID repo.Perm.RepoID = repo.ID - repo.Perm.Repo = repo err = _store.PermUpsert(repo.Perm) if err != nil { c.String(http.StatusInternalServerError, err.Error()) @@ -287,6 +289,9 @@ func PatchRepo(c *gin.Context) { if in.ConfigExtensionEndpoint != nil { repo.ConfigExtensionEndpoint = *in.ConfigExtensionEndpoint } + if in.ConfigExtensionExclusive != nil { + repo.ConfigExtensionExclusive = *in.ConfigExtensionExclusive + } err := _store.UpdateRepo(repo) if err != nil { @@ -388,8 +393,12 @@ func GetRepoBranches(c *gin.Context) { return } + forge.Refresh(c, _forge, _store, repoUser) + branches, err := _forge.Branches(c, repoUser, repo, session.Pagination(c)) - if err != nil { + if errors.Is(err, forge_types.ErrNotImplemented) { + log.Debug().Msg("Could not fetch repo branch list as forge adapter did not implement it") + } else if err != nil { log.Error().Err(err).Msg("failed to load branches") c.String(http.StatusInternalServerError, "failed to load branches: %s", err) return @@ -428,7 +437,9 @@ func GetRepoPullRequests(c *gin.Context) { forge.Refresh(c, _forge, _store, repoUser) prs, err := _forge.PullRequests(c, repoUser, repo, session.Pagination(c)) - if err != nil { + if errors.Is(err, forge_types.ErrNotImplemented) { + log.Debug().Msg("Could not fetch repo pull-request list as forge adapter did not implement it") + } else if err != nil { _ = c.AbortWithError(http.StatusInternalServerError, err) return } @@ -457,9 +468,19 @@ func DeleteRepo(c *gin.Context) { return } + forge.Refresh(c, _forge, _store, user) + if err := _forge.Deactivate(c, user, repo, server.Config.Server.WebhookHost); err != nil { - _ = c.AbortWithError(http.StatusInternalServerError, err) - return + log.Error().Err(err).Msgf("could not deactivate repo [%d] on forge", repo.ID) + + // in case we want to delete the repo on our side we should not worry to much on the forge side + // also if we get signalized that the repo on the forge is gone we can just ignore that + if errors.Is(err, forge_types.ErrRepoNotFound) || remove { + log.Debug().Msg("ignore deactivating repo on forge") + } else { + _ = c.AbortWithError(http.StatusInternalServerError, err) + return + } } if remove { @@ -522,6 +543,8 @@ func MoveRepo(c *gin.Context) { return } + forge.Refresh(c, _forge, _store, user) + to, exists := c.GetQuery("to") if !exists { err := fmt.Errorf("missing required to query value") @@ -559,6 +582,9 @@ func MoveRepo(c *gin.Context) { return } repo.Perm = from.Perm + repo.Perm.Synced = time.Now().Unix() + repo.Perm.UserID = user.ID + repo.Perm.RepoID = repo.ID errStore = _store.PermUpsert(repo.Perm) if errStore != nil { _ = c.AbortWithError(http.StatusInternalServerError, errStore) @@ -714,9 +740,10 @@ func repairRepo(c *gin.Context, repo *model.Repo, updatePermissions bool) error } if updatePermissions { - repo.Perm.Pull = from.Perm.Pull - repo.Perm.Push = from.Perm.Push - repo.Perm.Admin = from.Perm.Admin + repo.Perm = from.Perm + repo.Perm.Synced = time.Now().Unix() + repo.Perm.UserID = repoUser.ID + repo.Perm.RepoID = repo.ID if err := _store.PermUpsert(repo.Perm); err != nil { return err } diff --git a/server/api/repo_secret.go b/server/api/repo_secret.go index 59c73b4ff..6fe06bd9b 100644 --- a/server/api/repo_secret.go +++ b/server/api/repo_secret.go @@ -71,6 +71,7 @@ func PostSecret(c *gin.Context) { Value: in.Value, Events: in.Events, Images: in.Images, + Note: in.Note, } if err := secret.Validate(); err != nil { c.String(http.StatusUnprocessableEntity, "Error inserting secret. %s", err) @@ -92,17 +93,17 @@ func PostSecret(c *gin.Context) { // @Produce json // @Success 200 {object} Secret // @Tags Repository secrets -// @Param Authorization header string true "Insert your personal access token" default(Bearer ) -// @Param repo_id path int true "the repository id" -// @Param secretName path string true "the secret name" -// @Param secret body Secret true "the secret itself" +// @Param Authorization header string true "Insert your personal access token" default(Bearer ) +// @Param repo_id path int true "the repository id" +// @Param secretName path string true "the secret name" +// @Param secret body SecretPatch true "the secret itself" func PatchSecret(c *gin.Context) { var ( repo = session.Repo(c) name = c.Param("secret") ) - in := new(model.Secret) + in := new(model.SecretPatch) err := c.Bind(in) if err != nil { c.String(http.StatusBadRequest, "Error parsing secret. %s", err) @@ -115,8 +116,8 @@ func PatchSecret(c *gin.Context) { handleDBError(c, err) return } - if in.Value != "" { - secret.Value = in.Value + if in.Value != nil && *in.Value != "" { + secret.Value = *in.Value } if in.Events != nil { secret.Events = in.Events @@ -124,6 +125,9 @@ func PatchSecret(c *gin.Context) { if in.Images != nil { secret.Images = in.Images } + if in.Note != nil { + secret.Note = *in.Note + } if err := secret.Validate(); err != nil { c.String(http.StatusUnprocessableEntity, "Error updating secret. %s", err) diff --git a/server/api/user.go b/server/api/user.go index 9e048e6aa..8d69d1891 100644 --- a/server/api/user.go +++ b/server/api/user.go @@ -20,8 +20,8 @@ import ( "strconv" "github.com/gin-gonic/gin" - "github.com/google/tink/go/subtle/random" "github.com/rs/zerolog/log" + "github.com/tink-crypto/tink-go/v2/subtle/random" "go.woodpecker-ci.org/woodpecker/v3/server" "go.woodpecker-ci.org/woodpecker/v3/server/model" diff --git a/server/api/users.go b/server/api/users.go index 414cae651..872e95d1b 100644 --- a/server/api/users.go +++ b/server/api/users.go @@ -22,7 +22,7 @@ import ( "strconv" "github.com/gin-gonic/gin" - "github.com/google/tink/go/subtle/random" + "github.com/tink-crypto/tink-go/v2/subtle/random" "go.woodpecker-ci.org/woodpecker/v3/server/model" "go.woodpecker-ci.org/woodpecker/v3/server/router/middleware/session" diff --git a/server/badges/badges.go b/server/badges/badges.go index e05b356fb..57af0a706 100644 --- a/server/badges/badges.go +++ b/server/badges/badges.go @@ -14,33 +14,47 @@ package badges -import "go.woodpecker-ci.org/woodpecker/v3/server/model" +import ( + "github.com/rs/zerolog/log" -// cspell:words Verdana - -var ( - badgeSuccess = `pipeline: successpipelinesuccess` - badgeFailure = `pipeline: failurepipelinefailure` - badgeStarted = `pipeline: startedpipelinestarted` - badgeError = `pipeline: errorpipelineerror` - badgeNone = `pipeline: nonepipelinenone` + "go.woodpecker-ci.org/woodpecker/v3/server/model" ) -// Generate an SVG badge based on a pipeline. -func Generate(pipeline *model.Pipeline) string { - if pipeline == nil { - return badgeNone +var ( + // Status labels. + badgeStatusSuccess = "success" + badgeStatusFailure = "failure" + badgeStatusStarted = "started" + badgeStatusError = "error" + badgeStatusNone = "none" +) + +func getBadgeStatusLabelAndColor(status *model.StatusValue) (string, Color) { + if status == nil { + return badgeStatusNone, ColorGray } - switch pipeline.Status { + + switch *status { case model.StatusSuccess: - return badgeSuccess + return badgeStatusSuccess, ColorGreen case model.StatusFailure: - return badgeFailure - case model.StatusError, model.StatusKilled: - return badgeError + return badgeStatusFailure, ColorRed case model.StatusPending, model.StatusRunning: - return badgeStarted + return badgeStatusStarted, ColorYellow + case model.StatusError, model.StatusKilled: + return badgeStatusError, ColorGray default: - return badgeNone + return badgeStatusNone, ColorGray } } + +// Generate an SVG badge based on a pipeline. +func Generate(name string, status *model.StatusValue) (string, error) { + label, color := getBadgeStatusLabelAndColor(status) + bytes, err := RenderBytes(name, label, color) + if err != nil { + log.Warn().Err(err).Msg("could not render badge") + return "", err + } + return string(bytes), nil +} diff --git a/server/badges/badges_test.go b/server/badges/badges_test.go index 7829be16d..d2f6d1412 100644 --- a/server/badges/badges_test.go +++ b/server/badges/badges_test.go @@ -15,6 +15,10 @@ package badges import ( + "bytes" + "html/template" + "strings" + "sync" "testing" "github.com/stretchr/testify/assert" @@ -22,13 +26,89 @@ import ( "go.woodpecker-ci.org/woodpecker/v3/server/model" ) +var ( + badgeNone = `pipelinepipelinenonenone` + badgeSuccess = `pipelinepipelinesuccesssuccess` + badgeFailure = `pipelinepipelinefailurefailure` + badgeError = `pipelinepipelineerrorerror` + badgeStarted = `pipelinepipelinestartedstarted` +) + // Generate an SVG badge based on a pipeline. func TestGenerate(t *testing.T) { - assert.Equal(t, badgeNone, Generate(nil)) - assert.Equal(t, badgeSuccess, Generate(&model.Pipeline{Status: model.StatusSuccess})) - assert.Equal(t, badgeFailure, Generate(&model.Pipeline{Status: model.StatusFailure})) - assert.Equal(t, badgeError, Generate(&model.Pipeline{Status: model.StatusError})) - assert.Equal(t, badgeError, Generate(&model.Pipeline{Status: model.StatusKilled})) - assert.Equal(t, badgeStarted, Generate(&model.Pipeline{Status: model.StatusPending})) - assert.Equal(t, badgeStarted, Generate(&model.Pipeline{Status: model.StatusRunning})) + status := model.StatusDeclined + badge, err := Generate("pipeline", &status) + assert.NoError(t, err) + assert.Equal(t, badgeNone, badge) + status = model.StatusSuccess + badge, err = Generate("pipeline", &status) + assert.NoError(t, err) + assert.Equal(t, badgeSuccess, badge) + status = model.StatusFailure + badge, err = Generate("pipeline", &status) + assert.NoError(t, err) + assert.Equal(t, badgeFailure, badge) + status = model.StatusError + badge, err = Generate("pipeline", &status) + assert.NoError(t, err) + assert.Equal(t, badgeError, badge) + status = model.StatusKilled + badge, err = Generate("pipeline", &status) + assert.NoError(t, err) + assert.Equal(t, badgeError, badge) + status = model.StatusPending + badge, err = Generate("pipeline", &status) + assert.NoError(t, err) + assert.Equal(t, badgeStarted, badge) + status = model.StatusRunning + badge, err = Generate("pipeline", &status) + assert.NoError(t, err) + assert.Equal(t, badgeStarted, badge) +} + +func TestBadgeDrawerRender(t *testing.T) { + mockTemplate := strings.TrimSpace(` + {{.Subject}},{{.Status}},{{.Color}},{{with .Bounds}}{{.SubjectX}},{{.SubjectDx}},{{.StatusX}},{{.StatusDx}},{{.Dx}}{{end}} + `) + mockFontSize := 11.0 + mockDPI := 72.0 + + fd, err := mustNewFontDrawer(mockFontSize, mockDPI) + assert.NoError(t, err) + + d := &badgeDrawer{ + fd: fd, + tmpl: template.Must(template.New("mock-template").Parse(mockTemplate)), + mutex: &sync.Mutex{}, + } + + output := "XXX,YYY,#c0c0c0,15.5,29,41,26,55" + + var buf bytes.Buffer + assert.NoError(t, d.Render("XXX", "YYY", "#c0c0c0", &buf)) + assert.Equal(t, output, buf.String()) +} + +func TestBadgeDrawerRenderBytes(t *testing.T) { + mockTemplate := strings.TrimSpace(` + {{.Subject}},{{.Status}},{{.Color}},{{with .Bounds}}{{.SubjectX}},{{.SubjectDx}},{{.StatusX}},{{.StatusDx}},{{.Dx}}{{end}} + `) + mockFontSize := 11.0 + mockDPI := 72.0 + + fd, err := mustNewFontDrawer(mockFontSize, mockDPI) + assert.NoError(t, err) + + d := &badgeDrawer{ + fd: fd, + tmpl: template.Must(template.New("mock-template").Parse(mockTemplate)), + mutex: &sync.Mutex{}, + } + + output := "XXX,YYY,#c0c0c0,15.5,29,41,26,55" + + bytes, err := d.RenderBytes("XXX", "YYY", "#c0c0c0") + + assert.NoError(t, err) + assert.Equal(t, output, string(bytes)) } diff --git a/server/badges/color.go b/server/badges/color.go new file mode 100644 index 000000000..617ba2438 --- /dev/null +++ b/server/badges/color.go @@ -0,0 +1,15 @@ +// Copyright 2023 The narqo/go-badge Authors. All rights reserved. +// SPDX-License-Identifier: MIT. + +package badges + +// Color represents color of the badge. +type Color string + +// Standard colors. +const ( + ColorGreen = "#44cc11" + ColorYellow = "#dfb317" + ColorRed = "#e05d44" + ColorGray = "#9f9f9f" +) diff --git a/server/badges/drawer.go b/server/badges/drawer.go new file mode 100644 index 000000000..616a69cfa --- /dev/null +++ b/server/badges/drawer.go @@ -0,0 +1,137 @@ +// Copyright 2023 The narqo/go-badge Authors. All rights reserved. +// SPDX-License-Identifier: MIT. + +package badges + +// cspell:words Verdana + +import ( + "bytes" + "html/template" + "io" + "sync" + + "golang.org/x/image/font" + "golang.org/x/image/font/opentype" + "golang.org/x/image/font/sfnt" + + "go.woodpecker-ci.org/woodpecker/v3/server/badges/fonts" +) + +type badge struct { + Subject string + Status string + Color Color + Bounds bounds +} + +type bounds struct { + // SubjectDx is the width of subject string of the badge. + SubjectDx float64 + SubjectX float64 + // StatusDx is the width of status string of the badge. + StatusDx float64 + StatusX float64 +} + +func (b bounds) Dx() float64 { + return b.SubjectDx + b.StatusDx +} + +type badgeDrawer struct { + fd *font.Drawer + tmpl *template.Template + mutex *sync.Mutex +} + +func (d *badgeDrawer) Render(subject, status string, color Color, w io.Writer) error { + d.mutex.Lock() + subjectDx := d.measureString(subject) + statusDx := d.measureString(status) + d.mutex.Unlock() + + bdg := badge{ + Subject: subject, + Status: status, + Color: color, + Bounds: bounds{ + SubjectDx: subjectDx, + SubjectX: subjectDx/2.0 + 1, + StatusDx: statusDx, + StatusX: subjectDx + statusDx/2.0 - 1, + }, + } + return d.tmpl.Execute(w, bdg) +} + +func (d *badgeDrawer) RenderBytes(subject, status string, color Color) ([]byte, error) { + buf := &bytes.Buffer{} + err := d.Render(subject, status, color, buf) + return buf.Bytes(), err +} + +// shields.io uses Verdana.ttf to measure text width with an extra 10px. +// As we use DejaVuSans.ttf, we have to tune this value a little. +const extraDx = 5 + +func (d *badgeDrawer) measureString(s string) float64 { + SHIFT := 6 + return float64(d.fd.MeasureString(s)>>SHIFT) + extraDx +} + +// RenderBytes renders a badge of the given color, with given subject and status to bytes. +func RenderBytes(subject, status string, color Color) ([]byte, error) { + drawer, err := initDrawer() + if err != nil { + return nil, err + } + return drawer.RenderBytes(subject, status, color) +} + +const ( + dpi = 72 + fontSize = 11 +) + +var ( + drawer *badgeDrawer + initError error + initOnce sync.Once +) + +func initDrawer() (*badgeDrawer, error) { + initOnce.Do(func() { + fd, err := mustNewFontDrawer(fontSize, dpi) + if err != nil { + initError = err + return + } + drawer = &badgeDrawer{ + fd: fd, + tmpl: template.Must(template.New("flat-template").Parse(flatTemplate)), + mutex: &sync.Mutex{}, + } + initError = nil + }) + return drawer, initError +} + +func mustNewFontDrawer(size, dpi float64) (*font.Drawer, error) { + f, err := sfnt.Parse(fonts.DejaVuSans) + if err != nil { + return nil, err + } + + face, err := opentype.NewFace(f, &opentype.FaceOptions{ + Size: size, + DPI: dpi, + Hinting: font.HintingFull, + }) + if err != nil { + return nil, err + } + + return &font.Drawer{ + Face: face, + }, nil +} diff --git a/server/badges/fonts/DejaVuSans.ttf b/server/badges/fonts/DejaVuSans.ttf new file mode 100644 index 000000000..9d40c3256 Binary files /dev/null and b/server/badges/fonts/DejaVuSans.ttf differ diff --git a/server/badges/fonts/dejavusans.go b/server/badges/fonts/dejavusans.go new file mode 100644 index 000000000..0c5a0b916 --- /dev/null +++ b/server/badges/fonts/dejavusans.go @@ -0,0 +1,13 @@ +// Copyright 2023 The narqo/go-badge Authors. All rights reserved. +// SPDX-License-Identifier: MIT. + +package fonts + +import ( + _ "embed" +) + +// DejaVuSans is DejaVuSans.ttf font inlined to the bytes slice. +// +//go:embed DejaVuSans.ttf +var DejaVuSans []byte diff --git a/server/badges/style.go b/server/badges/style.go new file mode 100644 index 000000000..f09463f93 --- /dev/null +++ b/server/badges/style.go @@ -0,0 +1,8 @@ +// Copyright 2023 The narqo/go-badge Authors. All rights reserved. +// SPDX-License-Identifier: MIT. + +package badges + +// cspell:words Verdana + +var flatTemplate = `{{.Subject | html}}{{.Subject | html}}{{.Status | html}}{{.Status | html}}` diff --git a/server/cache/membership.go b/server/cache/membership.go index 0e7138eaa..cf1e09390 100644 --- a/server/cache/membership.go +++ b/server/cache/membership.go @@ -16,12 +16,15 @@ package cache import ( "context" + "errors" "fmt" "time" "github.com/jellydator/ttlcache/v3" + "github.com/rs/zerolog/log" "go.woodpecker-ci.org/woodpecker/v3/server/forge" + forge_types "go.woodpecker-ci.org/woodpecker/v3/server/forge/types" "go.woodpecker-ci.org/woodpecker/v3/server/model" "go.woodpecker-ci.org/woodpecker/v3/server/store" ) @@ -56,7 +59,10 @@ func (c *membershipCache) Get(ctx context.Context, _forge forge.Forge, u *model. } perm, err := _forge.OrgMembership(ctx, u, org) - if err != nil { + if errors.Is(err, forge_types.ErrNotImplemented) { + log.Debug().Msg("Could not check user org membership as forge adapter did not implement it") + return &model.OrgPerm{}, nil + } else if err != nil { return nil, err } c.cache.Set(key, perm, c.ttl) diff --git a/server/cron/cron.go b/server/cron/cron.go index 3460fbaa4..cb175b18b 100644 --- a/server/cron/cron.go +++ b/server/cron/cron.go @@ -121,7 +121,7 @@ func CreatePipeline(ctx context.Context, store store.Store, cron *model.Cron) (* cron.Branch = repo.Branch } - creator, err := store.GetUser(cron.CreatorID) + repoUser, err := store.GetUser(repo.UserID) if err != nil { return nil, nil, err } @@ -129,21 +129,22 @@ func CreatePipeline(ctx context.Context, store store.Store, cron *model.Cron) (* // If the forge has a refresh token, the current access token // may be stale. Therefore, we should refresh prior to dispatching // the pipeline. - forge.Refresh(ctx, _forge, store, creator) + forge.Refresh(ctx, _forge, store, repoUser) - commit, err := _forge.BranchHead(ctx, creator, repo, cron.Branch) + commit, err := _forge.BranchHead(ctx, repoUser, repo, cron.Branch) if err != nil { return nil, nil, err } return repo, &model.Pipeline{ - Event: model.EventCron, - Commit: commit.SHA, - Ref: "refs/heads/" + cron.Branch, - Branch: cron.Branch, - Message: cron.Name, - Timestamp: cron.NextExec, - Sender: cron.Name, - ForgeURL: commit.ForgeURL, + Event: model.EventCron, + Commit: commit.SHA, + Ref: "refs/heads/" + cron.Branch, + Branch: cron.Branch, + Message: cron.Name, + Timestamp: cron.NextExec, + Sender: cron.Name, + ForgeURL: commit.ForgeURL, + AdditionalVariables: cron.Variables, }, nil } diff --git a/server/cron/cron_test.go b/server/cron/cron_test.go index 2d47a4f82..c44d82aa1 100644 --- a/server/cron/cron_test.go +++ b/server/cron/cron_test.go @@ -34,7 +34,7 @@ func TestCreatePipeline(t *testing.T) { store := store_mocks.NewMockStore(t) ctx := t.Context() - creator := &model.User{ + repoUser := &model.User{ ID: 1, Login: "user1", } @@ -44,12 +44,13 @@ func TestCreatePipeline(t *testing.T) { Owner: "owner1", FullName: "repo1/owner1", Branch: "default", + UserID: repoUser.ID, } // mock things store.On("GetRepo", mock.Anything).Return(repo1, nil) - store.On("GetUser", mock.Anything).Return(creator, nil) - _forge.On("BranchHead", mock.Anything, creator, repo1, "default").Return(&model.Commit{ + store.On("GetUser", mock.Anything).Return(repoUser, nil) + _forge.On("BranchHead", mock.Anything, repoUser, repo1, "default").Return(&model.Commit{ ForgeURL: "https://example.com/sha1", SHA: "sha1", }, nil) diff --git a/server/forge/addon/client.go b/server/forge/addon/client.go index 507afb10f..c8b73fc2b 100644 --- a/server/forge/addon/client.go +++ b/server/forge/addon/client.go @@ -67,13 +67,19 @@ type RPC struct { func (g *RPC) Name() string { var resp string - _ = g.client.Call("Plugin.Name", nil, &resp) + err := g.client.Call("Plugin.Name", []byte{}, &resp) + if err != nil { + log.Error().Err(err).Msg("addon Plugin.Name call failed") + } return resp } func (g *RPC) URL() string { var resp string - _ = g.client.Call("Plugin.URL", nil, &resp) + err := g.client.Call("Plugin.URL", []byte{}, &resp) + if err != nil { + log.Error().Err(err).Msg("addon Plugin.URL call failed") + } return resp } diff --git a/server/forge/bitbucket/bitbucket.go b/server/forge/bitbucket/bitbucket.go index 6cd4713e8..930bf38fd 100644 --- a/server/forge/bitbucket/bitbucket.go +++ b/server/forge/bitbucket/bitbucket.go @@ -32,6 +32,7 @@ import ( "go.woodpecker-ci.org/woodpecker/v3/server/forge/common" forge_types "go.woodpecker-ci.org/woodpecker/v3/server/forge/types" "go.woodpecker-ci.org/woodpecker/v3/server/model" + "go.woodpecker-ci.org/woodpecker/v3/server/store" "go.woodpecker-ci.org/woodpecker/v3/shared/httputil" shared_utils "go.woodpecker-ci.org/woodpecker/v3/shared/utils" ) @@ -101,7 +102,21 @@ func (c *config) Login(ctx context.Context, req *forge_types.OAuthRequest) (*mod if err != nil { return nil, redirectURL, err } - return convertUser(curr, token), redirectURL, nil + + emails, err := client.ListEmail() + if err != nil { + return nil, redirectURL, err + } + + primaryEmail := "" + for _, e := range emails.Values { + if e.IsPrimary { + primaryEmail = e.Email + break + } + } + + return convertUser(curr, token, primaryEmail), redirectURL, nil } // Auth uses the Bitbucket oauth2 access token and refresh token to authenticate @@ -169,7 +184,7 @@ func (c *config) Repo(ctx context.Context, u *model.User, remoteID model.ForgeRe client := c.newClient(ctx, u) repo, err := client.FindRepo(owner, name) if err != nil { - return nil, err + return nil, errors.Join(err, forge_types.ErrRepoNotFound) } perm, err := client.GetPermission(repo.FullName) if err != nil { @@ -181,6 +196,12 @@ func (c *config) Repo(ctx context.Context, u *model.User, remoteID model.ForgeRe // Repos returns a list of all repositories for Bitbucket account, including // organization repositories. func (c *config) Repos(ctx context.Context, u *model.User, p *model.ListOptions) ([]*model.Repo, error) { + // we paginate internally (https://github.com/woodpecker-ci/woodpecker/issues/5667) + // we merge data from different sources + if p.Page != 1 { + return nil, nil + } + setListOptions(p) client := c.newClient(ctx, u) @@ -322,6 +343,11 @@ func (c *config) Activate(ctx context.Context, u *model.User, r *model.Repo, lin func (c *config) Deactivate(ctx context.Context, u *model.User, r *model.Repo, link string) error { client := c.newClient(ctx, u) + // check repo exists + if _, err := c.Repo(ctx, u, r.ForgeRemoteID, r.Owner, r.Name); err != nil { + return fmt.Errorf("repo online check failed: %w", err) + } + hooks, err := shared_utils.Paginate(func(page int) ([]*internal.Hook, error) { hooks, err := client.ListHooks(r.Owner, r.Name, &internal.ListOpts{ Page: page, @@ -412,6 +438,14 @@ func (c *config) Hook(ctx context.Context, req *http.Request) (*model.Repo, *mod return nil, nil, err } + // Refresh the OAuth token before making API calls. + // The token may be expired, and without this refresh the API calls below + // would fail with "OAuth2 access token expired" error. + _store, ok := store.TryFromContext(ctx) + if ok { + forge.Refresh(ctx, c, _store, u) + } + switch pl.Event { case model.EventPush: // List only the latest push changes diff --git a/server/forge/bitbucket/convert.go b/server/forge/bitbucket/convert.go index ae9348818..e4b30d17e 100644 --- a/server/forge/bitbucket/convert.go +++ b/server/forge/bitbucket/convert.go @@ -126,7 +126,7 @@ func sshCloneLink(repo *internal.Repo) string { // convertUser is a helper function used to convert a Bitbucket user account // structure to the Woodpecker User structure. -func convertUser(from *internal.Account, token *oauth2.Token) *model.User { +func convertUser(from *internal.Account, token *oauth2.Token, email string) *model.User { return &model.User{ Login: from.Login, AccessToken: token.AccessToken, @@ -134,6 +134,7 @@ func convertUser(from *internal.Account, token *oauth2.Token) *model.User { Expiry: token.Expiry.UTC().Unix(), Avatar: from.Links.Avatar.Href, ForgeRemoteID: model.ForgeRemoteID(fmt.Sprint(from.UUID)), + Email: email, } } diff --git a/server/forge/bitbucket/convert_test.go b/server/forge/bitbucket/convert_test.go index 5f450cc03..cf9b04fe9 100644 --- a/server/forge/bitbucket/convert_test.go +++ b/server/forge/bitbucket/convert_test.go @@ -86,9 +86,10 @@ func Test_convertUser(t *testing.T) { user := &internal.Account{Login: "octocat"} user.Links.Avatar.Href = "http://..." - result := convertUser(user, token) + result := convertUser(user, token, "test@example.com") assert.Equal(t, user.Links.Avatar.Href, result.Avatar) assert.Equal(t, user.Login, result.Login) + assert.Equal(t, "test@example.com", result.Email) assert.Equal(t, token.AccessToken, result.AccessToken) assert.Equal(t, token.RefreshToken, result.RefreshToken) assert.Equal(t, token.Expiry.UTC().Unix(), result.Expiry) diff --git a/server/forge/bitbucket/fixtures/handler.go b/server/forge/bitbucket/fixtures/handler.go index 85ed8fcdc..ce95e7409 100644 --- a/server/forge/bitbucket/fixtures/handler.go +++ b/server/forge/bitbucket/fixtures/handler.go @@ -37,6 +37,7 @@ func Handler() http.Handler { e.POST("/2.0/repositories/:owner/:name/commit/:commit/statuses/build", createRepoStatus) e.GET("/2.0/repositories/:owner", getUserRepos) e.GET("/2.0/user/", getUser) + e.GET("/2.0/user/emails", getEmails) e.GET("/2.0/user/permissions/repositories", getPermissions) e.GET("/2.0/repositories/:owner/:name/commits/:commit", getBranchHead) e.GET("/2.0/repositories/:owner/:name/pullrequests", getPullRequests) @@ -179,6 +180,15 @@ func getUser(c *gin.Context) { } } +func getEmails(c *gin.Context) { + switch c.Request.Header.Get("Authorization") { + case "Bearer user_not_found", "Bearer a87ff679": + c.String(http.StatusNotFound, "") + default: + c.String(http.StatusOK, emailsPayload) + } +} + func getUserRepos(c *gin.Context) { switch c.Request.Header.Get("Authorization") { case "Bearer repos_not_found", "Bearer 70efdf2e": @@ -220,162 +230,162 @@ const tokenNotFoundPayload = ` const repoPayload = ` { - "full_name": "test_name/repo_name", - "scm": "git", - "is_private": true + "full_name": "test_name/repo_name", + "scm": "git", + "is_private": true } ` const permissionRepoPayload = ` { - "full_name": "test_name/%s", - "scm": "git", - "is_private": true + "full_name": "test_name/%s", + "scm": "git", + "is_private": true } ` const repoPayloadFromHook = ` { - "type": "repository", - "full_name": "martinherren1984/publictestrepo", - "links": { - "self": { - "href": "https://api.bitbucket.org/2.0/repositories/martinherren1984/publictestrepo" - }, - "html": { - "href": "https://bitbucket.org/martinherren1984/publictestrepo" - }, - "avatar": { - "href": "https://bytebucket.org/ravatar/%7B898477b2-a080-4089-b385-597a783db392%7D?ts=default" - }, - "pullrequests": { - "href": "https://api.bitbucket.org/2.0/repositories/martinherren1984/publictestrepo/pullrequests" - }, - "commits": { - "href": "https://api.bitbucket.org/2.0/repositories/martinherren1984/publictestrepo/commits" - }, - "forks": { - "href": "https://api.bitbucket.org/2.0/repositories/martinherren1984/publictestrepo/forks" - }, - "watchers": { - "href": "https://api.bitbucket.org/2.0/repositories/martinherren1984/publictestrepo/watchers" - }, - "branches": { - "href": "https://api.bitbucket.org/2.0/repositories/martinherren1984/publictestrepo/refs/branches" - }, - "tags": { - "href": "https://api.bitbucket.org/2.0/repositories/martinherren1984/publictestrepo/refs/tags" - }, - "downloads": { - "href": "https://api.bitbucket.org/2.0/repositories/martinherren1984/publictestrepo/downloads" - }, - "source": { - "href": "https://api.bitbucket.org/2.0/repositories/martinherren1984/publictestrepo/src" - }, - "clone": [ - { - "name": "https", - "href": "https://bitbucket.org/martinherren1984/publictestrepo.git" - }, - { - "name": "ssh", - "href": "git@bitbucket.org:martinherren1984/publictestrepo.git" - } - ], - "hooks": { - "href": "https://api.bitbucket.org/2.0/repositories/martinherren1984/publictestrepo/hooks" - } - }, - "name": "PublicTestRepo", - "slug": "publictestrepo", - "description": "", - "scm": "git", - "website": null, - "owner": { - "display_name": "Martin Herren", - "links": { - "self": { - "href": "https://api.bitbucket.org/2.0/users/%7Bc5a0d676-fd27-4bd4-ac69-a7540d7b495b%7D" - }, - "avatar": { - "href": "https://secure.gravatar.com/avatar/37de364488b2ec474b5458ca86442bbb?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FMH-2.png" - }, - "html": { - "href": "https://bitbucket.org/%7Bc5a0d676-fd27-4bd4-ac69-a7540d7b495b%7D/" - } - }, - "type": "user", - "uuid": "{c5a0d676-fd27-4bd4-ac69-a7540d7b495b}", - "account_id": "5cf8e3a9678ca90f8e7cc8a8", - "nickname": "Martin Herren" - }, - "workspace": { - "type": "workspace", - "uuid": "{c5a0d676-fd27-4bd4-ac69-a7540d7b495b}", - "name": "Martin Herren", - "slug": "martinherren1984", - "links": { - "avatar": { - "href": "https://bitbucket.org/workspaces/martinherren1984/avatar/?ts=1658761964" - }, - "html": { - "href": "https://bitbucket.org/martinherren1984/" - }, - "self": { - "href": "https://api.bitbucket.org/2.0/workspaces/martinherren1984" - } - } - }, - "is_private": false, - "project": { - "type": "project", - "key": "PUB", - "uuid": "{2cede481-f59e-49ec-88d0-a85629b7925d}", - "name": "PublicTestProject", - "links": { - "self": { - "href": "https://api.bitbucket.org/2.0/workspaces/martinherren1984/projects/PUB" - }, - "html": { - "href": "https://bitbucket.org/martinherren1984/workspace/projects/PUB" - }, - "avatar": { - "href": "https://bitbucket.org/martinherren1984/workspace/projects/PUB/avatar/32?ts=1658768453" - } - } - }, - "fork_policy": "allow_forks", - "created_on": "2022-07-25T17:01:20.950706+00:00", - "updated_on": "2022-09-07T20:19:30.622886+00:00", - "size": 85955, - "language": "", - "uuid": "{898477b2-a080-4089-b385-597a783db392}", - "mainbranch": { - "name": "master", - "type": "branch" - }, - "override_settings": { - "default_merge_strategy": true, - "branching_model": true - }, - "parent": null, - "enforced_signed_commits": null, - "has_issues": false, - "has_wiki": false + "type": "repository", + "full_name": "martinherren1984/publictestrepo", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/repositories/martinherren1984/publictestrepo" + }, + "html": { + "href": "https://bitbucket.org/martinherren1984/publictestrepo" + }, + "avatar": { + "href": "https://bytebucket.org/ravatar/%7B898477b2-a080-4089-b385-597a783db392%7D?ts=default" + }, + "pullrequests": { + "href": "https://api.bitbucket.org/2.0/repositories/martinherren1984/publictestrepo/pullrequests" + }, + "commits": { + "href": "https://api.bitbucket.org/2.0/repositories/martinherren1984/publictestrepo/commits" + }, + "forks": { + "href": "https://api.bitbucket.org/2.0/repositories/martinherren1984/publictestrepo/forks" + }, + "watchers": { + "href": "https://api.bitbucket.org/2.0/repositories/martinherren1984/publictestrepo/watchers" + }, + "branches": { + "href": "https://api.bitbucket.org/2.0/repositories/martinherren1984/publictestrepo/refs/branches" + }, + "tags": { + "href": "https://api.bitbucket.org/2.0/repositories/martinherren1984/publictestrepo/refs/tags" + }, + "downloads": { + "href": "https://api.bitbucket.org/2.0/repositories/martinherren1984/publictestrepo/downloads" + }, + "source": { + "href": "https://api.bitbucket.org/2.0/repositories/martinherren1984/publictestrepo/src" + }, + "clone": [ + { + "name": "https", + "href": "https://bitbucket.org/martinherren1984/publictestrepo.git" + }, + { + "name": "ssh", + "href": "git@bitbucket.org:martinherren1984/publictestrepo.git" + } + ], + "hooks": { + "href": "https://api.bitbucket.org/2.0/repositories/martinherren1984/publictestrepo/hooks" + } + }, + "name": "PublicTestRepo", + "slug": "publictestrepo", + "description": "", + "scm": "git", + "website": null, + "owner": { + "display_name": "Martin Herren", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/users/%7Bc5a0d676-fd27-4bd4-ac69-a7540d7b495b%7D" + }, + "avatar": { + "href": "https://secure.gravatar.com/avatar/37de364488b2ec474b5458ca86442bbb?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FMH-2.png" + }, + "html": { + "href": "https://bitbucket.org/%7Bc5a0d676-fd27-4bd4-ac69-a7540d7b495b%7D/" + } + }, + "type": "user", + "uuid": "{c5a0d676-fd27-4bd4-ac69-a7540d7b495b}", + "account_id": "5cf8e3a9678ca90f8e7cc8a8", + "nickname": "Martin Herren" + }, + "workspace": { + "type": "workspace", + "uuid": "{c5a0d676-fd27-4bd4-ac69-a7540d7b495b}", + "name": "Martin Herren", + "slug": "martinherren1984", + "links": { + "avatar": { + "href": "https://bitbucket.org/workspaces/martinherren1984/avatar/?ts=1658761964" + }, + "html": { + "href": "https://bitbucket.org/martinherren1984/" + }, + "self": { + "href": "https://api.bitbucket.org/2.0/workspaces/martinherren1984" + } + } + }, + "is_private": false, + "project": { + "type": "project", + "key": "PUB", + "uuid": "{2cede481-f59e-49ec-88d0-a85629b7925d}", + "name": "PublicTestProject", + "links": { + "self": { + "href": "https://api.bitbucket.org/2.0/workspaces/martinherren1984/projects/PUB" + }, + "html": { + "href": "https://bitbucket.org/martinherren1984/workspace/projects/PUB" + }, + "avatar": { + "href": "https://bitbucket.org/martinherren1984/workspace/projects/PUB/avatar/32?ts=1658768453" + } + } + }, + "fork_policy": "allow_forks", + "created_on": "2022-07-25T17:01:20.950706+00:00", + "updated_on": "2022-09-07T20:19:30.622886+00:00", + "size": 85955, + "language": "", + "uuid": "{898477b2-a080-4089-b385-597a783db392}", + "mainbranch": { + "name": "master", + "type": "branch" + }, + "override_settings": { + "default_merge_strategy": true, + "branching_model": true + }, + "parent": null, + "enforced_signed_commits": null, + "has_issues": false, + "has_wiki": false } ` const repoHookPayload = ` { - "pagelen": 10, - "values": [ - { - "uuid": "{afe61e14-2c5f-49e8-8b68-ad1fb55fc052}", - "url": "http://127.0.0.1" - } - ], - "page": 1, - "size": 1 + "pagelen": 10, + "values": [ + { + "uuid": "{afe61e14-2c5f-49e8-8b68-ad1fb55fc052}", + "url": "http://127.0.0.1" + } + ], + "page": 1, + "size": 1 } ` @@ -383,168 +393,183 @@ const repoFilePayload = "dummy payload" const repoDirPayload = ` { - "pagelen": 10, - "page": 1, - "values": [ - { - "path": "README.md", - "type": "commit_file" - }, - { - "path": "test", - "type": "commit_directory" - }, - { - "path": ".gitignore", - "type": "commit_file" - } - ] + "pagelen": 10, + "page": 1, + "values": [ + { + "path": "README.md", + "type": "commit_file" + }, + { + "path": "test", + "type": "commit_directory" + }, + { + "path": ".gitignore", + "type": "commit_file" + } + ] } ` const branchCommitsPayload = ` { - "values": [ - { - "hash": "branch_head_name", + "values": [ + { + "hash": "branch_head_name", "links": { "html": { "href": "https://bitbucket.org/commitlink" } } - }, - { - "hash": "random1" - }, - { - "hash": "random2" - } - ] + }, + { + "hash": "random1" + }, + { + "hash": "random2" + } + ] } ` const pullRequestsPayload = ` { - "values": [ - { - "id": 123, + "values": [ + { + "id": 123, "title": "PRs title" - }, - { - "id": 456, + }, + { + "id": 456, "title": "Another PRs title" - } - ], + } + ], "pagelen": 10, - "size": 2, - "page": 1 + "size": 2, + "page": 1 } ` const diffStatPayload = ` { - "values": [ - { - "old": { - "path": "main.go" - }, - "new": { - "path": "main.go" - } - } - ] + "values": [ + { + "old": { + "path": "main.go" + }, + "new": { + "path": "main.go" + } + } + ] } ` const userPayload = ` { "uuid": "{4d8c0f46-cd62-4b77-b0cf-faa3e4d932c6}", - "username": "superman", - "links": { - "avatar": { - "href": "http:\/\/i.imgur.com\/ZygP55A.jpg" - } - }, - "type": "user" + "username": "superman", + "links": { + "avatar": { + "href": "http:\/\/i.imgur.com\/ZygP55A.jpg" + } + }, + "type": "user" } ` const userRepoPayload = ` { - "page": 1, + "page": 1, + "pagelen": 10, + "size": 1, + "values": [ + { + "links": { + "avatar": { + "href": "http:\/\/i.imgur.com\/ZygP55A.jpg" + } + }, + "full_name": "test_name/repo_name", + "scm": "git", + "is_private": true + } + ] +} +` + +const emailsPayload = ` +{ "pagelen": 10, - "size": 1, "values": [ { - "links": { - "avatar": { - "href": "http:\/\/i.imgur.com\/ZygP55A.jpg" - } - }, - "full_name": "test_name/repo_name", - "scm": "git", - "is_private": true - } - ] + "email": "test@example.com", + "is_confirmed": true, + "is_primary": true + } + ], + "page": 1, + "size": 1 } ` const workspacesPayload = ` { "page": 1, - "pagelen": 100, + "pagelen": 100, "size": 1, - "values": [ - { + "values": [ + { "type": "workspace", "uuid": "{c7a04a76-fa20-43e4-dc42-a7506db4c95b}", "name": "Ueber Dev", "slug": "ueberdev42", - "links": { + "links": { "avatar": { - "href": "https://bitbucket.org/workspaces/ueberdev42/avatar/?ts=1658761964" - }, - "html": { - "href": "https://bitbucket.org/ueberdev42/" - }, - "self": { - "href": "https://api.bitbucket.org/2.0/workspaces/ueberdev42" - } - } - } - ] + "href": "https://bitbucket.org/workspaces/ueberdev42/avatar/?ts=1658761964" + }, + "html": { + "href": "https://bitbucket.org/ueberdev42/" + }, + "self": { + "href": "https://api.bitbucket.org/2.0/workspaces/ueberdev42" + } + } + } + ] } ` const permissionsPayLoad = ` { - "pagelen": 100, + "pagelen": 100, "page": 1, - "values": [ - { - "repository": { - "full_name": "test_name/repo_name" - }, - "permission": "read" - }, + "values": [ { - "repository": { - "full_name": "test_name/permission_read" - }, - "permission": "read" - }, + "repository": { + "full_name": "test_name/repo_name" + }, + "permission": "read" + }, { - "repository": { - "full_name": "test_name/permission_write" - }, - "permission": "write" - }, + "repository": { + "full_name": "test_name/permission_read" + }, + "permission": "read" + }, { - "repository": { - "full_name": "test_name/permission_admin" - }, - "permission": "admin" - } - ] + "repository": { + "full_name": "test_name/permission_write" + }, + "permission": "write" + }, + { + "repository": { + "full_name": "test_name/permission_admin" + }, + "permission": "admin" + } + ] } ` diff --git a/server/forge/bitbucket/parse.go b/server/forge/bitbucket/parse.go index f21699692..445f9082d 100644 --- a/server/forge/bitbucket/parse.go +++ b/server/forge/bitbucket/parse.go @@ -31,7 +31,6 @@ const ( hookPullUpdated = "pullrequest:updated" hookPullMerged = "pullrequest:fulfilled" hookPullDeclined = "pullrequest:rejected" - stateOpen = "OPEN" stateClosed = "MERGED" stateDeclined = "DECLINED" ) diff --git a/server/forge/bitbucketdatacenter/bitbucketdatacenter.go b/server/forge/bitbucketdatacenter/bitbucketdatacenter.go index d530ea2b8..f182b3788 100644 --- a/server/forge/bitbucketdatacenter/bitbucketdatacenter.go +++ b/server/forge/bitbucketdatacenter/bitbucketdatacenter.go @@ -192,12 +192,12 @@ func (c *client) Repo(ctx context.Context, u *model.User, rID model.ForgeRemoteI opts.Start = resp.NextPageStart } if repo == nil { - return nil, fmt.Errorf("unable to find repository with id: %s", rID) + return nil, fmt.Errorf("%w: unable to find repository with id: %s", forge_types.ErrRepoNotFound, rID) } } else { repo, _, err = bc.Projects.GetRepository(ctx, owner, name) if err != nil { - return nil, fmt.Errorf("unable to get repository: %w", err) + return nil, fmt.Errorf("%w: unable to get repository: %w", forge_types.ErrRepoNotFound, err) } } @@ -466,6 +466,11 @@ func (c *client) Deactivate(ctx context.Context, u *model.User, r *model.Repo, l return fmt.Errorf("unable to create bitbucket client: %w", err) } + // check repo exists + if _, err := c.Repo(ctx, u, r.ForgeRemoteID, r.Owner, r.Name); err != nil { + return fmt.Errorf("repo online check failed: %w", err) + } + lu, err := url.Parse(link) if err != nil { return err diff --git a/server/forge/forge.go b/server/forge/forge.go index fb5adb474..3f322e178 100644 --- a/server/forge/forge.go +++ b/server/forge/forge.go @@ -51,6 +51,7 @@ import ( // Error Handling: // - types.ErrIgnoreEvent: Skippable webhook events // - types.RecordNotExist: Resource not found +// - types.ErrNotImplemented: Can be used to signal it's not supported // - nil Repo/Pipeline: "No action needed" (not an error). type Forge interface { // Name returns the unique identifier of this forge driver. @@ -76,9 +77,11 @@ type Forge interface { Auth(ctx context.Context, token, secret string) (string, error) // Teams fetches all team/organization memberships for a user. - // May return empty slice if forge doesn't support teams/organizations. // Used to determine if an user is member of an team/organization. // Should support pagination via ListOptions. + // + // Errors: + // - Expect types.ErrNotImplemented to be returned if forge doesn't support teams/organizations. Teams(ctx context.Context, u *model.User, p *model.ListOptions) ([]*model.Team, error) // Repo fetches a single repository. @@ -105,6 +108,9 @@ type Forge interface { // Dir fetches all files in a directory at a specific commit. // Supports pipeline configurations split across multiple files. // Should return files only. + // + // Errors: + // - Expect types.ErrNotImplemented to be returned if not supported by the forge Dir(ctx context.Context, u *model.User, r *model.Repo, b *model.Pipeline, dirName string) ([]*types.FileMeta, error) // Status sends workflow status updates to the forge. @@ -128,13 +134,20 @@ type Forge interface { // Branches returns all branch names in the repository. // Should support pagination via ListOptions. + // + // Errors: + // - Expect types.ErrNotImplemented to be returned if not supported by the forge Branches(ctx context.Context, u *model.User, r *model.Repo, p *model.ListOptions) ([]string, error) // BranchHead returns the latest commit SHA for a branch. + // Is essential for cron feature to work. BranchHead(ctx context.Context, u *model.User, r *model.Repo, branch string) (*model.Commit, error) // PullRequests returns all open pull requests. // Should support pagination via ListOptions. + // + // Errors: + // - Expect types.ErrNotImplemented to be returned if not supported by the forge PullRequests(ctx context.Context, u *model.User, r *model.Repo, p *model.ListOptions) ([]*model.PullRequest, error) // Hook parses incoming webhook and returns pipeline data. @@ -157,6 +170,9 @@ type Forge interface { // OrgMembership checks if user is member of organization and their permission. // Should return (Member: false, Admin: false) if not a member. + // + // Errors: + // - Expect types.ErrNotImplemented to be returned if not supported by the forge OrgMembership(ctx context.Context, u *model.User, org string) (*model.OrgPerm, error) // Org fetches organization details. diff --git a/server/forge/forgejo/fixtures/handler.go b/server/forge/forgejo/fixtures/handler.go index 73c3a9eb7..68e2d8590 100644 --- a/server/forge/forgejo/fixtures/handler.go +++ b/server/forge/forgejo/fixtures/handler.go @@ -139,34 +139,34 @@ func getPRFiles(c *gin.Context) { const listRepoHookPayloads = ` [ - { - "id": 1, - "type": "forgejo", - "config": { - "content_type": "json", - "url": "http:\/\/localhost\/hook?access_token=1234567890" - } - } + { + "id": 1, + "type": "forgejo", + "config": { + "content_type": "json", + "url": "http:\/\/localhost\/hook?access_token=1234567890" + } + } ] ` const repoPayload = ` { "id": 5, - "owner": { - "login": "test_name", - "email": "octocat@github.com", - "avatar_url": "https:\/\/secure.gravatar.com\/avatar\/8c58a0be77ee441bb8f8595b7f1b4e87" - }, - "full_name": "test_name\/repo_name", - "private": true, - "html_url": "http:\/\/localhost\/test_name\/repo_name", - "clone_url": "http:\/\/localhost\/test_name\/repo_name.git", - "permissions": { - "admin": true, - "push": true, - "pull": true - } + "owner": { + "login": "test_name", + "email": "octocat@github.com", + "avatar_url": "https:\/\/secure.gravatar.com\/avatar\/8c58a0be77ee441bb8f8595b7f1b4e87" + }, + "full_name": "test_name\/repo_name", + "private": true, + "html_url": "http:\/\/localhost\/test_name\/repo_name", + "clone_url": "http:\/\/localhost\/test_name\/repo_name.git", + "permissions": { + "admin": true, + "push": true, + "pull": true + } } ` @@ -174,37 +174,37 @@ const repoFilePayload = `{ platform: linux/amd64 }` const userRepoPayload = ` [ - { + { "id": 5, - "owner": { - "login": "test_name", - "email": "octocat@github.com", - "avatar_url": "https:\/\/secure.gravatar.com\/avatar\/8c58a0be77ee441bb8f8595b7f1b4e87" - }, - "full_name": "test_name\/repo_name", - "private": true, - "html_url": "http:\/\/localhost\/test_name\/repo_name", - "clone_url": "http:\/\/localhost\/test_name\/repo_name.git", - "permissions": { - "admin": true, - "push": true, - "pull": true - } - } + "owner": { + "login": "test_name", + "email": "octocat@github.com", + "avatar_url": "https:\/\/secure.gravatar.com\/avatar\/8c58a0be77ee441bb8f8595b7f1b4e87" + }, + "full_name": "test_name\/repo_name", + "private": true, + "html_url": "http:\/\/localhost\/test_name\/repo_name", + "clone_url": "http:\/\/localhost\/test_name\/repo_name.git", + "permissions": { + "admin": true, + "push": true, + "pull": true + } + } ] ` const prFilesPayload = ` [ - { - "filename": "README.md", - "status": "changed", - "additions": 2, - "deletions": 0, - "changes": 2, - "html_url": "http://localhost/username/repo/src/commit/e79e4b0e8d9dd6f72b70e776c3317db7c19ca0fd/README.md", - "contents_url": "http://localhost:3000/api/v1/repos/username/repo/contents/README.md?ref=e79e4b0e8d9dd6f72b70e776c3317db7c19ca0fd", - "raw_url": "http://localhost/username/repo/raw/commit/e79e4b0e8d9dd6f72b70e776c3317db7c19ca0fd/README.md" - } + { + "filename": "README.md", + "status": "changed", + "additions": 2, + "deletions": 0, + "changes": 2, + "html_url": "http://localhost/username/repo/src/commit/e79e4b0e8d9dd6f72b70e776c3317db7c19ca0fd/README.md", + "contents_url": "http://localhost:3000/api/v1/repos/username/repo/contents/README.md?ref=e79e4b0e8d9dd6f72b70e776c3317db7c19ca0fd", + "raw_url": "http://localhost/username/repo/raw/commit/e79e4b0e8d9dd6f72b70e776c3317db7c19ca0fd/README.md" + } ] ` diff --git a/server/forge/forgejo/forgejo.go b/server/forge/forgejo/forgejo.go index 689f73a26..2d86e7e2c 100644 --- a/server/forge/forgejo/forgejo.go +++ b/server/forge/forgejo/forgejo.go @@ -227,15 +227,21 @@ func (c *Forgejo) Repo(ctx context.Context, u *model.User, remoteID model.ForgeR if err != nil { return nil, err } - repo, _, err := client.GetRepoByID(intID) + repo, resp, err := client.GetRepoByID(intID) if err != nil { + if resp != nil && resp.StatusCode == http.StatusNotFound { + return nil, errors.Join(err, forge_types.ErrRepoNotFound) + } return nil, err } return toRepo(repo), nil } - repo, _, err := client.GetRepo(owner, name) + repo, resp, err := client.GetRepo(owner, name) if err != nil { + if resp != nil && resp.StatusCode == http.StatusNotFound { + return nil, errors.Join(err, forge_types.ErrRepoNotFound) + } return nil, err } return toRepo(repo), nil @@ -412,8 +418,14 @@ func (c *Forgejo) Deactivate(ctx context.Context, u *model.User, r *model.Repo, return err } + // make sure a repo rename does not trick us + forgeRepo, err := c.Repo(ctx, u, r.ForgeRemoteID, r.Owner, r.Name) + if err != nil { + return err + } + hooks, err := shared_utils.Paginate(func(page int) ([]*forgejo.Hook, error) { - hooks, _, err := client.ListRepoHooks(r.Owner, r.Name, forgejo.ListHooksOptions{ + hooks, _, err := client.ListRepoHooks(forgeRepo.Owner, forgeRepo.Name, forgejo.ListHooksOptions{ ListOptions: forgejo.ListOptions{ Page: page, PageSize: c.perPage(ctx), @@ -427,7 +439,7 @@ func (c *Forgejo) Deactivate(ctx context.Context, u *model.User, r *model.Repo, hook := matchingHooks(hooks, link) if hook != nil { - _, err := client.DeleteRepoHook(r.Owner, r.Name, hook.ID) + _, err := client.DeleteRepoHook(forgeRepo.Owner, forgeRepo.Name, hook.ID) return err } @@ -640,6 +652,8 @@ func (c *Forgejo) getChangedFilesForPR(ctx context.Context, repo *model.Repo, in return nil, err } + forge.Refresh(ctx, c, _store, user) + client, err := c.newClientToken(ctx, user.AccessToken) if err != nil { return nil, err @@ -677,6 +691,8 @@ func (c *Forgejo) getTagCommitSHA(ctx context.Context, repo *model.Repo, tagName return "", err } + forge.Refresh(ctx, c, _store, user) + client, err := c.newClientToken(ctx, user.AccessToken) if err != nil { return "", err diff --git a/server/forge/gitea/fixtures/handler.go b/server/forge/gitea/fixtures/handler.go index 7bc2bbb42..9545a0230 100644 --- a/server/forge/gitea/fixtures/handler.go +++ b/server/forge/gitea/fixtures/handler.go @@ -139,34 +139,34 @@ func getPRFiles(c *gin.Context) { const listRepoHookPayloads = ` [ - { - "id": 1, - "type": "gitea", - "config": { - "content_type": "json", - "url": "http:\/\/localhost\/hook?access_token=1234567890" - } - } + { + "id": 1, + "type": "gitea", + "config": { + "content_type": "json", + "url": "http:\/\/localhost\/hook?access_token=1234567890" + } + } ] ` const repoPayload = ` { "id": 5, - "owner": { - "login": "test_name", - "email": "octocat@github.com", - "avatar_url": "https:\/\/secure.gravatar.com\/avatar\/8c58a0be77ee441bb8f8595b7f1b4e87" - }, - "full_name": "test_name\/repo_name", - "private": true, - "html_url": "http:\/\/localhost\/test_name\/repo_name", - "clone_url": "http:\/\/localhost\/test_name\/repo_name.git", - "permissions": { - "admin": true, - "push": true, - "pull": true - } + "owner": { + "login": "test_name", + "email": "octocat@github.com", + "avatar_url": "https:\/\/secure.gravatar.com\/avatar\/8c58a0be77ee441bb8f8595b7f1b4e87" + }, + "full_name": "test_name\/repo_name", + "private": true, + "html_url": "http:\/\/localhost\/test_name\/repo_name", + "clone_url": "http:\/\/localhost\/test_name\/repo_name.git", + "permissions": { + "admin": true, + "push": true, + "pull": true + } } ` @@ -174,37 +174,37 @@ const repoFilePayload = `{ platform: linux/amd64 }` const userRepoPayload = ` [ - { + { "id": 5, - "owner": { - "login": "test_name", - "email": "octocat@github.com", - "avatar_url": "https:\/\/secure.gravatar.com\/avatar\/8c58a0be77ee441bb8f8595b7f1b4e87" - }, - "full_name": "test_name\/repo_name", - "private": true, - "html_url": "http:\/\/localhost\/test_name\/repo_name", - "clone_url": "http:\/\/localhost\/test_name\/repo_name.git", - "permissions": { - "admin": true, - "push": true, - "pull": true - } - } + "owner": { + "login": "test_name", + "email": "octocat@github.com", + "avatar_url": "https:\/\/secure.gravatar.com\/avatar\/8c58a0be77ee441bb8f8595b7f1b4e87" + }, + "full_name": "test_name\/repo_name", + "private": true, + "html_url": "http:\/\/localhost\/test_name\/repo_name", + "clone_url": "http:\/\/localhost\/test_name\/repo_name.git", + "permissions": { + "admin": true, + "push": true, + "pull": true + } + } ] ` const prFilesPayload = ` [ - { - "filename": "README.md", - "status": "changed", - "additions": 2, - "deletions": 0, - "changes": 2, - "html_url": "http://localhost/username/repo/src/commit/e79e4b0e8d9dd6f72b70e776c3317db7c19ca0fd/README.md", - "contents_url": "http://localhost:3000/api/v1/repos/username/repo/contents/README.md?ref=e79e4b0e8d9dd6f72b70e776c3317db7c19ca0fd", - "raw_url": "http://localhost/username/repo/raw/commit/e79e4b0e8d9dd6f72b70e776c3317db7c19ca0fd/README.md" - } + { + "filename": "README.md", + "status": "changed", + "additions": 2, + "deletions": 0, + "changes": 2, + "html_url": "http://localhost/username/repo/src/commit/e79e4b0e8d9dd6f72b70e776c3317db7c19ca0fd/README.md", + "contents_url": "http://localhost:3000/api/v1/repos/username/repo/contents/README.md?ref=e79e4b0e8d9dd6f72b70e776c3317db7c19ca0fd", + "raw_url": "http://localhost/username/repo/raw/commit/e79e4b0e8d9dd6f72b70e776c3317db7c19ca0fd/README.md" + } ] ` diff --git a/server/forge/gitea/gitea.go b/server/forge/gitea/gitea.go index 8a76505d3..8392b549f 100644 --- a/server/forge/gitea/gitea.go +++ b/server/forge/gitea/gitea.go @@ -229,15 +229,21 @@ func (c *Gitea) Repo(ctx context.Context, u *model.User, remoteID model.ForgeRem if err != nil { return nil, err } - repo, _, err := client.GetRepoByID(intID) + repo, resp, err := client.GetRepoByID(intID) if err != nil { + if resp != nil && resp.StatusCode == http.StatusNotFound { + return nil, errors.Join(err, forge_types.ErrRepoNotFound) + } return nil, err } return toRepo(repo), nil } - repo, _, err := client.GetRepo(owner, name) + repo, resp, err := client.GetRepo(owner, name) if err != nil { + if resp != nil && resp.StatusCode == http.StatusNotFound { + return nil, errors.Join(err, forge_types.ErrRepoNotFound) + } return nil, err } return toRepo(repo), nil @@ -414,8 +420,14 @@ func (c *Gitea) Deactivate(ctx context.Context, u *model.User, r *model.Repo, li return err } + // make sure a repo rename does not trick us + forgeRepo, err := c.Repo(ctx, u, r.ForgeRemoteID, r.Owner, r.Name) + if err != nil { + return err + } + hooks, err := shared_utils.Paginate(func(page int) ([]*gitea.Hook, error) { - hooks, _, err := client.ListRepoHooks(r.Owner, r.Name, gitea.ListHooksOptions{ + hooks, _, err := client.ListRepoHooks(forgeRepo.Owner, forgeRepo.Name, gitea.ListHooksOptions{ ListOptions: gitea.ListOptions{ Page: page, PageSize: c.perPage(ctx), @@ -429,7 +441,7 @@ func (c *Gitea) Deactivate(ctx context.Context, u *model.User, r *model.Repo, li hook := matchingHooks(hooks, link) if hook != nil { - _, err := client.DeleteRepoHook(r.Owner, r.Name, hook.ID) + _, err := client.DeleteRepoHook(forgeRepo.Owner, forgeRepo.Name, hook.ID) return err } @@ -569,7 +581,7 @@ func (c *Gitea) Org(ctx context.Context, u *model.User, owner string) (*model.Or org, _, orgErr := client.GetOrg(owner) if orgErr == nil && org != nil { return &model.Org{ - Name: org.UserName, + Name: org.Name, Private: gitea.VisibleType(org.Visibility) != gitea.VisibleTypePublic, }, nil } @@ -647,6 +659,8 @@ func (c *Gitea) getChangedFilesForPR(ctx context.Context, repo *model.Repo, inde return nil, err } + forge.Refresh(ctx, c, _store, user) + client, err := c.newClientToken(ctx, user.AccessToken) if err != nil { return nil, err @@ -684,6 +698,8 @@ func (c *Gitea) getTagCommitSHA(ctx context.Context, repo *model.Repo, tagName s return "", err } + forge.Refresh(ctx, c, _store, user) + client, err := c.newClientToken(ctx, user.AccessToken) if err != nil { return "", err diff --git a/server/forge/gitea/helper.go b/server/forge/gitea/helper.go index 595b5758c..01bf70782 100644 --- a/server/forge/gitea/helper.go +++ b/server/forge/gitea/helper.go @@ -64,7 +64,7 @@ func toPerm(from *gitea.Permission) *model.Perm { // toTeam converts a Gitea team to a Woodpecker team. func toTeam(from *gitea.Organization, link string) *model.Team { return &model.Team{ - Login: from.UserName, + Login: from.Name, Avatar: expandAvatar(link, from.AvatarURL), } } diff --git a/server/forge/gitea/helper_test.go b/server/forge/gitea/helper_test.go index b728699ae..5a4c974b9 100644 --- a/server/forge/gitea/helper_test.go +++ b/server/forge/gitea/helper_test.go @@ -181,12 +181,12 @@ func Test_toPerm(t *testing.T) { func Test_toTeam(t *testing.T) { from := &gitea.Organization{ - UserName: "woodpecker", + Name: "woodpecker", AvatarURL: "/avatars/1", } to := toTeam(from, "http://localhost:80") - assert.Equal(t, from.UserName, to.Login) + assert.Equal(t, from.Name, to.Login) assert.Equal(t, "http://localhost:80/avatars/1", to.Avatar) } diff --git a/server/forge/github/convert.go b/server/forge/github/convert.go index 0b3621848..5f2c6a990 100644 --- a/server/forge/github/convert.go +++ b/server/forge/github/convert.go @@ -18,7 +18,7 @@ package github import ( "fmt" - "github.com/google/go-github/v80/github" + "github.com/google/go-github/v83/github" "go.woodpecker-ci.org/woodpecker/v3/server/model" ) @@ -101,11 +101,11 @@ func convertRepo(from *github.Repository) *model.Repo { // convertPerm is a helper function used to convert a GitHub repository // permissions to the common Woodpecker permissions structure. -func convertPerm(perm map[string]bool) *model.Perm { +func convertPerm(perm *github.RepositoryPermissions) *model.Perm { return &model.Perm{ - Admin: perm["admin"], - Push: perm["push"], - Pull: perm["pull"], + Admin: perm.GetAdmin(), + Push: perm.GetPush(), + Pull: perm.GetPull(), } } diff --git a/server/forge/github/convert_test.go b/server/forge/github/convert_test.go index 2787a8463..22ac78746 100644 --- a/server/forge/github/convert_test.go +++ b/server/forge/github/convert_test.go @@ -18,7 +18,7 @@ package github import ( "testing" - "github.com/google/go-github/v80/github" + "github.com/google/go-github/v83/github" "github.com/stretchr/testify/assert" "go.woodpecker-ci.org/woodpecker/v3/server/model" @@ -54,10 +54,10 @@ func Test_convertRepoList(t *testing.T) { }, HTMLURL: github.Ptr("https://github.com/octocat/hello-world"), CloneURL: github.Ptr("https://github.com/octocat/hello-world.git"), - Permissions: map[string]bool{ - "push": true, - "pull": true, - "admin": true, + Permissions: &github.RepositoryPermissions{ + Admin: github.Ptr(true), + Push: github.Ptr(true), + Pull: github.Ptr(true), }, }, } @@ -81,10 +81,10 @@ func Test_convertRepo(t *testing.T) { AvatarURL: github.Ptr("http://..."), Login: github.Ptr("octocat"), }, - Permissions: map[string]bool{ - "push": true, - "pull": true, - "admin": true, + Permissions: &github.RepositoryPermissions{ + Admin: github.Ptr(true), + Push: github.Ptr(true), + Pull: github.Ptr(true), }, } @@ -101,10 +101,10 @@ func Test_convertRepo(t *testing.T) { func Test_convertPerm(t *testing.T) { from := &github.Repository{ - Permissions: map[string]bool{ - "admin": true, - "push": true, - "pull": true, + Permissions: &github.RepositoryPermissions{ + Admin: github.Ptr(true), + Push: github.Ptr(true), + Pull: github.Ptr(true), }, } diff --git a/server/forge/github/fixtures/handler.go b/server/forge/github/fixtures/handler.go index 0f0255705..b6c9231ca 100644 --- a/server/forge/github/fixtures/handler.go +++ b/server/forge/github/fixtures/handler.go @@ -66,102 +66,102 @@ func getMembership(c *gin.Context) { var repoPayload = ` { "id": 5, - "owner": { - "login": "octocat", - "avatar_url": "https://github.com/images/error/octocat_happy.gif" - }, - "name": "Hello-World", - "full_name": "octocat/Hello-World", - "private": true, - "html_url": "https://github.com/octocat/Hello-World", - "clone_url": "https://github.com/octocat/Hello-World.git", - "language": null, - "permissions": { - "admin": true, - "push": true, - "pull": true - } + "owner": { + "login": "octocat", + "avatar_url": "https://github.com/images/error/octocat_happy.gif" + }, + "name": "Hello-World", + "full_name": "octocat/Hello-World", + "private": true, + "html_url": "https://github.com/octocat/Hello-World", + "clone_url": "https://github.com/octocat/Hello-World.git", + "language": null, + "permissions": { + "admin": true, + "push": true, + "pull": true + } } ` var membershipIsOwnerPayload = ` { - "url": "https://api.github.com/orgs/octocat/memberships/octocat", - "state": "active", - "role": "admin", - "organization_url": "https://api.github.com/orgs/octocat", - "user": { - "login": "octocat", - "id": 5555555, - "avatar_url": "https://github.com/images/error/octocat_happy.gif", - "gravatar_id": "", - "url": "https://api.github.com/users/octocat", - "html_url": "https://github.com/octocat", - "followers_url": "https://api.github.com/users/octocat/followers", - "following_url": "https://api.github.com/users/octocat/following{/other_user}", - "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", - "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", - "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", - "organizations_url": "https://api.github.com/users/octocat/orgs", - "repos_url": "https://api.github.com/users/octocat/repos", - "events_url": "https://api.github.com/users/octocat/events{/privacy}", - "received_events_url": "https://api.github.com/users/octocat/received_events", - "type": "User", - "site_admin": false - }, - "organization": { - "login": "octocat", - "id": 5555556, - "url": "https://api.github.com/orgs/octocat", - "repos_url": "https://api.github.com/orgs/octocat/repos", - "events_url": "https://api.github.com/orgs/octocat/events", - "hooks_url": "https://api.github.com/orgs/octocat/hooks", - "issues_url": "https://api.github.com/orgs/octocat/issues", - "members_url": "https://api.github.com/orgs/octocat/members{/member}", - "public_members_url": "https://api.github.com/orgs/octocat/public_members{/member}", - "avatar_url": "https://github.com/images/error/octocat_happy.gif", - "description": "" - } + "url": "https://api.github.com/orgs/octocat/memberships/octocat", + "state": "active", + "role": "admin", + "organization_url": "https://api.github.com/orgs/octocat", + "user": { + "login": "octocat", + "id": 5555555, + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": "https://api.github.com/users/octocat/following{/other_user}", + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "User", + "site_admin": false + }, + "organization": { + "login": "octocat", + "id": 5555556, + "url": "https://api.github.com/orgs/octocat", + "repos_url": "https://api.github.com/orgs/octocat/repos", + "events_url": "https://api.github.com/orgs/octocat/events", + "hooks_url": "https://api.github.com/orgs/octocat/hooks", + "issues_url": "https://api.github.com/orgs/octocat/issues", + "members_url": "https://api.github.com/orgs/octocat/members{/member}", + "public_members_url": "https://api.github.com/orgs/octocat/public_members{/member}", + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "description": "" + } } ` var membershipIsMemberPayload = ` { - "url": "https://api.github.com/orgs/github/memberships/octocat", - "state": "active", - "role": "member", - "organization_url": "https://api.github.com/orgs/github", - "user": { - "login": "octocat", - "id": 5555555, - "avatar_url": "https://github.com/images/error/octocat_happy.gif", - "gravatar_id": "", - "url": "https://api.github.com/users/octocat", - "html_url": "https://github.com/octocat", - "followers_url": "https://api.github.com/users/octocat/followers", - "following_url": "https://api.github.com/users/octocat/following{/other_user}", - "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", - "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", - "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", - "organizations_url": "https://api.github.com/users/octocat/orgs", - "repos_url": "https://api.github.com/users/octocat/repos", - "events_url": "https://api.github.com/users/octocat/events{/privacy}", - "received_events_url": "https://api.github.com/users/octocat/received_events", - "type": "User", - "site_admin": false - }, - "organization": { - "login": "octocat", - "id": 5555557, - "url": "https://api.github.com/orgs/github", - "repos_url": "https://api.github.com/orgs/github/repos", - "events_url": "https://api.github.com/orgs/github/events", - "hooks_url": "https://api.github.com/orgs/github/hooks", - "issues_url": "https://api.github.com/orgs/github/issues", - "members_url": "https://api.github.com/orgs/github/members{/member}", - "public_members_url": "https://api.github.com/orgs/github/public_members{/member}", - "avatar_url": "https://github.com/images/error/octocat_happy.gif", - "description": "" - } + "url": "https://api.github.com/orgs/github/memberships/octocat", + "state": "active", + "role": "member", + "organization_url": "https://api.github.com/orgs/github", + "user": { + "login": "octocat", + "id": 5555555, + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": "https://api.github.com/users/octocat/following{/other_user}", + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "User", + "site_admin": false + }, + "organization": { + "login": "octocat", + "id": 5555557, + "url": "https://api.github.com/orgs/github", + "repos_url": "https://api.github.com/orgs/github/repos", + "events_url": "https://api.github.com/orgs/github/events", + "hooks_url": "https://api.github.com/orgs/github/hooks", + "issues_url": "https://api.github.com/orgs/github/issues", + "members_url": "https://api.github.com/orgs/github/members{/member}", + "public_members_url": "https://api.github.com/orgs/github/public_members{/member}", + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "description": "" + } } ` diff --git a/server/forge/github/github.go b/server/forge/github/github.go index 01e6d21a4..230cd4c23 100644 --- a/server/forge/github/github.go +++ b/server/forge/github/github.go @@ -27,7 +27,7 @@ import ( "strings" "time" - "github.com/google/go-github/v80/github" + "github.com/google/go-github/v83/github" "github.com/rs/zerolog/log" "golang.org/x/oauth2" @@ -209,15 +209,21 @@ func (c *client) Repo(ctx context.Context, u *model.User, id model.ForgeRemoteID if err != nil { return nil, err } - repo, _, err := client.Repositories.GetByID(ctx, intID) + repo, resp, err := client.Repositories.GetByID(ctx, intID) if err != nil { + if resp != nil && resp.StatusCode == http.StatusNotFound { + return nil, errors.Join(err, forge_types.ErrRepoNotFound) + } return nil, err } return convertRepo(repo), nil } - repo, _, err := client.Repositories.Get(ctx, owner, name) + repo, resp, err := client.Repositories.Get(ctx, owner, name) if err != nil { + if resp != nil && resp.StatusCode == http.StatusNotFound { + return nil, errors.Join(err, forge_types.ErrRepoNotFound) + } return nil, err } return convertRepo(repo), nil @@ -226,22 +232,30 @@ func (c *client) Repo(ctx context.Context, u *model.User, id model.ForgeRemoteID // Repos returns a list of all repositories for GitHub account, including // organization repositories. func (c *client) Repos(ctx context.Context, u *model.User, p *model.ListOptions) ([]*model.Repo, error) { - client := c.newClientToken(ctx, u.AccessToken) - list, _, err := client.Repositories.ListByAuthenticatedUser(ctx, &github.RepositoryListByAuthenticatedUserOptions{ - ListOptions: github.ListOptions{ - Page: p.Page, - PerPage: perPage(p.PerPage), - }, - }) - if err != nil { - return nil, err + // we paginate internally (https://github.com/woodpecker-ci/woodpecker/issues/5667) + if p.Page != 1 { + return nil, nil } - repos := make([]*model.Repo, 0, len(list)) - for _, repo := range list { - if repo.GetArchived() { - continue + + client := c.newClientToken(ctx, u.AccessToken) + + opts := new(github.RepositoryListByAuthenticatedUserOptions) + opts.PerPage = 100 + opts.Page = 1 + + var repos []*model.Repo + for opts.Page > 0 { + list, resp, err := client.Repositories.ListByAuthenticatedUser(ctx, opts) + if err != nil { + return nil, err } - repos = append(repos, convertRepo(repo)) + for _, repo := range list { + if repo.GetArchived() { + continue + } + repos = append(repos, convertRepo(repo)) + } + opts.Page = resp.NextPage } return repos, nil } @@ -301,7 +315,7 @@ func (c *client) Dir(ctx context.Context, u *model.User, r *model.Repo, b *model var files []*forge_types.FileMeta - for i := 0; i < len(data); i++ { + for range data { select { case err := <-errChan: return nil, err @@ -370,7 +384,14 @@ func (c *client) Netrc(u *model.User, r *model.Repo) (*model.Netrc, error) { // the GitHub repository. func (c *client) Deactivate(ctx context.Context, u *model.User, r *model.Repo, link string) error { client := c.newClientToken(ctx, u.AccessToken) - hooks, _, err := client.Repositories.ListHooks(ctx, r.Owner, r.Name, nil) + + // make sure a repo rename does not trick us + forgeRepo, err := c.Repo(ctx, u, r.ForgeRemoteID, r.Owner, r.Name) + if err != nil { + return err + } + + hooks, _, err := client.Repositories.ListHooks(ctx, forgeRepo.Owner, forgeRepo.Name, nil) if err != nil { return err } @@ -378,7 +399,7 @@ func (c *client) Deactivate(ctx context.Context, u *model.User, r *model.Repo, l if match == nil { return nil } - _, err = client.Repositories.DeleteHook(ctx, r.Owner, r.Name, *match.ID) + _, err = client.Repositories.DeleteHook(ctx, forgeRepo.Owner, forgeRepo.Name, *match.ID) return err } @@ -671,6 +692,11 @@ func (c *client) loadChangedFilesFromPullRequest(ctx context.Context, pull *gith return nil, err } + // Refresh the OAuth token before making API calls. + // The token may be expired, and without this refresh the API calls below + // would fail with an authentication error. + forge.Refresh(ctx, c, _store, user) + gh := c.newClientToken(ctx, user.AccessToken) fileList := make([]string, 0, 16) @@ -709,6 +735,11 @@ func (c *client) getTagCommitSHA(ctx context.Context, repo *model.Repo, tagName return "", err } + // Refresh the OAuth token before making API calls. + // The token may be expired, and without this refresh the API calls below + // would fail with an authentication error. + forge.Refresh(ctx, c, _store, user) + gh := c.newClientToken(ctx, user.AccessToken) page := 1 @@ -764,6 +795,11 @@ func (c *client) loadChangedFilesFromCommits(ctx context.Context, tmpRepo *model return nil, err } + // Refresh the OAuth token before making API calls. + // The token may be expired, and without this refresh the API calls below + // would fail with an authentication error. + forge.Refresh(ctx, c, _store, user) + gh := c.newClientToken(ctx, user.AccessToken) fileList := make([]string, 0, 16) diff --git a/server/forge/github/github_test.go b/server/forge/github/github_test.go index 6f78d42d0..de4994b33 100644 --- a/server/forge/github/github_test.go +++ b/server/forge/github/github_test.go @@ -22,7 +22,7 @@ import ( "testing" "github.com/gin-gonic/gin" - "github.com/google/go-github/v80/github" + "github.com/google/go-github/v83/github" gh_mock "github.com/migueleliasweb/go-github-mock/src/mock" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" diff --git a/server/forge/github/parse.go b/server/forge/github/parse.go index 663f842dc..a938bff11 100644 --- a/server/forge/github/parse.go +++ b/server/forge/github/parse.go @@ -22,7 +22,7 @@ import ( "net/http" "strings" - "github.com/google/go-github/v80/github" + "github.com/google/go-github/v83/github" "go.woodpecker-ci.org/woodpecker/v3/server/forge/common" "go.woodpecker-ci.org/woodpecker/v3/server/forge/types" diff --git a/server/forge/gitlab/fixtures/projects.go b/server/forge/gitlab/fixtures/projects.go index 4eed50000..9a6dfc5ea 100644 --- a/server/forge/gitlab/fixtures/projects.go +++ b/server/forge/gitlab/fixtures/projects.go @@ -281,56 +281,56 @@ var project4PayloadHook = []byte(` var project4PayloadHooks = []byte(` [ - { - "id": 10717088, - "url": "http://example.com/api/hook", - "created_at": "2021-12-18T23:29:33.852Z", - "push_events": true, - "tag_push_events": true, - "merge_requests_events": true, - "repository_update_events": false, - "enable_ssl_verification": true, - "project_id": 4, - "issues_events": false, - "confidential_issues_events": false, - "note_events": false, - "confidential_note_events": null, - "pipeline_events": false, - "wiki_page_events": false, - "deployment_events": true, - "job_events": false, - "releases_events": false, - "push_events_branch_filter": null - } + { + "id": 10717088, + "url": "http://example.com/api/hook", + "created_at": "2021-12-18T23:29:33.852Z", + "push_events": true, + "tag_push_events": true, + "merge_requests_events": true, + "repository_update_events": false, + "enable_ssl_verification": true, + "project_id": 4, + "issues_events": false, + "confidential_issues_events": false, + "note_events": false, + "confidential_note_events": null, + "pipeline_events": false, + "wiki_page_events": false, + "deployment_events": true, + "job_events": false, + "releases_events": false, + "push_events_branch_filter": null + } ] `) var project4PayloadMembers = []byte(` { - "id": 3, - "username": "some_user", - "name": "Diaspora", - "state": "active", - "locked": false, - "avatar_url": "https://example.com/uploads/-/system/user/avatar/3/avatar.png", - "web_url": "https://example.com/some_user", - "access_level": 50, - "created_at": "2024-01-16T12:39:58.912Z", - "expires_at": null + "id": 3, + "username": "some_user", + "name": "Diaspora", + "state": "active", + "locked": false, + "avatar_url": "https://example.com/uploads/-/system/user/avatar/3/avatar.png", + "web_url": "https://example.com/some_user", + "access_level": 50, + "created_at": "2024-01-16T12:39:58.912Z", + "expires_at": null } `) var project6PayloadMembers = []byte(` { - "id": 3, - "username": "some_user", - "name": "Diaspora", - "state": "active", - "locked": false, - "avatar_url": "https://example.com/uploads/-/system/user/avatar/3/avatar.png", - "web_url": "https://example.com/some_user", - "access_level": 30, - "created_at": "2024-01-16T12:39:58.912Z", - "expires_at": null + "id": 3, + "username": "some_user", + "name": "Diaspora", + "state": "active", + "locked": false, + "avatar_url": "https://example.com/uploads/-/system/user/avatar/3/avatar.png", + "web_url": "https://example.com/some_user", + "access_level": 30, + "created_at": "2024-01-16T12:39:58.912Z", + "expires_at": null } `) diff --git a/server/forge/gitlab/fixtures/users.go b/server/forge/gitlab/fixtures/users.go index b5ee1c4c4..8a6e2770f 100644 --- a/server/forge/gitlab/fixtures/users.go +++ b/server/forge/gitlab/fixtures/users.go @@ -16,23 +16,23 @@ package fixtures var currentUserPayload = []byte(` { - "id": 1, - "username": "john_smith", - "email": "john@example.com", - "name": "John Smith", - "private_token": "dd34asd13as", - "state": "active", - "created_at": "2012-05-23T08:00:58Z", - "bio": null, - "skype": "", - "linkedin": "", - "twitter": "", - "website_url": "", - "theme_id": 1, - "color_scheme_id": 2, - "is_admin": false, - "can_create_group": true, - "can_create_project": true, - "projects_limit": 100 + "id": 1, + "username": "john_smith", + "email": "john@example.com", + "name": "John Smith", + "private_token": "dd34asd13as", + "state": "active", + "created_at": "2012-05-23T08:00:58Z", + "bio": null, + "skype": "", + "linkedin": "", + "twitter": "", + "website_url": "", + "theme_id": 1, + "color_scheme_id": 2, + "is_admin": false, + "can_create_group": true, + "can_create_project": true, + "projects_limit": 100 } `) diff --git a/server/forge/gitlab/gitlab.go b/server/forge/gitlab/gitlab.go index a4683bb4b..09ade99f0 100644 --- a/server/forge/gitlab/gitlab.go +++ b/server/forge/gitlab/gitlab.go @@ -199,10 +199,7 @@ func (g *GitLab) Teams(ctx context.Context, user *model.User, p *model.ListOptio return nil, err } - perPage := p.PerPage - if perPage > defaultPerPage { - perPage = defaultPerPage - } + perPage := min(p.PerPage, defaultPerPage) groups, _, err := client.Groups.ListGroups(&gitlab.ListGroupsOptions{ ListOptions: gitlab.ListOptions{ @@ -240,11 +237,17 @@ func (g *GitLab) getProject(ctx context.Context, client *gitlab.Client, forgeRem if err != nil { return nil, err } - repo, _, err = client.Projects.GetProject(intID, nil, gitlab.WithContext(ctx)) + repo, resp, err := client.Projects.GetProject(intID, nil, gitlab.WithContext(ctx)) + if err != nil && resp != nil && resp.StatusCode == http.StatusNotFound { + return nil, errors.Join(err, forge_types.ErrRepoNotFound) + } return repo, err } - repo, _, err = client.Projects.GetProject(fmt.Sprintf("%s/%s", owner, name), nil, gitlab.WithContext(ctx)) + repo, resp, err := client.Projects.GetProject(fmt.Sprintf("%s/%s", owner, name), nil, gitlab.WithContext(ctx)) + if err != nil && resp != nil && resp.StatusCode == http.StatusNotFound { + return nil, errors.Join(err, forge_types.ErrRepoNotFound) + } return repo, err } @@ -294,10 +297,7 @@ func (g *GitLab) Repos(ctx context.Context, user *model.User, p *model.ListOptio return nil, err } - perPage := p.PerPage - if perPage > defaultPerPage { - perPage = defaultPerPage - } + perPage := min(p.PerPage, defaultPerPage) opts := &gitlab.ListProjectsOptions{ ListOptions: gitlab.ListOptions{ @@ -796,6 +796,8 @@ func (g *GitLab) loadMetadataFromMergeRequest(ctx context.Context, tmpRepo *mode return nil, err } + forge.Refresh(ctx, g, _store, user) + client, err := newClient(g.url, user.AccessToken, g.skipVerify) if err != nil { return nil, err diff --git a/server/forge/types/errors.go b/server/forge/types/errors.go index e4c7890cd..5914be9bf 100644 --- a/server/forge/types/errors.go +++ b/server/forge/types/errors.go @@ -21,7 +21,10 @@ import ( "strings" ) -var ErrNotImplemented = errors.New("not implemented") +var ( + ErrNotImplemented = errors.New("not implemented") + ErrRepoNotFound = errors.New("repo not found") +) type ErrIgnoreEvent struct { Event string diff --git a/server/model/agent.go b/server/model/agent.go index 5e2fefb23..8390e349e 100644 --- a/server/model/agent.go +++ b/server/model/agent.go @@ -18,7 +18,7 @@ import ( "encoding/base32" "fmt" - "github.com/google/tink/go/subtle/random" + "github.com/tink-crypto/tink-go/v2/subtle/random" "go.woodpecker-ci.org/woodpecker/v3/pipeline" ) diff --git a/server/model/cron.go b/server/model/cron.go index 7af889085..9624c369e 100644 --- a/server/model/cron.go +++ b/server/model/cron.go @@ -21,14 +21,16 @@ import ( ) type Cron struct { - ID int64 `json:"id" xorm:"pk autoincr 'id'"` - Name string `json:"name" xorm:"name UNIQUE(s) INDEX"` - RepoID int64 `json:"repo_id" xorm:"repo_id UNIQUE(s) INDEX"` - CreatorID int64 `json:"creator_id" xorm:"creator_id INDEX"` - NextExec int64 `json:"next_exec" xorm:"next_exec"` - Schedule string `json:"schedule" xorm:"schedule NOT NULL"` // @weekly, 3min, ... - Created int64 `json:"created" xorm:"created NOT NULL DEFAULT 0"` - Branch string `json:"branch" xorm:"branch"` + ID int64 `json:"id" xorm:"pk autoincr 'id'"` + Name string `json:"name" xorm:"name UNIQUE(s) INDEX"` + RepoID int64 `json:"repo_id" xorm:"repo_id UNIQUE(s) INDEX"` + CreatorID int64 `json:"creator_id" xorm:"creator_id INDEX"` // TODO: drop with next major version + NextExec int64 `json:"next_exec" xorm:"next_exec"` + Schedule string `json:"schedule" xorm:"schedule NOT NULL"` // @weekly, 3min, ... + Created int64 `json:"created" xorm:"created NOT NULL DEFAULT 0"` + Branch string `json:"branch" xorm:"branch"` + Enabled bool `json:"enabled" xorm:"enabled NOT NULL DEFAULT TRUE"` + Variables map[string]string `json:"variables" xorm:"json 'variables'"` } // @name Cron // TableName returns the database table name for xorm. @@ -53,3 +55,11 @@ func (c *Cron) Validate() error { return nil } + +type CronPatch struct { + Name *string `json:"name"` + Schedule *string `json:"schedule"` + Branch *string `json:"branch"` + Enabled *bool `json:"enabled"` + Variables map[string]string `json:"variables"` +} // @name CronPatch diff --git a/server/model/perm.go b/server/model/perm.go index a746c8241..06cb2f765 100644 --- a/server/model/perm.go +++ b/server/model/perm.go @@ -19,7 +19,6 @@ package model type Perm struct { UserID int64 `json:"-" xorm:"UNIQUE(s) INDEX NOT NULL 'user_id'"` RepoID int64 `json:"-" xorm:"UNIQUE(s) INDEX NOT NULL 'repo_id'"` - Repo *Repo `json:"-" xorm:"-"` Pull bool `json:"pull" xorm:"pull"` Push bool `json:"push" xorm:"push"` Admin bool `json:"admin" xorm:"admin"` diff --git a/server/model/pipeline.go b/server/model/pipeline.go index 6dbae5008..4de1c69bd 100644 --- a/server/model/pipeline.go +++ b/server/model/pipeline.go @@ -16,45 +16,46 @@ package model import ( - "go.woodpecker-ci.org/woodpecker/v3/pipeline/errors/types" + "go.woodpecker-ci.org/woodpecker/v3/pipeline/errors" ) type Pipeline struct { - ID int64 `json:"id" xorm:"pk autoincr 'id'"` - RepoID int64 `json:"-" xorm:"UNIQUE(s) INDEX 'repo_id'"` - Number int64 `json:"number" xorm:"UNIQUE(s) 'number'"` - Author string `json:"author" xorm:"INDEX 'author'"` - Parent int64 `json:"parent" xorm:"parent"` - Event WebhookEvent `json:"event" xorm:"event"` - EventReason []string `json:"event_reason" xorm:"json 'event_reason'"` - Status StatusValue `json:"status" xorm:"INDEX 'status'"` - Errors []*types.PipelineError `json:"errors" xorm:"json 'errors'"` - Created int64 `json:"created" xorm:"'created' NOT NULL DEFAULT 0 created"` - Updated int64 `json:"updated" xorm:"'updated' NOT NULL DEFAULT 0 updated"` - Started int64 `json:"started" xorm:"started"` - Finished int64 `json:"finished" xorm:"finished"` - DeployTo string `json:"deploy_to" xorm:"deploy"` - DeployTask string `json:"deploy_task" xorm:"deploy_task"` - Commit string `json:"commit" xorm:"commit"` - Branch string `json:"branch" xorm:"branch"` - Ref string `json:"ref" xorm:"ref"` - Refspec string `json:"refspec" xorm:"refspec"` - Title string `json:"title" xorm:"title"` - Message string `json:"message" xorm:"TEXT 'message'"` - Timestamp int64 `json:"timestamp" xorm:"'timestamp'"` - Sender string `json:"sender" xorm:"sender"` // uses reported user for webhooks and name of cron for cron pipelines - Avatar string `json:"author_avatar" xorm:"varchar(500) avatar"` - Email string `json:"author_email" xorm:"varchar(500) email"` - ForgeURL string `json:"forge_url" xorm:"forge_url"` - Reviewer string `json:"reviewed_by" xorm:"reviewer"` - Reviewed int64 `json:"reviewed" xorm:"reviewed"` - Workflows []*Workflow `json:"workflows,omitempty" xorm:"-"` - ChangedFiles []string `json:"changed_files,omitempty" xorm:"LONGTEXT 'changed_files'"` - AdditionalVariables map[string]string `json:"variables,omitempty" xorm:"json 'additional_variables'"` - PullRequestLabels []string `json:"pr_labels,omitempty" xorm:"json 'pr_labels'"` - PullRequestMilestone string `json:"pr_milestone,omitempty" xorm:"pr_milestone"` - IsPrerelease bool `json:"is_prerelease,omitempty" xorm:"is_prerelease"` - FromFork bool `json:"from_fork,omitempty" xorm:"from_fork"` + ID int64 `json:"id" xorm:"pk autoincr 'id'"` + RepoID int64 `json:"-" xorm:"UNIQUE(s) INDEX 'repo_id'"` + Number int64 `json:"number" xorm:"UNIQUE(s) 'number'"` + Author string `json:"author" xorm:"INDEX 'author'"` + Parent int64 `json:"parent" xorm:"parent"` + Event WebhookEvent `json:"event" xorm:"event"` + EventReason []string `json:"event_reason" xorm:"json 'event_reason'"` + Status StatusValue `json:"status" xorm:"INDEX 'status'"` + Errors []*errors.PipelineError `json:"errors" xorm:"json 'errors'"` + Created int64 `json:"created" xorm:"'created' NOT NULL DEFAULT 0 created"` + Updated int64 `json:"updated" xorm:"'updated' NOT NULL DEFAULT 0 updated"` + Started int64 `json:"started" xorm:"started"` + Finished int64 `json:"finished" xorm:"finished"` + DeployTo string `json:"deploy_to" xorm:"deploy"` + DeployTask string `json:"deploy_task" xorm:"deploy_task"` + Commit string `json:"commit" xorm:"commit"` + Branch string `json:"branch" xorm:"branch"` + Ref string `json:"ref" xorm:"ref"` + Refspec string `json:"refspec" xorm:"refspec"` + Title string `json:"title" xorm:"title"` + Message string `json:"message" xorm:"TEXT 'message'"` + Timestamp int64 `json:"timestamp" xorm:"'timestamp'"` + Sender string `json:"sender" xorm:"sender"` // uses reported user for webhooks and name of cron for cron pipelines + Avatar string `json:"author_avatar" xorm:"varchar(500) avatar"` + Email string `json:"author_email" xorm:"varchar(500) email"` + ForgeURL string `json:"forge_url" xorm:"forge_url"` + Reviewer string `json:"reviewed_by" xorm:"reviewer"` + Reviewed int64 `json:"reviewed" xorm:"reviewed"` + CancelInfo *CancelInfo `json:"cancel_info,omitempty" xorm:"json 'cancel_info'"` + Workflows []*Workflow `json:"workflows,omitempty" xorm:"-"` + ChangedFiles []string `json:"changed_files,omitempty" xorm:"LONGTEXT 'changed_files'"` + AdditionalVariables map[string]string `json:"variables,omitempty" xorm:"json 'additional_variables'"` + PullRequestLabels []string `json:"pr_labels,omitempty" xorm:"json 'pr_labels'"` + PullRequestMilestone string `json:"pr_milestone,omitempty" xorm:"pr_milestone"` + IsPrerelease bool `json:"is_prerelease,omitempty" xorm:"is_prerelease"` + FromFork bool `json:"from_fork,omitempty" xorm:"from_fork"` } // @name Pipeline // TableName return database table name for xorm. @@ -85,3 +86,8 @@ type PipelineOptions struct { Branch string `json:"branch"` Variables map[string]string `json:"variables"` } // @name PipelineOptions + +type CancelInfo struct { + CanceledByUser string `json:"canceled_by_user,omitempty"` + SupersededBy int64 `json:"superseded_by,omitempty"` +} // @name CancelInfo diff --git a/server/model/repo.go b/server/model/repo.go index f2e009f60..e64367588 100644 --- a/server/model/repo.go +++ b/server/model/repo.go @@ -73,6 +73,7 @@ type Repo struct { CancelPreviousPipelineEvents []WebhookEvent `json:"cancel_previous_pipeline_events" xorm:"json 'cancel_previous_pipeline_events'"` NetrcTrustedPlugins []string `json:"netrc_trusted" xorm:"json 'netrc_trusted'"` ConfigExtensionEndpoint string `json:"config_extension_endpoint" xorm:"varchar(500) 'config_extension_endpoint'"` + ConfigExtensionExclusive bool `json:"config_extension_exclusive" xorm:"DEFAULT FALSE 'config_extension_exclusive'"` } // @name Repo // TableName return database table name for xorm. @@ -144,6 +145,7 @@ type RepoPatch struct { NetrcTrusted *[]string `json:"netrc_trusted"` Trusted *TrustedConfigurationPatch `json:"trusted"` ConfigExtensionEndpoint *string `json:"config_extension_endpoint,omitempty"` + ConfigExtensionExclusive *bool `json:"config_extension_exclusive"` } // @name RepoPatch type ForgeRemoteID string diff --git a/server/model/secret.go b/server/model/secret.go index e510f65b4..7ca81ac46 100644 --- a/server/model/secret.go +++ b/server/model/secret.go @@ -52,6 +52,7 @@ type Secret struct { Value string `json:"value,omitempty" xorm:"TEXT 'value'"` Images []string `json:"images" xorm:"json 'images'"` Events []WebhookEvent `json:"events" xorm:"json 'events'"` + Note string `json:"note" xorm:"note"` } // @name Secret // TableName return database table name for xorm. @@ -129,6 +130,7 @@ func (s *Secret) Copy() *Secret { Name: s.Name, Images: s.Images, Events: sortEvents(s.Events), + Note: s.Note, } } @@ -136,3 +138,11 @@ func sortEvents(wel WebhookEventList) WebhookEventList { sort.Sort(wel) return wel } + +type SecretPatch struct { + Name *string `json:"name" ` + Value *string `json:"value,omitempty" ` + Images []string `json:"images" ` + Events []WebhookEvent `json:"events" ` + Note *string `json:"note" ` +} // @name SecretPatch diff --git a/server/model/task.go b/server/model/task.go index 76bd1d240..1be6c2783 100644 --- a/server/model/task.go +++ b/server/model/task.go @@ -17,7 +17,6 @@ package model import ( "fmt" "slices" - "strings" "go.woodpecker-ci.org/woodpecker/v3/pipeline" ) @@ -43,9 +42,7 @@ func (Task) TableName() string { } func (t *Task) String() string { - var sb strings.Builder - sb.WriteString(fmt.Sprintf("%s (%s) - %s", t.ID, t.Dependencies, t.DepStatus)) - return sb.String() + return fmt.Sprintf("%s (%s) - %s", t.ID, t.Dependencies, t.DepStatus) } func (t *Task) ApplyLabelsFromRepo(r *Repo) error { diff --git a/server/model/workflow.go b/server/model/workflow.go index e6029ab69..53a21a2dc 100644 --- a/server/model/workflow.go +++ b/server/model/workflow.go @@ -57,30 +57,3 @@ func IsThereRunningStage(workflows []*Workflow) bool { } return false } - -// PipelineStatus determine pipeline status based on corresponding workflow list. -func PipelineStatus(workflows []*Workflow) StatusValue { - status := StatusSuccess - - for _, p := range workflows { - if p.Failing() { - status = p.State - } - } - - return status -} - -// WorkflowStatus determine workflow status based on corresponding step list. -func WorkflowStatus(steps []*Step) StatusValue { - status := StatusSuccess - - for _, p := range steps { - if p.Failing() { - status = p.State - break - } - } - - return status -} diff --git a/server/pipeline/cancel.go b/server/pipeline/cancel.go index 78612562d..a55031f8e 100644 --- a/server/pipeline/cancel.go +++ b/server/pipeline/cancel.go @@ -29,7 +29,7 @@ import ( ) // Cancel the pipeline and returns the status. -func Cancel(ctx context.Context, _forge forge.Forge, store store.Store, repo *model.Repo, user *model.User, pipeline *model.Pipeline) error { +func Cancel(ctx context.Context, _forge forge.Forge, store store.Store, repo *model.Repo, user *model.User, pipeline *model.Pipeline, cancelInfo *model.CancelInfo) error { if pipeline.Status != model.StatusRunning && pipeline.Status != model.StatusPending && pipeline.Status != model.StatusBlocked { return &ErrBadRequest{Msg: "Cannot cancel a non-running or non-pending or non-blocked pipeline"} } @@ -39,31 +39,17 @@ func Cancel(ctx context.Context, _forge forge.Forge, store store.Store, repo *mo return &ErrNotFound{Msg: err.Error()} } - // First cancel/evict steps in the queue in one go - var ( - stepsToCancel []string - stepsToEvict []string - ) - for _, workflow := range workflows { - if workflow.State == model.StatusRunning { - stepsToCancel = append(stepsToCancel, fmt.Sprint(workflow.ID)) - } - if workflow.State == model.StatusPending { - stepsToEvict = append(stepsToEvict, fmt.Sprint(workflow.ID)) + // First cancel/evict workflows in the queue in one go + var workflowsToCancel []string + for _, w := range workflows { + if w.State == model.StatusRunning || w.State == model.StatusPending { + workflowsToCancel = append(workflowsToCancel, fmt.Sprint(w.ID)) } } - if len(stepsToEvict) != 0 { - if err := server.Config.Services.Queue.EvictAtOnce(ctx, stepsToEvict); err != nil { - log.Error().Err(err).Msgf("queue: evict_at_once: %v", stepsToEvict) - } - if err := server.Config.Services.Queue.ErrorAtOnce(ctx, stepsToEvict, queue.ErrCancel); err != nil { - log.Error().Err(err).Msgf("queue: evict_at_once: %v", stepsToEvict) - } - } - if len(stepsToCancel) != 0 { - if err := server.Config.Services.Queue.ErrorAtOnce(ctx, stepsToCancel, queue.ErrCancel); err != nil { - log.Error().Err(err).Msgf("queue: evict_at_once: %v", stepsToCancel) + if len(workflowsToCancel) != 0 { + if err := server.Config.Services.Queue.ErrorAtOnce(ctx, workflowsToCancel, queue.ErrCancel); err != nil { + log.Error().Err(err).Msgf("queue: evict_at_once: %v", workflowsToCancel) } } @@ -84,7 +70,7 @@ func Cancel(ctx context.Context, _forge forge.Forge, store store.Store, repo *mo } } - killedPipeline, err := UpdateToStatusKilled(store, *pipeline) + killedPipeline, err := UpdateToStatusKilled(store, *pipeline, cancelInfo) if err != nil { log.Error().Err(err).Msgf("UpdateToStatusKilled: %v", pipeline) return err @@ -147,7 +133,9 @@ func cancelPreviousPipelines( continue } - if err = Cancel(ctx, _forge, _store, repo, user, active); err != nil { + if err = Cancel(ctx, _forge, _store, repo, user, active, &model.CancelInfo{ + SupersededBy: pipeline.Number, + }); err != nil { log.Error(). Err(err). Str("ref", active.Ref). diff --git a/server/pipeline/pipeline_status.go b/server/pipeline/pipeline_status.go index fbac2776f..86bf7183b 100644 --- a/server/pipeline/pipeline_status.go +++ b/server/pipeline/pipeline_status.go @@ -23,6 +23,17 @@ import ( "go.woodpecker-ci.org/woodpecker/v3/server/store" ) +// PipelineStatus determine pipeline status based on corresponding workflow list. +func PipelineStatus(workflows []*model.Workflow) model.StatusValue { + status := model.StatusSuccess + + for _, p := range workflows { + status = MergeStatusValues(status, p.State) + } + + return status +} + func UpdateToStatusRunning(store store.Store, pipeline model.Pipeline, started int64) (*model.Pipeline, error) { pipeline.Status = model.StatusRunning pipeline.Started = started @@ -59,8 +70,9 @@ func UpdateToStatusError(store store.Store, pipeline model.Pipeline, err error) return &pipeline, store.UpdatePipeline(&pipeline) } -func UpdateToStatusKilled(store store.Store, pipeline model.Pipeline) (*model.Pipeline, error) { +func UpdateToStatusKilled(store store.Store, pipeline model.Pipeline, cancelInfo *model.CancelInfo) (*model.Pipeline, error) { pipeline.Status = model.StatusKilled pipeline.Finished = time.Now().Unix() + pipeline.CancelInfo = cancelInfo return &pipeline, store.UpdatePipeline(&pipeline) } diff --git a/server/pipeline/pipeline_status_test.go b/server/pipeline/pipeline_status_test.go index aa4bfcee4..8964e007a 100644 --- a/server/pipeline/pipeline_status_test.go +++ b/server/pipeline/pipeline_status_test.go @@ -94,9 +94,14 @@ func TestUpdateToStatusKilled(t *testing.T) { t.Parallel() now := time.Now().Unix() + cancelInfo := &model.CancelInfo{ + SupersededBy: 2, + } - pipeline, _ := UpdateToStatusKilled(mockStorePipeline(t), model.Pipeline{}) + pipeline, _ := UpdateToStatusKilled(mockStorePipeline(t), model.Pipeline{}, cancelInfo) assert.Equal(t, model.StatusKilled, pipeline.Status) + assert.NotNil(t, pipeline.CancelInfo) + assert.EqualValues(t, 2, pipeline.CancelInfo.SupersededBy) assert.LessOrEqual(t, now, pipeline.Finished) } diff --git a/server/pipeline/queue.go b/server/pipeline/queue.go index f204b4461..f921930c2 100644 --- a/server/pipeline/queue.go +++ b/server/pipeline/queue.go @@ -20,7 +20,7 @@ import ( "fmt" "maps" - "go.woodpecker-ci.org/woodpecker/v3/pipeline/rpc" + "go.woodpecker-ci.org/woodpecker/v3/rpc" "go.woodpecker-ci.org/woodpecker/v3/server" "go.woodpecker-ci.org/woodpecker/v3/server/model" "go.woodpecker-ci.org/woodpecker/v3/server/pipeline/stepbuilder" diff --git a/server/pipeline/status.go b/server/pipeline/status.go new file mode 100644 index 000000000..4efdf1c13 --- /dev/null +++ b/server/pipeline/status.go @@ -0,0 +1,55 @@ +// Copyright 2026 Woodpecker Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package pipeline + +import "go.woodpecker-ci.org/woodpecker/v3/server/model" + +// list of statuses by their priority. Most important is on top. +var statusPriorityOrder = []model.StatusValue{ + // blocked, declined and created cannot appear in the + // same workflow/pipeline at the same time + model.StatusDeclined, + model.StatusBlocked, + model.StatusCreated, + + // errors have highest priority. + model.StatusError, + + // skipped and killed cannot appear together with running/pending. + model.StatusKilled, + model.StatusSkipped, + + // running states + model.StatusRunning, + model.StatusPending, + + // finished states + model.StatusFailure, + model.StatusSuccess, +} + +var priorityMap map[model.StatusValue]int = buildPriorityMap() + +func buildPriorityMap() map[model.StatusValue]int { + m := map[model.StatusValue]int{} + for i, s := range statusPriorityOrder { + m[s] = i + } + return m +} + +func MergeStatusValues(s, t model.StatusValue) model.StatusValue { + return statusPriorityOrder[min(priorityMap[s], priorityMap[t])] +} diff --git a/server/pipeline/status_test.go b/server/pipeline/status_test.go new file mode 100644 index 000000000..18171d281 --- /dev/null +++ b/server/pipeline/status_test.go @@ -0,0 +1,76 @@ +// Copyright 2026 Woodpecker Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package pipeline + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "go.woodpecker-ci.org/woodpecker/v3/server/model" +) + +func TestStatusValueMerge(t *testing.T) { + tests := []struct { + s model.StatusValue + t model.StatusValue + e model.StatusValue + }{ + { + s: model.StatusSuccess, + t: model.StatusSkipped, + e: model.StatusSkipped, + }, + { + s: model.StatusSuccess, + t: model.StatusSuccess, + e: model.StatusSuccess, + }, + { + s: model.StatusFailure, + t: model.StatusSuccess, + e: model.StatusFailure, + }, + { + s: model.StatusRunning, + t: model.StatusSuccess, + e: model.StatusRunning, + }, + { + s: model.StatusRunning, + t: model.StatusFailure, + e: model.StatusRunning, + }, + { + s: model.StatusFailure, + t: model.StatusKilled, + e: model.StatusKilled, + }, + { + s: model.StatusSkipped, + t: model.StatusKilled, + e: model.StatusKilled, + }, + { + s: model.StatusSkipped, + t: model.StatusSkipped, + e: model.StatusSkipped, + }, + } + for _, tt := range tests { + assert.Equal(t, tt.e, MergeStatusValues(tt.s, tt.t)) + assert.Equal(t, tt.e, MergeStatusValues(tt.t, tt.s)) + } +} diff --git a/server/pipeline/step_status.go b/server/pipeline/step_status.go index 31ac5b8dd..a45c13616 100644 --- a/server/pipeline/step_status.go +++ b/server/pipeline/step_status.go @@ -16,28 +16,76 @@ package pipeline import ( - "go.woodpecker-ci.org/woodpecker/v3/pipeline" - "go.woodpecker-ci.org/woodpecker/v3/pipeline/rpc" + "fmt" + "time" + + "github.com/rs/zerolog/log" + + "go.woodpecker-ci.org/woodpecker/v3/rpc" "go.woodpecker-ci.org/woodpecker/v3/server/model" "go.woodpecker-ci.org/woodpecker/v3/server/store" ) +// UpdateStepStatus updates step status based on agent reports via RPC. func UpdateStepStatus(store store.Store, step *model.Step, state rpc.StepState) error { - if state.Exited { - step.Finished = state.Finished - step.ExitCode = state.ExitCode - step.Error = state.Error - step.State = model.StatusSuccess - if state.ExitCode != 0 || state.Error != "" { - step.State = model.StatusFailure + log.Debug().Str("StepUUID", step.UUID).Msgf("Update step %#v state %#v", *step, state) + + switch step.State { + case model.StatusPending: + // Transition from pending to running when started + if state.Finished == 0 { + step.State = model.StatusRunning } - if state.ExitCode == pipeline.ExitCodeKilled { - step.State = model.StatusKilled - } - } else if step.Finished == 0 { step.Started = state.Started - step.State = model.StatusRunning + if step.Started == 0 { + step.Started = time.Now().Unix() + } + + // Handle direct transition to finished if step setup error happened + if state.Exited || state.Error != "" { + step.Finished = state.Finished + if step.Finished == 0 { + step.Finished = time.Now().Unix() + } + step.ExitCode = state.ExitCode + step.Error = state.Error + + if state.ExitCode == 0 && state.Error == "" { + step.State = model.StatusSuccess + } else { + step.State = model.StatusFailure + } + } + + case model.StatusRunning: + // Already running, check if it finished + if state.Exited || state.Error != "" { + step.Finished = state.Finished + if step.Finished == 0 { + step.Finished = time.Now().Unix() + } + step.ExitCode = state.ExitCode + step.Error = state.Error + + if state.ExitCode == 0 && state.Error == "" { + step.State = model.StatusSuccess + } else { + step.State = model.StatusFailure + } + } + + default: + return fmt.Errorf("step has state %s and does not expect rpc state updates", step.State) } + + // Handle cancellation across both cases + if state.Canceled && step.State != model.StatusKilled { + step.State = model.StatusKilled + if step.Finished == 0 { + step.Finished = time.Now().Unix() + } + } + return store.StepUpdate(step) } diff --git a/server/pipeline/step_status_test.go b/server/pipeline/step_status_test.go index 0537d892b..2a00aef87 100644 --- a/server/pipeline/step_status_test.go +++ b/server/pipeline/step_status_test.go @@ -1,5 +1,4 @@ // Copyright 2022 Woodpecker Authors -// Copyright 2019 mhmxs // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -22,7 +21,7 @@ import ( "github.com/stretchr/testify/mock" "go.woodpecker-ci.org/woodpecker/v3/pipeline" - "go.woodpecker-ci.org/woodpecker/v3/pipeline/rpc" + "go.woodpecker-ci.org/woodpecker/v3/rpc" "go.woodpecker-ci.org/woodpecker/v3/server/model" "go.woodpecker-ci.org/woodpecker/v3/server/store" "go.woodpecker-ci.org/woodpecker/v3/server/store/mocks" @@ -34,138 +33,224 @@ func mockStoreStep(t *testing.T) store.Store { return s } -func TestUpdateStepStatusNotExited(t *testing.T) { - t.Parallel() - // step in db before update - step := &model.Step{} - - // advertised step status - state := rpc.StepState{ - Started: int64(42), - Exited: false, - // Dummy data - Finished: int64(1), - ExitCode: pipeline.ExitCodeKilled, - Error: "not an error", - } - - err := UpdateStepStatus(mockStoreStep(t), step, state) - assert.NoError(t, err) - assert.EqualValues(t, model.StatusRunning, step.State) - assert.EqualValues(t, 42, step.Started) - assert.EqualValues(t, 0, step.Finished) - assert.EqualValues(t, 0, step.ExitCode) - assert.EqualValues(t, "", step.Error) -} - -func TestUpdateStepStatusNotExitedButStopped(t *testing.T) { +func TestUpdateStepStatus(t *testing.T) { t.Parallel() - // step in db before update - step := &model.Step{Started: 42, Finished: 64, State: model.StatusKilled} + t.Run("Pending", func(t *testing.T) { + t.Parallel() - // advertised step status - state := rpc.StepState{ - Exited: false, - // Dummy data - Finished: int64(1), - ExitCode: pipeline.ExitCodeKilled, - Error: "not an error", - } + t.Run("TransitionToRunning", func(t *testing.T) { + t.Parallel() - err := UpdateStepStatus(mockStoreStep(t), step, state) - assert.NoError(t, err) - assert.EqualValues(t, model.StatusKilled, step.State) - assert.EqualValues(t, 42, step.Started) - assert.EqualValues(t, 64, step.Finished) - assert.EqualValues(t, 0, step.ExitCode) - assert.EqualValues(t, "", step.Error) -} + t.Run("WithStartTime", func(t *testing.T) { + t.Parallel() + step := &model.Step{State: model.StatusPending} + state := rpc.StepState{Started: 42, Finished: 0} -func TestUpdateStepStatusExited(t *testing.T) { - t.Parallel() + err := UpdateStepStatus(mockStoreStep(t), step, state) - // step in db before update - step := &model.Step{Started: 42} + assert.NoError(t, err) + assert.Equal(t, model.StatusRunning, step.State) + assert.Equal(t, int64(42), step.Started) + assert.Equal(t, int64(0), step.Finished) + }) - // advertised step status - state := rpc.StepState{ - Started: int64(42), - Exited: true, - Finished: int64(34), - ExitCode: pipeline.ExitCodeKilled, - Error: "an error", - } + t.Run("WithoutStartTime", func(t *testing.T) { + t.Parallel() + step := &model.Step{State: model.StatusPending} + state := rpc.StepState{Started: 0, Finished: 0} - err := UpdateStepStatus(mockStoreStep(t), step, state) - assert.NoError(t, err) - assert.EqualValues(t, model.StatusKilled, step.State) - assert.EqualValues(t, 42, step.Started) - assert.EqualValues(t, 34, step.Finished) - assert.EqualValues(t, pipeline.ExitCodeKilled, step.ExitCode) - assert.EqualValues(t, "an error", step.Error) -} + err := UpdateStepStatus(mockStoreStep(t), step, state) -func TestUpdateStepStatusExitedButNot137(t *testing.T) { - t.Parallel() + assert.NoError(t, err) + assert.Equal(t, model.StatusRunning, step.State) + assert.Greater(t, step.Started, int64(0)) + }) + }) - // step in db before update - step := &model.Step{Started: 42} + t.Run("DirectToSuccess", func(t *testing.T) { + t.Parallel() - // advertised step status - state := rpc.StepState{ - Started: int64(42), - Exited: true, - Finished: int64(34), - Error: "an error", - } + t.Run("WithFinishTime", func(t *testing.T) { + t.Parallel() + step := &model.Step{State: model.StatusPending} + state := rpc.StepState{Started: 42, Exited: true, Finished: 100, ExitCode: 0, Error: ""} - err := UpdateStepStatus(mockStoreStep(t), step, state) - assert.NoError(t, err) - assert.EqualValues(t, model.StatusFailure, step.State) - assert.EqualValues(t, 42, step.Started) - assert.EqualValues(t, 34, step.Finished) - assert.EqualValues(t, 0, step.ExitCode) - assert.EqualValues(t, "an error", step.Error) -} + err := UpdateStepStatus(mockStoreStep(t), step, state) -func TestUpdateStepStatusExitedWithCode(t *testing.T) { - t.Parallel() + assert.NoError(t, err) + assert.Equal(t, model.StatusSuccess, step.State) + assert.Equal(t, int64(42), step.Started) + assert.Equal(t, int64(100), step.Finished) + }) - // advertised step status - state := rpc.StepState{ - Started: int64(42), - Exited: true, - Finished: int64(34), - ExitCode: 1, - Error: "an error", - } - step := &model.Step{} - err := UpdateStepStatus(mockStoreStep(t), step, state) - assert.NoError(t, err) + t.Run("WithoutFinishTime", func(t *testing.T) { + t.Parallel() + step := &model.Step{State: model.StatusPending} + state := rpc.StepState{Started: 42, Exited: true, Finished: 0, ExitCode: 0, Error: ""} - assert.Equal(t, model.StatusFailure, step.State) - assert.Equal(t, 1, step.ExitCode) + err := UpdateStepStatus(mockStoreStep(t), step, state) + + assert.NoError(t, err) + assert.Equal(t, model.StatusSuccess, step.State) + assert.Greater(t, step.Finished, int64(0)) + }) + }) + + t.Run("DirectToFailure", func(t *testing.T) { + t.Parallel() + + t.Run("WithExitCode", func(t *testing.T) { + t.Parallel() + step := &model.Step{State: model.StatusPending} + state := rpc.StepState{Started: 42, Exited: true, Finished: 34, ExitCode: 1, Error: "an error"} + + err := UpdateStepStatus(mockStoreStep(t), step, state) + + assert.NoError(t, err) + assert.Equal(t, model.StatusFailure, step.State) + assert.Equal(t, 1, step.ExitCode) + assert.Equal(t, "an error", step.Error) + }) + }) + }) + + t.Run("Running", func(t *testing.T) { + t.Parallel() + + t.Run("ToSuccess", func(t *testing.T) { + t.Parallel() + + t.Run("WithFinishTime", func(t *testing.T) { + t.Parallel() + step := &model.Step{State: model.StatusRunning, Started: 42} + state := rpc.StepState{Exited: true, Finished: 100, ExitCode: 0, Error: ""} + + err := UpdateStepStatus(mockStoreStep(t), step, state) + + assert.NoError(t, err) + assert.Equal(t, model.StatusSuccess, step.State) + assert.Equal(t, int64(100), step.Finished) + }) + + t.Run("WithoutFinishTime", func(t *testing.T) { + t.Parallel() + step := &model.Step{State: model.StatusRunning, Started: 42} + state := rpc.StepState{Exited: true, Finished: 0, ExitCode: 0, Error: ""} + + err := UpdateStepStatus(mockStoreStep(t), step, state) + + assert.NoError(t, err) + assert.Equal(t, model.StatusSuccess, step.State) + assert.Greater(t, step.Finished, int64(0)) + }) + }) + + t.Run("ToFailure", func(t *testing.T) { + t.Parallel() + + t.Run("WithExitCode137", func(t *testing.T) { + t.Parallel() + step := &model.Step{State: model.StatusRunning, Started: 42} + state := rpc.StepState{Exited: true, Finished: 34, ExitCode: pipeline.ExitCodeKilled, Error: "an error"} + + err := UpdateStepStatus(mockStoreStep(t), step, state) + + assert.NoError(t, err) + assert.Equal(t, model.StatusFailure, step.State) + assert.Equal(t, int64(34), step.Finished) + assert.Equal(t, pipeline.ExitCodeKilled, step.ExitCode) + }) + + t.Run("WithError", func(t *testing.T) { + t.Parallel() + step := &model.Step{State: model.StatusRunning, Started: 42} + state := rpc.StepState{Exited: true, Finished: 34, ExitCode: 0, Error: "an error"} + + err := UpdateStepStatus(mockStoreStep(t), step, state) + + assert.NoError(t, err) + assert.Equal(t, model.StatusFailure, step.State) + assert.Equal(t, "an error", step.Error) + }) + }) + + t.Run("StillRunning", func(t *testing.T) { + t.Parallel() + step := &model.Step{State: model.StatusRunning, Started: 42} + state := rpc.StepState{Exited: false, Finished: 0} + + err := UpdateStepStatus(mockStoreStep(t), step, state) + + assert.NoError(t, err) + assert.Equal(t, model.StatusRunning, step.State) + assert.Equal(t, int64(0), step.Finished) + }) + }) + + t.Run("Canceled", func(t *testing.T) { + t.Parallel() + + t.Run("WithoutFinishTime", func(t *testing.T) { + t.Parallel() + step := &model.Step{State: model.StatusRunning, Started: 42} + state := rpc.StepState{Canceled: true} + + err := UpdateStepStatus(mockStoreStep(t), step, state) + + assert.NoError(t, err) + assert.Equal(t, model.StatusKilled, step.State) + assert.Greater(t, step.Finished, int64(0)) + }) + + t.Run("WithExitedAndFinishTime", func(t *testing.T) { + t.Parallel() + step := &model.Step{State: model.StatusRunning, Started: 42} + state := rpc.StepState{Canceled: true, Exited: true, Finished: 100, ExitCode: 1, Error: "canceled"} + + err := UpdateStepStatus(mockStoreStep(t), step, state) + + assert.NoError(t, err) + assert.Equal(t, model.StatusKilled, step.State) + assert.Equal(t, int64(100), step.Finished) + assert.Equal(t, 1, step.ExitCode) + assert.Equal(t, "canceled", step.Error) + }) + }) + + t.Run("TerminalState", func(t *testing.T) { + t.Parallel() + step := &model.Step{State: model.StatusKilled, Started: 42, Finished: 64} + state := rpc.StepState{Exited: false} + + err := UpdateStepStatus(mocks.NewMockStore(t), step, state) + + assert.Error(t, err) + assert.Contains(t, err.Error(), "does not expect rpc state updates") + assert.Equal(t, model.StatusKilled, step.State) + }) } func TestUpdateStepToStatusSkipped(t *testing.T) { t.Parallel() - step, _ := UpdateStepToStatusSkipped(mockStoreStep(t), model.Step{}, int64(1)) + t.Run("NotStarted", func(t *testing.T) { + t.Parallel() - assert.Equal(t, model.StatusSkipped, step.State) - assert.EqualValues(t, 0, step.Finished) -} + step, err := UpdateStepToStatusSkipped(mockStoreStep(t), model.Step{}, int64(1)) -func TestUpdateStepToStatusSkippedButStarted(t *testing.T) { - t.Parallel() + assert.NoError(t, err) + assert.Equal(t, model.StatusSkipped, step.State) + assert.Equal(t, int64(0), step.Finished) + }) - step := &model.Step{ - Started: int64(42), - } + t.Run("AlreadyStarted", func(t *testing.T) { + t.Parallel() - step, _ = UpdateStepToStatusSkipped(mockStoreStep(t), *step, int64(1)) + step, err := UpdateStepToStatusSkipped(mockStoreStep(t), model.Step{Started: 42}, int64(100)) - assert.Equal(t, model.StatusSuccess, step.State) - assert.EqualValues(t, 1, step.Finished) + assert.NoError(t, err) + assert.Equal(t, model.StatusSuccess, step.State) + assert.Equal(t, int64(100), step.Finished) + }) } diff --git a/server/pipeline/stepbuilder/step_builder.go b/server/pipeline/stepbuilder/step_builder.go index ab690ee1f..f98ca4f74 100644 --- a/server/pipeline/stepbuilder/step_builder.go +++ b/server/pipeline/stepbuilder/step_builder.go @@ -29,7 +29,6 @@ import ( "go.woodpecker-ci.org/woodpecker/v3/pipeline" backend_types "go.woodpecker-ci.org/woodpecker/v3/pipeline/backend/types" pipeline_errors "go.woodpecker-ci.org/woodpecker/v3/pipeline/errors" - errorTypes "go.woodpecker-ci.org/woodpecker/v3/pipeline/errors/types" "go.woodpecker-ci.org/woodpecker/v3/pipeline/frontend/metadata" "go.woodpecker-ci.org/woodpecker/v3/pipeline/frontend/yaml" "go.woodpecker-ci.org/woodpecker/v3/pipeline/frontend/yaml/compiler" @@ -139,7 +138,7 @@ func (b *StepBuilder) genItemForWorkflow(workflow *model.Workflow, axis matrix.A // parse yaml pipeline parsed, err := yaml.ParseString(substituted) if err != nil { - return nil, &errorTypes.PipelineError{Message: err.Error(), Type: errorTypes.PipelineErrorTypeCompiler} + return nil, &pipeline_errors.PipelineError{Message: err.Error(), Type: pipeline_errors.PipelineErrorTypeCompiler} } // lint pipeline diff --git a/server/pipeline/workflow_status.go b/server/pipeline/workflow_status.go index 12d2c15a7..6174aca13 100644 --- a/server/pipeline/workflow_status.go +++ b/server/pipeline/workflow_status.go @@ -15,11 +15,22 @@ package pipeline import ( - "go.woodpecker-ci.org/woodpecker/v3/pipeline/rpc" + "go.woodpecker-ci.org/woodpecker/v3/rpc" "go.woodpecker-ci.org/woodpecker/v3/server/model" "go.woodpecker-ci.org/woodpecker/v3/server/store" ) +// WorkflowStatus determine workflow status based on corresponding step list. +func WorkflowStatus(steps []*model.Step) model.StatusValue { + status := model.StatusSuccess + + for _, p := range steps { + status = MergeStatusValues(status, p.State) + } + + return status +} + func UpdateWorkflowStatusToRunning(store store.Store, workflow model.Workflow, state rpc.WorkflowState) (*model.Workflow, error) { workflow.Started = state.Started workflow.State = model.StatusRunning @@ -37,10 +48,13 @@ func UpdateWorkflowStatusToDone(store store.Store, workflow model.Workflow, stat if state.Started == 0 { workflow.State = model.StatusSkipped } else { - workflow.State = model.WorkflowStatus(workflow.Children) + workflow.State = WorkflowStatus(workflow.Children) } if workflow.Error != "" { workflow.State = model.StatusFailure } + if state.Canceled { + workflow.State = model.StatusKilled + } return &workflow, store.WorkflowUpdate(&workflow) } diff --git a/server/pipeline/workflow_status_test.go b/server/pipeline/workflow_status_test.go new file mode 100644 index 000000000..b5740ca8b --- /dev/null +++ b/server/pipeline/workflow_status_test.go @@ -0,0 +1,145 @@ +// Copyright 2026 Woodpecker Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package pipeline + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + + "go.woodpecker-ci.org/woodpecker/v3/rpc" + "go.woodpecker-ci.org/woodpecker/v3/server/model" + store_mocks "go.woodpecker-ci.org/woodpecker/v3/server/store/mocks" +) + +func TestUpdateWorkflowStatusToRunning(t *testing.T) { + t.Run("should update workflow to running status", func(t *testing.T) { + workflow := model.Workflow{ + ID: 1, + State: model.StatusPending, + } + state := rpc.WorkflowState{ + Started: 1234567890, + } + + mockStore := store_mocks.NewMockStore(t) + mockStore.On("WorkflowUpdate", mock.MatchedBy(func(w *model.Workflow) bool { + return w.ID == 1 && w.State == model.StatusRunning && w.Started == 1234567890 + })).Return(nil) + + result, err := UpdateWorkflowStatusToRunning(mockStore, workflow, state) + + assert.NoError(t, err) + assert.Equal(t, model.StatusRunning, result.State) + assert.Equal(t, int64(1234567890), result.Started) + mockStore.AssertCalled(t, "WorkflowUpdate", mock.Anything) + }) +} + +func TestUpdateWorkflowToStatusSkipped(t *testing.T) { + t.Run("should update workflow to skipped status", func(t *testing.T) { + workflow := model.Workflow{ + ID: 2, + State: model.StatusPending, + } + + mockStore := store_mocks.NewMockStore(t) + mockStore.On("WorkflowUpdate", mock.MatchedBy(func(w *model.Workflow) bool { + return w.ID == 2 && w.State == model.StatusSkipped + })).Return(nil) + + result, err := UpdateWorkflowToStatusSkipped(mockStore, workflow) + + assert.NoError(t, err) + assert.Equal(t, model.StatusSkipped, result.State) + mockStore.AssertCalled(t, "WorkflowUpdate", mock.Anything) + }) +} + +func TestUpdateWorkflowStatusToDone(t *testing.T) { + t.Run("should mark as skipped when not started", func(t *testing.T) { + workflow := model.Workflow{ + ID: 3, + State: model.StatusRunning, + Children: []*model.Step{}, + } + state := rpc.WorkflowState{ + Started: 0, // Not started + Finished: 1234567900, + Error: "", + } + + mockStore := store_mocks.NewMockStore(t) + mockStore.On("WorkflowUpdate", mock.MatchedBy(func(w *model.Workflow) bool { + return w.State == model.StatusSkipped && w.Finished == 1234567900 + })).Return(nil) + + result, err := UpdateWorkflowStatusToDone(mockStore, workflow, state) + + assert.NoError(t, err) + assert.Equal(t, model.StatusSkipped, result.State) + assert.Equal(t, int64(1234567900), result.Finished) + }) + + t.Run("should mark as failure when error exists", func(t *testing.T) { + workflow := model.Workflow{ + ID: 5, + State: model.StatusRunning, + Children: []*model.Step{}, + } + state := rpc.WorkflowState{ + Started: 1234567800, + Finished: 1234567900, + Error: "some error occurred", + } + + mockStore := store_mocks.NewMockStore(t) + mockStore.On("WorkflowUpdate", mock.MatchedBy(func(w *model.Workflow) bool { + return w.State == model.StatusFailure + })).Return(nil) + + result, err := UpdateWorkflowStatusToDone(mockStore, workflow, state) + + assert.NoError(t, err) + assert.Equal(t, model.StatusFailure, result.State) + assert.Equal(t, "some error occurred", result.Error) + }) + + t.Run("should mark as success when all children are successful", func(t *testing.T) { + successStep := &model.Step{ + ID: 1, + State: model.StatusSuccess, + } + workflow := model.Workflow{ + ID: 6, + State: model.StatusRunning, + Children: []*model.Step{successStep}, + } + state := rpc.WorkflowState{ + Started: 1234567800, + Finished: 1234567900, + Error: "", + } + + mockStore := store_mocks.NewMockStore(t) + mockStore.On("WorkflowUpdate", mock.Anything).Return(nil) + + result, err := UpdateWorkflowStatusToDone(mockStore, workflow, state) + + assert.NoError(t, err) + assert.Equal(t, int64(1234567900), result.Finished) + }) +} diff --git a/server/queue/LICENSE b/server/queue/LICENSE deleted file mode 100644 index 64e202179..000000000 --- a/server/queue/LICENSE +++ /dev/null @@ -1,29 +0,0 @@ -BSD 3-Clause License - -Copyright (c) 2017, Brad Rydzewski -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -* Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/server/queue/fifo.go b/server/queue/fifo.go index c4bd11abf..e215c817a 100644 --- a/server/queue/fifo.go +++ b/server/queue/fifo.go @@ -17,7 +17,7 @@ package queue import ( "container/list" "context" - "fmt" + "errors" "slices" "sync" "time" @@ -58,8 +58,6 @@ type fifo struct { // as the agent pull in 10 milliseconds we should also give them work asap. const processTimeInterval = 100 * time.Millisecond -var ErrWorkerKicked = fmt.Errorf("worker was kicked") - // NewMemoryQueue returns a new fifo queue. func NewMemoryQueue(ctx context.Context) Queue { q := &fifo{ @@ -90,23 +88,23 @@ func (q *fifo) Poll(c context.Context, agentID int64, filter FilterFn) (*model.T q.Lock() ctx, stop := context.WithCancelCause(c) - _worker := &worker{ + w := &worker{ agentID: agentID, channel: make(chan *model.Task, 1), filter: filter, stop: stop, } - q.workers[_worker] = struct{}{} + q.workers[w] = struct{}{} q.Unlock() for { select { case <-ctx.Done(): q.Lock() - delete(q.workers, _worker) + delete(q.workers, w) q.Unlock() return nil, ctx.Err() - case t := <-_worker.channel: + case t := <-w.channel: return t, nil } } @@ -122,50 +120,47 @@ func (q *fifo) Error(_ context.Context, id string, err error) error { return q.finished([]string{id}, model.StatusFailure, err) } -// ErrorAtOnce signals multiple done are complete with an error. +// ErrorAtOnce signals multiple tasks are done and complete with an error. +// If still pending they will just get removed from the queue. func (q *fifo) ErrorAtOnce(_ context.Context, ids []string, err error) error { + if errors.Is(err, ErrCancel) { + return q.finished(ids, model.StatusKilled, err) + } return q.finished(ids, model.StatusFailure, err) } +// locks the queue itself! func (q *fifo) finished(ids []string, exitStatus model.StatusValue, err error) error { q.Lock() + defer q.Unlock() + // it's an external error so we wrap it + err = NewErrExternal(err) + + var errs []error + // we first process the tasks itself for _, id := range ids { - taskEntry, ok := q.running[id] - if ok { + if taskEntry, ok := q.running[id]; ok { taskEntry.error = err close(taskEntry.done) delete(q.running, id) } else { - q.removeFromPending(id) + errs = append(errs, q.removeFromPendingAndWaiting(id)) } + } + + // next we aim for there dependencies + // we do this because in our ids list there could be tasks and its dependencies + // so not to mess things up + for _, id := range ids { q.updateDepStatusInQueue(id, exitStatus) } - q.Unlock() - return nil -} - -// EvictAtOnce removes multiple pending tasks from the queue. -func (q *fifo) EvictAtOnce(_ context.Context, taskIDs []string) error { - q.Lock() - defer q.Unlock() - - for _, id := range taskIDs { - var next *list.Element - for element := q.pending.Front(); element != nil; element = next { - next = element.Next() - task, ok := element.Value.(*model.Task) - if ok && task.ID == id { - q.pending.Remove(element) - return nil - } - } - } - return ErrNotFound + return errors.Join(errs...) } // Wait waits until the item is done executing. +// Also signals via error ErrCancel if workflow got canceled. func (q *fifo) Wait(ctx context.Context, taskID string) error { q.Lock() state := q.running[taskID] @@ -174,7 +169,10 @@ func (q *fifo) Wait(ctx context.Context, taskID string) error { select { case <-ctx.Done(): case <-state.done: - return state.error + // only return queue errors and no workflow errors + if !errors.Is(state.error, new(ErrExternal)) { + return state.error + } } } return nil @@ -286,19 +284,15 @@ func (q *fifo) process() { func (q *fifo) filterWaiting() { // resubmits all waiting tasks to pending, deps may have cleared - var nextWaiting *list.Element - for e := q.waitingOnDeps.Front(); e != nil; e = nextWaiting { - nextWaiting = e.Next() - task, _ := e.Value.(*model.Task) + for element := q.waitingOnDeps.Front(); element != nil; element = element.Next() { + task, _ := element.Value.(*model.Task) q.pending.PushBack(task) } // rebuild waitingDeps q.waitingOnDeps = list.New() var filtered []*list.Element - var nextPending *list.Element - for element := q.pending.Front(); element != nil; element = nextPending { - nextPending = element.Next() + for element := q.pending.Front(); element != nil; element = element.Next() { task, _ := element.Value.(*model.Task) if q.depsInQueue(task) { log.Debug().Msgf("queue: waiting due to unmet dependencies %v", task.ID) @@ -314,12 +308,10 @@ func (q *fifo) filterWaiting() { } func (q *fifo) assignToWorker() (*list.Element, *worker) { - var next *list.Element var bestWorker *worker var bestScore int - for element := q.pending.Front(); element != nil; element = next { - next = element.Next() + for element := q.pending.Front(); element != nil; element = element.Next() { task, _ := element.Value.(*model.Task) log.Debug().Msgf("queue: trying to assign task: %v with deps %v", task.ID, task.Dependencies) @@ -352,9 +344,7 @@ func (q *fifo) resubmitExpiredPipelines() { } func (q *fifo) depsInQueue(task *model.Task) bool { - var next *list.Element - for element := q.pending.Front(); element != nil; element = next { - next = element.Next() + for element := q.pending.Front(); element != nil; element = element.Next() { possibleDep, ok := element.Value.(*model.Task) log.Debug().Msgf("queue: pending right now: %v", possibleDep.ID) for _, dep := range task.Dependencies { @@ -372,13 +362,12 @@ func (q *fifo) depsInQueue(task *model.Task) bool { return false } +// expects the q to be currently owned e.g. locked by caller! func (q *fifo) updateDepStatusInQueue(taskID string, status model.StatusValue) { - var next *list.Element - for element := q.pending.Front(); element != nil; element = next { - next = element.Next() - pending, ok := element.Value.(*model.Task) + for element := q.pending.Front(); element != nil; element = element.Next() { + pending, _ := element.Value.(*model.Task) for _, dep := range pending.Dependencies { - if ok && taskID == dep { + if taskID == dep { pending.DepStatus[dep] = status } } @@ -392,27 +381,40 @@ func (q *fifo) updateDepStatusInQueue(taskID string, status model.StatusValue) { } } - for element := q.waitingOnDeps.Front(); element != nil; element = next { - next = element.Next() - waiting, ok := element.Value.(*model.Task) + for element := q.waitingOnDeps.Front(); element != nil; element = element.Next() { + waiting, _ := element.Value.(*model.Task) for _, dep := range waiting.Dependencies { - if ok && taskID == dep { + if taskID == dep { waiting.DepStatus[dep] = status } } } } -func (q *fifo) removeFromPending(taskID string) { +// expects the q to be currently owned e.g. locked by caller! +func (q *fifo) removeFromPendingAndWaiting(taskID string) error { log.Debug().Msgf("queue: trying to remove %s", taskID) - var next *list.Element - for element := q.pending.Front(); element != nil; element = next { - next = element.Next() + + // we assume pending first + for element := q.pending.Front(); element != nil; element = element.Next() { task, _ := element.Value.(*model.Task) if task.ID == taskID { log.Debug().Msgf("queue: %s is removed from pending", taskID) - q.pending.Remove(element) - return + _ = q.pending.Remove(element) + return nil } } + + // well looks like it's waiting + for element := q.waitingOnDeps.Front(); element != nil; element = element.Next() { + task, _ := element.Value.(*model.Task) + if task.ID == taskID { + log.Debug().Msgf("queue: %s is removed from waitingOnDeps", taskID) + _ = q.waitingOnDeps.Remove(element) + return nil + } + } + + // well it could not be found + return ErrNotFound } diff --git a/server/queue/fifo_test.go b/server/queue/fifo_test.go index 6270a0337..2904d503f 100644 --- a/server/queue/fifo_test.go +++ b/server/queue/fifo_test.go @@ -38,634 +38,963 @@ var ( waitForProcess = func() { time.Sleep(processTimeInterval + 50*time.Millisecond) } ) -func TestFifo(t *testing.T) { - ctx, cancel := context.WithCancelCause(t.Context()) - t.Cleanup(func() { cancel(nil) }) - - q := NewMemoryQueue(ctx) - dummyTask := genDummyTask() - - assert.NoError(t, q.PushAtOnce(ctx, []*model.Task{dummyTask})) - waitForProcess() - info := q.Info(ctx) - assert.Len(t, info.Pending, 1, "expect task in pending queue") - - got, err := q.Poll(ctx, 1, filterFnTrue) - assert.NoError(t, err) - assert.Equal(t, dummyTask, got) - - waitForProcess() - info = q.Info(ctx) - assert.Len(t, info.Pending, 0, "expect task removed from pending queue") - assert.Len(t, info.Running, 1, "expect task in running queue") - - assert.NoError(t, q.Done(ctx, got.ID, model.StatusSuccess)) - - waitForProcess() - info = q.Info(ctx) - assert.Len(t, info.Pending, 0, "expect task removed from pending queue") - assert.Len(t, info.Running, 0, "expect task removed from running queue") -} - -func TestFifoExpire(t *testing.T) { +func setupTestQueue(t *testing.T) (context.Context, context.CancelCauseFunc, *fifo) { ctx, cancel := context.WithCancelCause(t.Context()) t.Cleanup(func() { cancel(nil) }) q, _ := NewMemoryQueue(ctx).(*fifo) - assert.NotNil(t, q) - - dummyTask := genDummyTask() - - q.extension = 0 - assert.NoError(t, q.PushAtOnce(ctx, []*model.Task{dummyTask})) - waitForProcess() - info := q.Info(ctx) - assert.Len(t, info.Pending, 1, "expect task in pending queue") - - got, err := q.Poll(ctx, 1, filterFnTrue) - assert.NoError(t, err) - assert.Equal(t, dummyTask, got) - - waitForProcess() - info = q.Info(ctx) - assert.Len(t, info.Pending, 1, "expect task re-added to pending queue") -} - -func TestFifoWaitOnExpireReturnsError(t *testing.T) { - ctx, cancel := context.WithCancelCause(t.Context()) - t.Cleanup(func() { cancel(nil) }) - - q, _ := NewMemoryQueue(ctx).(*fifo) - assert.NotNil(t, q) - - q.extension = 0 - - dummyTask := genDummyTask() - assert.NoError(t, q.PushAtOnce(ctx, []*model.Task{dummyTask})) - - waitForProcess() - got, err := q.Poll(ctx, 1, filterFnTrue) - assert.NoError(t, err) - assert.Equal(t, dummyTask, got) - - errCh := make(chan error, 1) - go func() { - errCh <- q.Wait(ctx, got.ID) - }() - - waitForProcess() - - select { - case werr := <-errCh: - assert.Error(t, werr, "expected Wait to return error when lease expires") - case <-time.After(2 * time.Second): - t.Fatal("timeout waiting for Wait to return after lease expiration") + if q == nil { + t.Fatal("Failed to create queue") } - info := q.Info(ctx) - assert.Len(t, info.Pending, 1, "expect task re-added to pending queue after expiration") + return ctx, cancel, q } -func TestFifoWait(t *testing.T) { - ctx, cancel := context.WithCancelCause(t.Context()) - t.Cleanup(func() { cancel(nil) }) +func TestFifoBasicOperations(t *testing.T) { + ctx, cancel, q := setupTestQueue(t) + defer cancel(nil) - q, _ := NewMemoryQueue(ctx).(*fifo) - assert.NotNil(t, q) + t.Run("push poll done lifecycle", func(t *testing.T) { + dummyTask := genDummyTask() - dummyTask := genDummyTask() + assert.NoError(t, q.PushAtOnce(ctx, []*model.Task{dummyTask})) + waitForProcess() - assert.NoError(t, q.PushAtOnce(ctx, []*model.Task{dummyTask})) + info := q.Info(ctx) + assert.Len(t, info.Pending, 1) - waitForProcess() - got, err := q.Poll(ctx, 1, filterFnTrue) - assert.NoError(t, err) - assert.Equal(t, dummyTask, got) + got, err := q.Poll(ctx, 1, filterFnTrue) + assert.NoError(t, err) + assert.Equal(t, dummyTask, got) - var wg sync.WaitGroup - wg.Add(1) - go func() { - assert.NoError(t, q.Wait(ctx, got.ID)) - wg.Done() - }() + waitForProcess() + info = q.Info(ctx) + assert.Len(t, info.Pending, 0) + assert.Len(t, info.Running, 1) - <-time.After(time.Millisecond) - assert.NoError(t, q.Done(ctx, got.ID, model.StatusSuccess)) - wg.Wait() + // Edge case: verify task can't be polled again while running + pollCtx, pollCancel := context.WithTimeout(ctx, 100*time.Millisecond) + _, err = q.Poll(pollCtx, 2, filterFnTrue) + pollCancel() + assert.Error(t, err) // Should timeout/cancel, not return the same task + + assert.NoError(t, q.Done(ctx, got.ID, model.StatusSuccess)) + + waitForProcess() + info = q.Info(ctx) + assert.Len(t, info.Running, 0) + + // Edge case: Done on already completed task should handle gracefully + err = q.Done(ctx, got.ID, model.StatusSuccess) + // Document current behavior - should either error or be idempotent + if err != nil { + assert.Error(t, err) + } + }) + + t.Run("error handling", func(t *testing.T) { + task1 := &model.Task{ID: "task-error-1"} + assert.NoError(t, q.PushAtOnce(ctx, []*model.Task{task1})) + + waitForProcess() + got, _ := q.Poll(ctx, 1, filterFnTrue) + + assert.NoError(t, q.Error(ctx, got.ID, fmt.Errorf("test error"))) + waitForProcess() + info := q.Info(ctx) + assert.Len(t, info.Running, 0) + + assert.Error(t, q.Error(ctx, "totally-fake-id", fmt.Errorf("test error"))) + + // Edge case: Error on task that's already errored + err := q.Error(ctx, got.ID, fmt.Errorf("double error")) + // Should either error or be idempotent + if err != nil { + assert.Error(t, err) + } + }) + + t.Run("external error filtered by Wait", func(t *testing.T) { + // Test that external errors (from Error/ErrorAtOnce) are wrapped as ErrExternal + // and filtered out by Wait(), while internal errors like context cancellation + // are passed through + + // Test 1: External error is filtered by Wait + task1 := &model.Task{ID: "wait-external-1"} + assert.NoError(t, q.PushAtOnce(ctx, []*model.Task{task1})) + waitForProcess() + + got1, err := q.Poll(ctx, 1, filterFnTrue) + assert.NoError(t, err) + + // Start waiting on the task + waitDone := make(chan error, 1) + go func() { + waitDone <- q.Wait(ctx, got1.ID) + }() + + time.Sleep(10 * time.Millisecond) + + // Report an external error (agent reported error) + externalErr := fmt.Errorf("agent reported error") + assert.NoError(t, q.Error(ctx, got1.ID, externalErr)) + + // Wait should return nil (external error filtered out) + select { + case err := <-waitDone: + assert.NoError(t, err, "Wait should filter ErrExternal and return nil") + case <-time.After(time.Second): + t.Fatal("Wait should have returned") + } + + // Test 2: Internal error (context cancellation) passes through Wait + task2 := &model.Task{ID: "wait-internal-1"} + assert.NoError(t, q.PushAtOnce(ctx, []*model.Task{task2})) + waitForProcess() + + got2, err := q.Poll(ctx, 2, filterFnTrue) + assert.NoError(t, err) + + waitCtx, waitCancel := context.WithCancelCause(ctx) + waitDone2 := make(chan error, 1) + go func() { + waitDone2 <- q.Wait(waitCtx, got2.ID) + }() + + time.Sleep(10 * time.Millisecond) + waitCancel(nil) + + // Context cancellation should cause Wait to return (internal error handling) + select { + case err := <-waitDone2: + // Wait returns nil when context is canceled (normal behavior) + assert.NoError(t, err, "Wait should return nil when context is canceled") + case <-time.After(time.Second): + t.Fatal("Wait should return when context is canceled") + } + + // Clean up + assert.NoError(t, q.Done(ctx, got2.ID, model.StatusSuccess)) + waitForProcess() + + // Test 3: Multiple waiters all get nil when external error occurs + task3 := &model.Task{ID: "wait-multi-1"} + assert.NoError(t, q.PushAtOnce(ctx, []*model.Task{task3})) + waitForProcess() + + got3, err := q.Poll(ctx, 3, filterFnTrue) + assert.NoError(t, err) + + // Start multiple waiters + numWaiters := 3 + waitResults := make(chan error, numWaiters) + for i := 0; i < numWaiters; i++ { + go func() { + waitResults <- q.Wait(ctx, got3.ID) + }() + } + + time.Sleep(10 * time.Millisecond) + + // Report an external error + batchErr := fmt.Errorf("external batch failure") + assert.NoError(t, q.ErrorAtOnce(ctx, []string{got3.ID}, batchErr)) + + // All waiters should return nil (external error filtered) + for i := 0; i < numWaiters; i++ { + select { + case err := <-waitResults: + assert.NoError(t, err, "All waiters should get nil when ErrExternal is filtered") + case <-time.After(time.Second): + t.Fatalf("Waiter %d didn't return in time", i) + } + } + }) + + t.Run("error at once", func(t *testing.T) { + task1 := &model.Task{ID: "batch-1"} + task2 := &model.Task{ID: "batch-2"} + task3 := &model.Task{ID: "batch-3"} + + assert.NoError(t, q.PushAtOnce(ctx, []*model.Task{task1, task2, task3})) + waitForProcess() + + got1, _ := q.Poll(ctx, 1, filterFnTrue) + got2, _ := q.Poll(ctx, 2, filterFnTrue) + + assert.NoError(t, q.ErrorAtOnce(ctx, []string{got1.ID, got2.ID}, fmt.Errorf("batch error"))) + waitForProcess() + info := q.Info(ctx) + assert.Len(t, info.Running, 0) + assert.Len(t, info.Pending, 1) + + got3, _ := q.Poll(ctx, 1, filterFnTrue) + assert.NoError(t, q.Done(ctx, got3.ID, model.StatusSuccess)) + waitForProcess() + + task4 := &model.Task{ID: "batch-4"} + assert.NoError(t, q.PushAtOnce(ctx, []*model.Task{task4})) + waitForProcess() + got4, _ := q.Poll(ctx, 1, filterFnTrue) + + err := q.ErrorAtOnce(ctx, []string{got4.ID, "fake-1", "fake-2"}, fmt.Errorf("test")) + assert.Error(t, err) + assert.ErrorIs(t, err, ErrNotFound) + + waitForProcess() + info = q.Info(ctx) + assert.Len(t, info.Running, 0) + + // Edge case: ErrorAtOnce with empty slice + err = q.ErrorAtOnce(ctx, []string{}, fmt.Errorf("no tasks")) + assert.NoError(t, err) + // Should handle gracefully, potentially no-op + + // Edge case: ErrorAtOnce with nil error + task5 := &model.Task{ID: "batch-5"} + assert.NoError(t, q.PushAtOnce(ctx, []*model.Task{task5})) + waitForProcess() + got5, _ := q.Poll(ctx, 3, filterFnTrue) + err = q.ErrorAtOnce(ctx, []string{got5.ID}, nil) + assert.NoError(t, err) + // Should handle nil error gracefully + waitForProcess() + }) + + t.Run("error at once with waiting deps", func(t *testing.T) { + task5 := &model.Task{ID: "deps-cancel-5"} + task6 := &model.Task{ + ID: "deps-cancel-6", + Dependencies: []string{"deps-cancel-5"}, + DepStatus: make(map[string]model.StatusValue), + } + + assert.NoError(t, q.PushAtOnce(ctx, []*model.Task{task5, task6})) + waitForProcess() + + info := q.Info(ctx) + assert.Equal(t, 1, info.Stats.WaitingOnDeps) + + assert.NoError(t, q.ErrorAtOnce(ctx, []string{"deps-cancel-5", "deps-cancel-6"}, fmt.Errorf("canceled"))) + + waitForProcess() + info = q.Info(ctx) + assert.Equal(t, 0, info.Stats.WaitingOnDeps) + assert.Len(t, info.Pending, 0) + + // Edge case: verify both tasks are actually gone, not stuck somewhere + assert.Len(t, info.Running, 0) + assert.Len(t, info.WaitingOnDeps, 0) + }) + + t.Run("error at once cancellation", func(t *testing.T) { + task1 := &model.Task{ID: "cancel-prop-1"} + task2 := &model.Task{ + ID: "cancel-prop-2", + Dependencies: []string{"cancel-prop-1"}, + DepStatus: make(map[string]model.StatusValue), + RunOn: []string{"success", "failure"}, + } + + assert.NoError(t, q.PushAtOnce(ctx, []*model.Task{task1, task2})) + waitForProcess() + got1, _ := q.Poll(ctx, 1, filterFnTrue) + + assert.NoError(t, q.ErrorAtOnce(ctx, []string{got1.ID}, ErrCancel)) + + waitForProcess() + waitForProcess() + + got2, _ := q.Poll(ctx, 2, filterFnTrue) + assert.Equal(t, model.StatusKilled, got2.DepStatus["cancel-prop-1"]) + + // Edge case: verify ErrCancel results in StatusKilled not StatusFailure + assert.NotEqual(t, model.StatusFailure, got2.DepStatus["cancel-prop-1"]) + assert.NoError(t, q.Done(ctx, got2.ID, model.StatusSuccess)) + waitForProcess() + }) + + t.Run("pause resume", func(t *testing.T) { + dummyTask := &model.Task{ID: "pause-1"} + + var wg sync.WaitGroup + wg.Add(1) + go func() { + _, _ = q.Poll(ctx, 99, filterFnTrue) + wg.Done() + }() + + q.Pause() + t0 := time.Now() + assert.NoError(t, q.PushAtOnce(ctx, []*model.Task{dummyTask})) + waitForProcess() + + // Edge case: verify queue is actually paused + info := q.Info(ctx) + assert.True(t, info.Paused) + assert.Len(t, info.Pending, 1) + assert.Len(t, info.Running, 0) + + q.Resume() + + wg.Wait() + assert.Greater(t, time.Since(t0), 20*time.Millisecond) + + // Edge case: verify queue is unpaused + info = q.Info(ctx) + assert.False(t, info.Paused) + + // Edge case: multiple pause/resume cycles + task2 := &model.Task{ID: "pause-2"} + q.Pause() + q.Pause() // Double pause + assert.NoError(t, q.PushAtOnce(ctx, []*model.Task{task2})) + waitForProcess() + q.Resume() + q.Resume() // Double resume + waitForProcess() + got, _ := q.Poll(ctx, 99, filterFnTrue) + assert.NoError(t, q.Done(ctx, got.ID, model.StatusSuccess)) + waitForProcess() + }) } func TestFifoDependencies(t *testing.T) { - ctx, cancel := context.WithCancelCause(t.Context()) - t.Cleanup(func() { cancel(nil) }) + ctx, cancel, q := setupTestQueue(t) + defer cancel(nil) - task1 := genDummyTask() - task2 := &model.Task{ - ID: "2", - Dependencies: []string{"1"}, - DepStatus: make(map[string]model.StatusValue), - } + t.Run("basic dependency handling", func(t *testing.T) { + task1 := &model.Task{ID: "dep-basic-1"} + task2 := &model.Task{ + ID: "dep-basic-2", + Dependencies: []string{"dep-basic-1"}, + DepStatus: make(map[string]model.StatusValue), + } + task3 := &model.Task{ + ID: "dep-basic-3", + Dependencies: []string{"dep-basic-1"}, + DepStatus: make(map[string]model.StatusValue), + RunOn: []string{"success", "failure"}, + } - q, _ := NewMemoryQueue(ctx).(*fifo) - assert.NotNil(t, q) + assert.NoError(t, q.PushAtOnce(ctx, []*model.Task{task2, task3, task1})) + waitForProcess() - assert.NoError(t, q.PushAtOnce(ctx, []*model.Task{task2, task1})) + info := q.Info(ctx) + assert.Equal(t, 2, info.Stats.WaitingOnDeps) - waitForProcess() - got, err := q.Poll(ctx, 1, filterFnTrue) - assert.NoError(t, err) - assert.Equal(t, task1, got) + got, err := q.Poll(ctx, 1, filterFnTrue) + assert.NoError(t, err) + assert.Equal(t, task1, got) + assert.NoError(t, q.Error(ctx, got.ID, fmt.Errorf("exit code 1"))) - waitForProcess() - assert.NoError(t, q.Done(ctx, got.ID, model.StatusSuccess)) + waitForProcess() + got, err = q.Poll(ctx, 1, filterFnTrue) + assert.NoError(t, err) + assert.Equal(t, task2, got) + assert.False(t, got.ShouldRun()) + assert.Equal(t, model.StatusFailure, got.DepStatus["dep-basic-1"]) - waitForProcess() - got, err = q.Poll(ctx, 1, filterFnTrue) - assert.NoError(t, err) - assert.Equal(t, task2, got) + waitForProcess() + got, err = q.Poll(ctx, 1, filterFnTrue) + assert.NoError(t, err) + assert.Equal(t, task3, got) + assert.True(t, got.ShouldRun()) + assert.Equal(t, model.StatusFailure, got.DepStatus["dep-basic-1"]) + + waitForProcess() + info = q.Info(ctx) + assert.Equal(t, 0, info.Stats.WaitingOnDeps) + + // Edge case: verify DepStatus is correctly set before polling + assert.NotEmpty(t, task2.DepStatus) + assert.NotEmpty(t, task3.DepStatus) + }) + + t.Run("multiple dependencies", func(t *testing.T) { + task1 := &model.Task{ID: "multi-dep-1"} + task2 := &model.Task{ID: "multi-dep-2"} + task3 := &model.Task{ + ID: "multi-dep-3", + Dependencies: []string{"multi-dep-1", "multi-dep-2"}, + DepStatus: make(map[string]model.StatusValue), + } + + assert.NoError(t, q.PushAtOnce(ctx, []*model.Task{task2, task3, task1})) + waitForProcess() + + got1, _ := q.Poll(ctx, 1, filterFnTrue) + got2, _ := q.Poll(ctx, 2, filterFnTrue) + + gotIDs := map[string]bool{got1.ID: true, got2.ID: true} + assert.True(t, gotIDs["multi-dep-1"] && gotIDs["multi-dep-2"]) + + if got1.ID == "multi-dep-1" { + assert.NoError(t, q.Done(ctx, got1.ID, model.StatusSuccess)) + assert.NoError(t, q.Error(ctx, got2.ID, fmt.Errorf("failed"))) + } else { + assert.NoError(t, q.Done(ctx, got2.ID, model.StatusSuccess)) + assert.NoError(t, q.Error(ctx, got1.ID, fmt.Errorf("failed"))) + } + + waitForProcess() + got3, err := q.Poll(ctx, 3, filterFnTrue) + assert.NoError(t, err) + + assert.Contains(t, got3.DepStatus, "multi-dep-1") + assert.Contains(t, got3.DepStatus, "multi-dep-2") + assert.True(t, + (got3.DepStatus["multi-dep-1"] == model.StatusSuccess && got3.DepStatus["multi-dep-2"] == model.StatusFailure) || + (got3.DepStatus["multi-dep-1"] == model.StatusFailure && got3.DepStatus["multi-dep-2"] == model.StatusSuccess)) + assert.False(t, got3.ShouldRun()) + + // Edge case: verify both deps are tracked + assert.Len(t, got3.DepStatus, 2) + assert.NoError(t, q.Done(ctx, got3.ID, model.StatusSkipped)) + waitForProcess() + }) + + t.Run("transitive dependencies", func(t *testing.T) { + task1 := &model.Task{ID: "trans-1"} + task2 := &model.Task{ + ID: "trans-2", + Dependencies: []string{"trans-1"}, + DepStatus: make(map[string]model.StatusValue), + } + task3 := &model.Task{ + ID: "trans-3", + Dependencies: []string{"trans-2"}, + DepStatus: make(map[string]model.StatusValue), + } + + assert.NoError(t, q.PushAtOnce(ctx, []*model.Task{task2, task3, task1})) + waitForProcess() + + got, _ := q.Poll(ctx, 1, filterFnTrue) + assert.NoError(t, q.Error(ctx, got.ID, fmt.Errorf("exit code 1"))) + + waitForProcess() + got, _ = q.Poll(ctx, 2, filterFnTrue) + assert.False(t, got.ShouldRun()) + assert.NoError(t, q.Done(ctx, got.ID, model.StatusSkipped)) + + waitForProcess() + got, _ = q.Poll(ctx, 3, filterFnTrue) + assert.Equal(t, model.StatusSkipped, got.DepStatus["trans-2"]) + assert.False(t, got.ShouldRun()) + + // Edge case: verify transitive failure propagates correctly + // task3 should see trans-2 as skipped, not trans-1's status + assert.NotContains(t, got.DepStatus, "trans-1") + assert.NoError(t, q.Done(ctx, got.ID, model.StatusSkipped)) + waitForProcess() + }) + + t.Run("dependency status propagation", func(t *testing.T) { + task1 := &model.Task{ID: "prop-1"} + task2 := &model.Task{ + ID: "prop-2", + Dependencies: []string{"prop-1"}, + DepStatus: make(map[string]model.StatusValue), + } + task3 := &model.Task{ + ID: "prop-3", + Dependencies: []string{"prop-1"}, + DepStatus: make(map[string]model.StatusValue), + RunOn: []string{"success", "failure"}, + } + + assert.NoError(t, q.PushAtOnce(ctx, []*model.Task{task1, task2, task3})) + waitForProcess() + + info := q.Info(ctx) + assert.Equal(t, 2, info.Stats.WaitingOnDeps) + + got1, _ := q.Poll(ctx, 1, filterFnTrue) + assert.NoError(t, q.Done(ctx, got1.ID, model.StatusSuccess)) + + waitForProcess() + + got2, _ := q.Poll(ctx, 2, filterFnTrue) + got3, _ := q.Poll(ctx, 3, filterFnTrue) + + assert.Equal(t, model.StatusSuccess, got2.DepStatus["prop-1"]) + assert.Equal(t, model.StatusSuccess, got3.DepStatus["prop-1"]) + + // Edge case: verify both tasks can be polled concurrently + assert.NotEqual(t, got2.ID, got3.ID) + assert.NoError(t, q.Done(ctx, got2.ID, model.StatusSuccess)) + assert.NoError(t, q.Done(ctx, got3.ID, model.StatusSuccess)) + waitForProcess() + + task4 := &model.Task{ID: "prop-4"} + task5 := &model.Task{ + ID: "prop-5", + Dependencies: []string{"prop-4"}, + DepStatus: make(map[string]model.StatusValue), + } + task6 := &model.Task{ + ID: "prop-6", + Dependencies: []string{"prop-4"}, + DepStatus: make(map[string]model.StatusValue), + RunOn: []string{"success", "failure"}, + } + + assert.NoError(t, q.PushAtOnce(ctx, []*model.Task{task4, task5, task6})) + waitForProcess() + + got4, _ := q.Poll(ctx, 4, filterFnTrue) + assert.NoError(t, q.Error(ctx, got4.ID, fmt.Errorf("failed"))) + + waitForProcess() + + got5, _ := q.Poll(ctx, 5, filterFnTrue) + assert.Equal(t, model.StatusFailure, got5.DepStatus["prop-4"]) + assert.False(t, got5.ShouldRun()) + + got6, _ := q.Poll(ctx, 6, filterFnTrue) + assert.Equal(t, model.StatusFailure, got6.DepStatus["prop-4"]) + assert.True(t, got6.ShouldRun()) + + // Edge case: complete dependent tasks + assert.NoError(t, q.Done(ctx, got5.ID, model.StatusSkipped)) + assert.NoError(t, q.Done(ctx, got6.ID, model.StatusSuccess)) + waitForProcess() + }) + + // Edge case: circular dependency detection (should be handled or cause issue) + t.Run("circular dependencies", func(t *testing.T) { + task1 := &model.Task{ + ID: "circ-1", + Dependencies: []string{"circ-2"}, + DepStatus: make(map[string]model.StatusValue), + } + task2 := &model.Task{ + ID: "circ-2", + Dependencies: []string{"circ-1"}, + DepStatus: make(map[string]model.StatusValue), + } + + assert.NoError(t, q.PushAtOnce(ctx, []*model.Task{task1, task2})) + waitForProcess() + + info := q.Info(ctx) + // Both should be waiting on deps - this is a deadlock scenario + assert.Equal(t, 2, info.Stats.WaitingOnDeps) + assert.Len(t, info.Pending, 0) + + // Verify they never become available for polling + pollCtx, pollCancel := context.WithTimeout(ctx, 200*time.Millisecond) + _, err := q.Poll(pollCtx, 99, filterFnTrue) + pollCancel() + assert.Error(t, err) // Should timeout + + // Clean up the deadlocked tasks + assert.NoError(t, q.ErrorAtOnce(ctx, []string{"circ-1", "circ-2"}, fmt.Errorf("circular dep"))) + waitForProcess() + }) + + // Edge case: dependency on non-existent task + // NOTE: This reveals a potential issue - the queue doesn't validate dependencies exist. + // If a dependency was never added to the queue, the task will run immediately since + // depsInQueue() only checks currently pending/running tasks, not if deps will arrive. + t.Run("non-existent dependency", func(t *testing.T) { + task1 := &model.Task{ + ID: "orphan-1", + Dependencies: []string{"does-not-exist"}, + DepStatus: make(map[string]model.StatusValue), + } + + assert.NoError(t, q.PushAtOnce(ctx, []*model.Task{task1})) + waitForProcess() + + info := q.Info(ctx) + // Current implementation: task doesn't wait if dependency not in queue + // This means tasks with typos in dependency names will run immediately! + assert.Equal(t, 0, info.Stats.WaitingOnDeps) + assert.Len(t, info.Pending, 1) + + // Task will be available for polling even though dependency doesn't exist + got, err := q.Poll(ctx, 99, filterFnTrue) + assert.NoError(t, err) + assert.Equal(t, "orphan-1", got.ID) + + // DepStatus will be empty since dependency never completed + assert.Empty(t, got.DepStatus) + + // Clean up + assert.NoError(t, q.Done(ctx, got.ID, model.StatusSuccess)) + waitForProcess() + }) + + // Edge case: dependency added AFTER dependent task (race condition) + t.Run("dependency added after dependent", func(t *testing.T) { + // Push dependent task first + dependent := &model.Task{ + ID: "late-dep-child", + Dependencies: []string{"late-dep-parent"}, + DepStatus: make(map[string]model.StatusValue), + } + assert.NoError(t, q.PushAtOnce(ctx, []*model.Task{dependent})) + waitForProcess() + + // At this point, dependent doesn't see parent in queue, so it won't wait + info := q.Info(ctx) + // Dependent should NOT be waiting since parent doesn't exist yet + initialWaiting := info.Stats.WaitingOnDeps + + // Now add the parent task + parent := &model.Task{ID: "late-dep-parent"} + assert.NoError(t, q.PushAtOnce(ctx, []*model.Task{parent})) + waitForProcess() + + // After filterWaiting runs, dependent SHOULD now see parent and wait + info = q.Info(ctx) + // The implementation calls filterWaiting() which rechecks dependencies + // So dependent should now be waiting + assert.Greater(t, info.Stats.WaitingOnDeps, initialWaiting, + "dependent should start waiting once parent is added") + + // Complete parent first + gotParent, _ := q.Poll(ctx, 1, filterFnTrue) + assert.Equal(t, "late-dep-parent", gotParent.ID, "parent should be polled first") + assert.NoError(t, q.Done(ctx, gotParent.ID, model.StatusSuccess)) + waitForProcess() + + // Now child should be unblocked with parent's status + gotChild, _ := q.Poll(ctx, 2, filterFnTrue) + assert.Equal(t, "late-dep-child", gotChild.ID) + assert.Equal(t, model.StatusSuccess, gotChild.DepStatus["late-dep-parent"]) + + assert.NoError(t, q.Done(ctx, gotChild.ID, model.StatusSuccess)) + waitForProcess() + }) } -func TestFifoErrors(t *testing.T) { - ctx, cancel := context.WithCancelCause(t.Context()) - t.Cleanup(func() { cancel(nil) }) +func TestFifoLeaseManagement(t *testing.T) { + ctx, cancel, q := setupTestQueue(t) + defer cancel(nil) - task1 := genDummyTask() - task2 := &model.Task{ - ID: "2", - Dependencies: []string{"1"}, - DepStatus: make(map[string]model.StatusValue), - } - task3 := &model.Task{ - ID: "3", - Dependencies: []string{"1"}, - DepStatus: make(map[string]model.StatusValue), - RunOn: []string{"success", "failure"}, - } + t.Run("lease expiration", func(t *testing.T) { + q.extension = 0 + t.Cleanup(func() { + q.extension = 50 * time.Millisecond + }) + dummyTask := &model.Task{ID: "lease-exp-1"} + assert.NoError(t, q.PushAtOnce(ctx, []*model.Task{dummyTask})) - q, _ := NewMemoryQueue(ctx).(*fifo) - assert.NotNil(t, q) - - assert.NoError(t, q.PushAtOnce(ctx, []*model.Task{task2, task3, task1})) - - waitForProcess() - got, err := q.Poll(ctx, 1, filterFnTrue) - assert.NoError(t, err) - assert.Equal(t, task1, got) - - assert.NoError(t, q.Error(ctx, got.ID, fmt.Errorf("exit code 1, there was an error"))) - - waitForProcess() - got, err = q.Poll(ctx, 1, filterFnTrue) - assert.NoError(t, err) - assert.Equal(t, task2, got) - assert.False(t, got.ShouldRun()) - - waitForProcess() - got, err = q.Poll(ctx, 1, filterFnTrue) - assert.NoError(t, err) - assert.Equal(t, task3, got) - assert.True(t, got.ShouldRun()) -} - -func TestFifoErrors2(t *testing.T) { - ctx, cancel := context.WithCancelCause(t.Context()) - t.Cleanup(func() { cancel(nil) }) - - task1 := genDummyTask() - task2 := &model.Task{ - ID: "2", - } - task3 := &model.Task{ - ID: "3", - Dependencies: []string{"1", "2"}, - DepStatus: make(map[string]model.StatusValue), - } - - q, _ := NewMemoryQueue(ctx).(*fifo) - assert.NotNil(t, q) - - assert.NoError(t, q.PushAtOnce(ctx, []*model.Task{task2, task3, task1})) - - for i := 0; i < 2; i++ { waitForProcess() got, err := q.Poll(ctx, 1, filterFnTrue) assert.NoError(t, err) - assert.False(t, got != task1 && got != task2, "expect task1 or task2 returned from queue as task3 depends on them") - if got != task1 { - assert.NoError(t, q.Done(ctx, got.ID, model.StatusSuccess)) - } - if got != task2 { - assert.NoError(t, q.Error(ctx, got.ID, fmt.Errorf("exit code 1, there was an error"))) - } - } + errCh := make(chan error, 1) + go func() { errCh <- q.Wait(ctx, got.ID) }() - waitForProcess() - got, err := q.Poll(ctx, 1, filterFnTrue) - assert.NoError(t, err) - assert.Equal(t, task3, got) - assert.False(t, got.ShouldRun()) -} - -func TestFifoErrorsMultiThread(t *testing.T) { - ctx, cancel := context.WithCancelCause(t.Context()) - t.Cleanup(func() { cancel(nil) }) - - task1 := genDummyTask() - task2 := &model.Task{ - ID: "2", - Dependencies: []string{"1"}, - DepStatus: make(map[string]model.StatusValue), - } - task3 := &model.Task{ - ID: "3", - Dependencies: []string{"1", "2"}, - DepStatus: make(map[string]model.StatusValue), - } - - q, _ := NewMemoryQueue(ctx).(*fifo) - assert.NotNil(t, q) - - assert.NoError(t, q.PushAtOnce(ctx, []*model.Task{task2, task3, task1})) - - obtainedWorkCh := make(chan *model.Task) - defer func() { close(obtainedWorkCh) }() - - for i := 0; i < 10; i++ { - go func(i int) { - for { - fmt.Printf("Worker %d started\n", i) - got, err := q.Poll(ctx, 1, filterFnTrue) - if err != nil && errors.Is(err, context.Canceled) { - return - } - assert.NoError(t, err) - obtainedWorkCh <- got - } - }(i) - } - - task1Processed := false - task2Processed := false - - for { + waitForProcess() select { - case got := <-obtainedWorkCh: - fmt.Println(got.ID) - - switch { - case !task1Processed: - assert.Equal(t, task1, got) - task1Processed = true - assert.NoError(t, q.Error(ctx, got.ID, fmt.Errorf("exit code 1, there was an error"))) - go func() { - for { - fmt.Printf("Worker spawned\n") - got, err := q.Poll(ctx, 1, filterFnTrue) - if err != nil && errors.Is(err, context.Canceled) { - return - } - assert.NoError(t, err) - obtainedWorkCh <- got - } - }() - case !task2Processed: - assert.Equal(t, task2, got) - task2Processed = true - assert.NoError(t, q.Done(ctx, got.ID, model.StatusSuccess)) - go func() { - for { - fmt.Printf("Worker spawned\n") - got, err := q.Poll(ctx, 1, filterFnTrue) - if err != nil && errors.Is(err, context.Canceled) { - return - } - assert.NoError(t, err) - obtainedWorkCh <- got - } - }() - default: - assert.Equal(t, task3, got) - assert.False(t, got.ShouldRun(), "expect task3 should not run, task1 succeeded but task2 failed") - return - } - - case <-time.After(5 * time.Second): - info := q.Info(ctx) - fmt.Println(info.String()) - t.Errorf("test timed out") - return + case werr := <-errCh: + assert.Error(t, werr) + // Edge case: verify error is ErrTaskExpired + assert.ErrorIs(t, werr, ErrTaskExpired) + case <-time.After(2 * time.Second): + t.Fatal("timeout waiting for Wait to return") } - } + + info := q.Info(ctx) + assert.Len(t, info.Pending, 1) + + // Edge case: verify task was resubmitted to front of queue + got2, _ := q.Poll(ctx, 1, filterFnTrue) + assert.Equal(t, got.ID, got2.ID) // Same task resubmitted + + assert.NoError(t, q.Done(ctx, got2.ID, model.StatusSuccess)) + waitForProcess() + + // Verify cleanup + info = q.Info(ctx) + assert.Len(t, info.Pending, 0) + assert.Len(t, info.Running, 0) + }) + + t.Run("extend lease", func(t *testing.T) { + q.extension = 50 * time.Millisecond + dummyTask := &model.Task{ID: "extend-1"} + assert.NoError(t, q.PushAtOnce(ctx, []*model.Task{dummyTask})) + + waitForProcess() + got, _ := q.Poll(ctx, 5, filterFnTrue) + + assert.NoError(t, q.Extend(ctx, 5, got.ID)) + assert.ErrorIs(t, q.Extend(ctx, 999, got.ID), ErrAgentMissMatch) + assert.ErrorIs(t, q.Extend(ctx, 1, got.ID), ErrAgentMissMatch) + assert.ErrorIs(t, q.Extend(ctx, 1, "non-existent"), ErrNotFound) + + // Edge case: extend multiple times rapidly + for i := 0; i < 3; i++ { + time.Sleep(30 * time.Millisecond) + assert.NoError(t, q.Extend(ctx, 5, got.ID)) + } + + info := q.Info(ctx) + assert.Len(t, info.Running, 1) + assert.Len(t, info.Pending, 0) + + // Edge case: extend after Done should error + assert.NoError(t, q.Done(ctx, got.ID, model.StatusSuccess)) + waitForProcess() + assert.ErrorIs(t, q.Extend(ctx, 5, got.ID), ErrNotFound) + + // Verify cleanup + info = q.Info(ctx) + assert.Len(t, info.Pending, 0) + assert.Len(t, info.Running, 0) + }) + + t.Run("wait operations", func(t *testing.T) { + // Verify queue is clean before starting + info := q.Info(ctx) + assert.Len(t, info.Pending, 0, "queue should be empty at start of wait operations") + assert.Len(t, info.Running, 0, "queue should be empty at start of wait operations") + + dummyTask := &model.Task{ID: "wait-1"} + assert.NoError(t, q.PushAtOnce(ctx, []*model.Task{dummyTask})) + + waitForProcess() + got, _ := q.Poll(ctx, 1, filterFnTrue) + + var wg sync.WaitGroup + wg.Add(1) + go func() { + assert.NoError(t, q.Wait(ctx, got.ID)) + wg.Done() + }() + + time.Sleep(time.Millisecond) + assert.NoError(t, q.Done(ctx, got.ID, model.StatusSuccess)) + wg.Wait() + + // Edge case: Wait on non-existent task should return immediately + assert.NoError(t, q.Wait(ctx, "non-existent")) + + dummyTask2 := &model.Task{ID: "wait-2"} + assert.NoError(t, q.PushAtOnce(ctx, []*model.Task{dummyTask2})) + waitForProcess() + got2, _ := q.Poll(ctx, 1, filterFnTrue) + + waitCtx, waitCancel := context.WithCancelCause(ctx) + errCh := make(chan error, 1) + go func() { errCh <- q.Wait(waitCtx, got2.ID) }() + + time.Sleep(50 * time.Millisecond) + waitCancel(nil) + + select { + case err := <-errCh: + assert.NoError(t, err) + case <-time.After(time.Second): + t.Fatal("Wait should return when context is canceled") + } + + // Clean up - complete the second wait task + assert.NoError(t, q.Done(ctx, got2.ID, model.StatusSuccess)) + waitForProcess() + + // Edge case: multiple concurrent waits on same task + dummyTask3 := &model.Task{ID: "wait-3"} + assert.NoError(t, q.PushAtOnce(ctx, []*model.Task{dummyTask3})) + waitForProcess() + got3, _ := q.Poll(ctx, 1, filterFnTrue) + + var wg2 sync.WaitGroup + wg2.Add(3) + for i := 0; i < 3; i++ { + go func() { + assert.NoError(t, q.Wait(ctx, got3.ID)) + wg2.Done() + }() + } + + time.Sleep(10 * time.Millisecond) + assert.NoError(t, q.Done(ctx, got3.ID, model.StatusSuccess)) + wg2.Wait() + + // Verify cleanup + info = q.Info(ctx) + assert.Len(t, info.Pending, 0) + assert.Len(t, info.Running, 0) + }) } -func TestFifoTransitiveErrors(t *testing.T) { +func TestFifoWorkerManagement(t *testing.T) { + ctx, cancel, q := setupTestQueue(t) + defer cancel(nil) + + t.Run("poll with context cancellation", func(t *testing.T) { + pollCtx, pollCancel := context.WithCancelCause(ctx) + errCh := make(chan error, 1) + go func() { + _, err := q.Poll(pollCtx, 1, filterFnTrue) + errCh <- err + }() + + time.Sleep(50 * time.Millisecond) + pollCancel(nil) + + select { + case err := <-errCh: + assert.ErrorIs(t, err, context.Canceled) + case <-time.After(time.Second): + t.Fatal("Poll should return when context is canceled") + } + + // Edge case: verify worker is cleaned up + info := q.Info(ctx) + assert.Equal(t, 0, info.Stats.Workers) + }) + + t.Run("kick agent workers", func(t *testing.T) { + pollResults := make(chan error, 5) + for i := 0; i < 5; i++ { + go func() { + _, err := q.Poll(ctx, 42, filterFnTrue) + pollResults <- err + }() + } + + time.Sleep(50 * time.Millisecond) + + // Edge case: verify workers are registered before kicking + info := q.Info(ctx) + assert.Equal(t, 5, info.Stats.Workers) + + q.KickAgentWorkers(42) + + kickedCount := 0 + for i := 0; i < 5; i++ { + select { + case err := <-pollResults: + if errors.Is(err, context.Canceled) { + kickedCount++ + } + case <-time.After(time.Second): + t.Fatal("expected all workers to be kicked") + } + } + assert.Equal(t, 5, kickedCount) + + // Edge case: verify workers are removed after kicking + waitForProcess() + info = q.Info(ctx) + assert.Equal(t, 0, info.Stats.Workers) + + // Edge case: kick non-existent agent should be no-op + q.KickAgentWorkers(999) + }) + + // Edge case: mixed agent workers + t.Run("kick specific agent among multiple", func(t *testing.T) { + pollResults := make(chan struct { + agentID int64 + err error + }, 10) + + // Start workers for agent 1 + for i := 0; i < 3; i++ { + go func() { + _, err := q.Poll(ctx, 1, filterFnTrue) + pollResults <- struct { + agentID int64 + err error + }{1, err} + }() + } + + // Start workers for agent 2 + for i := 0; i < 3; i++ { + go func() { + _, err := q.Poll(ctx, 2, filterFnTrue) + pollResults <- struct { + agentID int64 + err error + }{2, err} + }() + } + + time.Sleep(50 * time.Millisecond) + info := q.Info(ctx) + assert.Equal(t, 6, info.Stats.Workers) + + // Kick only agent 1 + q.KickAgentWorkers(1) + + kickedAgent1 := 0 + kickedAgent2 := 0 + for i := 0; i < 3; i++ { + select { + case result := <-pollResults: + if errors.Is(result.err, context.Canceled) { + if result.agentID == 1 { + kickedAgent1++ + } else { + kickedAgent2++ + } + } + case <-time.After(time.Second): + t.Fatal("expected kicked workers to return") + } + } + + assert.Equal(t, 3, kickedAgent1) + assert.Equal(t, 0, kickedAgent2) + + // Clean up agent 2 workers + q.KickAgentWorkers(2) + for i := 0; i < 3; i++ { + <-pollResults + } + }) +} + +func TestFifoLabelBasedScoring(t *testing.T) { ctx, cancel := context.WithCancelCause(t.Context()) - t.Cleanup(func() { cancel(nil) }) - - task1 := genDummyTask() - task2 := &model.Task{ - ID: "2", - Dependencies: []string{"1"}, - DepStatus: make(map[string]model.StatusValue), - } - task3 := &model.Task{ - ID: "3", - Dependencies: []string{"2"}, - DepStatus: make(map[string]model.StatusValue), - } - - q, _ := NewMemoryQueue(ctx).(*fifo) - assert.NotNil(t, q) - - assert.NoError(t, q.PushAtOnce(ctx, []*model.Task{task2, task3, task1})) - - waitForProcess() - got, err := q.Poll(ctx, 1, filterFnTrue) - assert.NoError(t, err) - assert.Equal(t, task1, got) - assert.NoError(t, q.Error(ctx, got.ID, fmt.Errorf("exit code 1, there was an error"))) - - waitForProcess() - got, err = q.Poll(ctx, 1, filterFnTrue) - assert.NoError(t, err) - assert.Equal(t, task2, got) - assert.False(t, got.ShouldRun(), "expect task2 should not run, since task1 failed") - assert.NoError(t, q.Done(ctx, got.ID, model.StatusSkipped)) - - waitForProcess() - got, err = q.Poll(ctx, 1, filterFnTrue) - assert.NoError(t, err) - assert.Equal(t, task3, got) - assert.False(t, got.ShouldRun(), "expect task3 should not run, task1 failed, thus task2 was skipped, task3 should be skipped too") -} - -func TestFifoCancel(t *testing.T) { - ctx, cancel := context.WithCancelCause(t.Context()) - t.Cleanup(func() { cancel(nil) }) - - task1 := genDummyTask() - task2 := &model.Task{ - ID: "2", - Dependencies: []string{"1"}, - DepStatus: make(map[string]model.StatusValue), - } - task3 := &model.Task{ - ID: "3", - Dependencies: []string{"1"}, - DepStatus: make(map[string]model.StatusValue), - RunOn: []string{"success", "failure"}, - } - - q, _ := NewMemoryQueue(ctx).(*fifo) - assert.NotNil(t, q) - - assert.NoError(t, q.PushAtOnce(ctx, []*model.Task{task2, task3, task1})) - - _, _ = q.Poll(ctx, 1, filterFnTrue) - assert.NoError(t, q.Error(ctx, task1.ID, fmt.Errorf("canceled"))) - assert.NoError(t, q.Error(ctx, task2.ID, fmt.Errorf("canceled"))) - assert.NoError(t, q.Error(ctx, task3.ID, fmt.Errorf("canceled"))) - info := q.Info(ctx) - assert.Len(t, info.Pending, 0, "all pipelines should be canceled") - - time.Sleep(processTimeInterval * 2) - info = q.Info(ctx) - assert.Len(t, info.Pending, 2, "canceled are rescheduled") - assert.Len(t, info.Running, 0, "canceled are rescheduled") - assert.Len(t, info.WaitingOnDeps, 0, "canceled are rescheduled") -} - -func TestFifoPause(t *testing.T) { - ctx, cancel := context.WithCancelCause(t.Context()) - t.Cleanup(func() { cancel(nil) }) - - q, _ := NewMemoryQueue(ctx).(*fifo) - assert.NotNil(t, q) - - dummyTask := genDummyTask() - - var wg sync.WaitGroup - wg.Add(1) - go func() { - _, _ = q.Poll(ctx, 1, filterFnTrue) - wg.Done() - }() - - q.Pause() - t0 := time.Now() - assert.NoError(t, q.PushAtOnce(ctx, []*model.Task{dummyTask})) - waitForProcess() - q.Resume() - - wg.Wait() - t1 := time.Now() - - assert.Greater(t, t1.Sub(t0), 20*time.Millisecond, "should have waited til resume") - - q.Pause() - assert.NoError(t, q.PushAtOnce(ctx, []*model.Task{dummyTask})) - q.Resume() - _, _ = q.Poll(ctx, 1, filterFnTrue) -} - -func TestFifoPauseResume(t *testing.T) { - ctx, cancel := context.WithCancelCause(t.Context()) - t.Cleanup(func() { cancel(nil) }) - - q, _ := NewMemoryQueue(ctx).(*fifo) - assert.NotNil(t, q) - - dummyTask := genDummyTask() - - q.Pause() - assert.NoError(t, q.PushAtOnce(ctx, []*model.Task{dummyTask})) - q.Resume() - - _, _ = q.Poll(ctx, 1, filterFnTrue) -} - -func TestWaitingVsPending(t *testing.T) { - ctx, cancel := context.WithCancelCause(t.Context()) - t.Cleanup(func() { cancel(nil) }) - - task1 := genDummyTask() - task2 := &model.Task{ - ID: "2", - Dependencies: []string{"1"}, - DepStatus: make(map[string]model.StatusValue), - } - task3 := &model.Task{ - ID: "3", - Dependencies: []string{"1"}, - DepStatus: make(map[string]model.StatusValue), - RunOn: []string{"success", "failure"}, - } - - q, _ := NewMemoryQueue(ctx).(*fifo) - assert.NotNil(t, q) - - assert.NoError(t, q.PushAtOnce(ctx, []*model.Task{task2, task3, task1})) - - got, _ := q.Poll(ctx, 1, filterFnTrue) - - waitForProcess() - info := q.Info(ctx) - assert.Equal(t, 2, info.Stats.WaitingOnDeps) - - assert.NoError(t, q.Error(ctx, got.ID, fmt.Errorf("exit code 1, there was an error"))) - got, err := q.Poll(ctx, 1, filterFnTrue) - assert.NoError(t, err) - assert.EqualValues(t, task2, got) - - waitForProcess() - info = q.Info(ctx) - assert.Equal(t, 0, info.Stats.WaitingOnDeps) - assert.Equal(t, 1, info.Stats.Pending) -} - -func TestShouldRun(t *testing.T) { - task := &model.Task{ - ID: "2", - Dependencies: []string{"1"}, - DepStatus: map[string]model.StatusValue{ - "1": model.StatusSuccess, - }, - RunOn: []string{"failure"}, - } - assert.False(t, task.ShouldRun(), "expect task to not run, it runs on failure only") - - task = &model.Task{ - ID: "2", - Dependencies: []string{"1"}, - DepStatus: map[string]model.StatusValue{ - "1": model.StatusSuccess, - }, - RunOn: []string{"failure", "success"}, - } - assert.True(t, task.ShouldRun()) - - task = &model.Task{ - ID: "2", - Dependencies: []string{"1"}, - DepStatus: map[string]model.StatusValue{ - "1": model.StatusFailure, - }, - } - assert.False(t, task.ShouldRun()) - - task = &model.Task{ - ID: "2", - Dependencies: []string{"1"}, - DepStatus: map[string]model.StatusValue{ - "1": model.StatusSuccess, - }, - RunOn: []string{"success"}, - } - assert.True(t, task.ShouldRun()) - - task = &model.Task{ - ID: "2", - Dependencies: []string{"1"}, - DepStatus: map[string]model.StatusValue{ - "1": model.StatusFailure, - }, - RunOn: []string{"failure"}, - } - assert.True(t, task.ShouldRun()) - - task = &model.Task{ - ID: "2", - Dependencies: []string{"1"}, - DepStatus: map[string]model.StatusValue{ - "1": model.StatusSkipped, - }, - } - assert.False(t, task.ShouldRun(), "task should not run if dependency is skipped") - - task = &model.Task{ - ID: "2", - Dependencies: []string{"1"}, - DepStatus: map[string]model.StatusValue{ - "1": model.StatusSkipped, - }, - RunOn: []string{"failure"}, - } - assert.True(t, task.ShouldRun(), "on failure, tasks should run on skipped deps, something failed higher up the chain") -} - -func TestFifoWithScoring(t *testing.T) { - ctx, cancel := context.WithCancelCause(t.Context()) - t.Cleanup(func() { cancel(nil) }) + defer cancel(nil) q := NewMemoryQueue(ctx) - // Create tasks with different labels tasks := []*model.Task{ {ID: "1", Labels: map[string]string{"org-id": "123", "platform": "linux"}}, {ID: "2", Labels: map[string]string{"org-id": "456", "platform": "linux"}}, - {ID: "3", Labels: map[string]string{"org-id": "789", "platform": "windows"}}, - {ID: "4", Labels: map[string]string{"org-id": "123", "platform": "linux"}}, - {ID: "5", Labels: map[string]string{"org-id": "*", "platform": "linux"}}, + {ID: "3", Labels: map[string]string{"org-id": "123", "platform": "windows"}}, } assert.NoError(t, q.PushAtOnce(ctx, tasks)) - // Create filter functions for different workers - filters := map[int]FilterFn{ - 1: func(task *model.Task) (bool, int) { - if task.Labels["org-id"] == "123" { - return true, 20 - } - if task.Labels["platform"] == "linux" { - return true, 10 - } - return true, 1 - }, - 2: func(task *model.Task) (bool, int) { - if task.Labels["org-id"] == "456" { - return true, 20 - } - if task.Labels["platform"] == "linux" { - return true, 10 - } - return true, 1 - }, - 3: func(task *model.Task) (bool, int) { - if task.Labels["platform"] == "windows" { - return true, 20 - } - return true, 1 - }, - 4: func(task *model.Task) (bool, int) { - if task.Labels["org-id"] == "123" { - return true, 20 - } - if task.Labels["platform"] == "linux" { - return true, 10 - } - return true, 1 - }, - 5: func(task *model.Task) (bool, int) { - if task.Labels["org-id"] == "*" { - return true, 15 - } - return true, 1 - }, + filter123 := func(task *model.Task) (bool, int) { + if task.Labels["org-id"] == "123" { + return true, 20 + } + return true, 1 } - // Start polling in separate goroutines - results := make(chan *model.Task, 5) - for i := 1; i <= 5; i++ { - go func(n int) { - task, err := q.Poll(ctx, int64(n), filters[n]) - assert.NoError(t, err) - results <- task - }(i) + filter456 := func(task *model.Task) (bool, int) { + if task.Labels["org-id"] == "456" { + return true, 20 + } + return true, 1 } - // Collect results + results := make(chan *model.Task, 2) + go func() { + task, _ := q.Poll(ctx, 1, filter123) + results <- task + }() + go func() { + task, _ := q.Poll(ctx, 2, filter456) + results <- task + }() + receivedTasks := make(map[string]int64) - for i := 0; i < 5; i++ { + for i := 0; i < 2; i++ { select { case task := <-results: receivedTasks[task.ID] = task.AgentID @@ -674,26 +1003,89 @@ func TestFifoWithScoring(t *testing.T) { } } - assert.Len(t, receivedTasks, 5, "All tasks should be assigned") + assert.Contains(t, []string{"1", "3"}, findTaskByAgent(receivedTasks, 1)) + assert.Equal(t, "2", findTaskByAgent(receivedTasks, 2)) - // Define expected agent assignments - // Map structure: {taskID: []possible agentIDs} - // - taskID "1" and "4" can be assigned to agents 1 or 4 (org-id "123") - // - taskID "2" should be assigned to agent 2 (org-id "456") - // - taskID "3" should be assigned to agent 3 (platform "windows") - // - taskID "5" should be assigned to agent 5 (org-id "*") - expectedAssignments := map[string][]int64{ - "1": {1, 4}, - "2": {2}, - "3": {3}, - "4": {1, 4}, - "5": {5}, + // Edge case: filter that rejects all tasks + filterRejectAll := func(task *model.Task) (bool, int) { + return false, 0 } - // Check if tasks are assigned as expected - for taskID, expectedAgents := range expectedAssignments { - agentID, ok := receivedTasks[taskID] - assert.True(t, ok, "Task %s should be assigned", taskID) - assert.Contains(t, expectedAgents, agentID, "Task %s should be assigned to one of the expected agents", taskID) + task4 := &model.Task{ID: "4", Labels: map[string]string{"org-id": "789"}} + assert.NoError(t, q.PushAtOnce(ctx, []*model.Task{task4})) + waitForProcess() + + pollCtx, pollCancel := context.WithTimeout(ctx, 200*time.Millisecond) + _, err := q.Poll(pollCtx, 99, filterRejectAll) + pollCancel() + assert.Error(t, err) // Should timeout as filter rejects task + + // Clean up remaining tasks + task3, _ := q.Poll(ctx, 1, filterFnTrue) + assert.NoError(t, q.Done(ctx, task3.ID, model.StatusSuccess)) + task4Got, _ := q.Poll(ctx, 99, filterFnTrue) + assert.NoError(t, q.Done(ctx, task4Got.ID, model.StatusSuccess)) + waitForProcess() +} + +func TestShouldRunLogic(t *testing.T) { + tests := []struct { + name string + depStatus model.StatusValue + runOn []string + expected bool + }{ + {"Success without RunOn", model.StatusSuccess, nil, true}, + {"Failure without RunOn", model.StatusFailure, nil, false}, + {"Success with failure RunOn", model.StatusSuccess, []string{"failure"}, false}, + {"Failure with failure RunOn", model.StatusFailure, []string{"failure"}, true}, + {"Success with both RunOn", model.StatusSuccess, []string{"success", "failure"}, true}, + {"Skipped without RunOn", model.StatusSkipped, nil, false}, + {"Skipped with failure RunOn", model.StatusSkipped, []string{"failure"}, true}, + // Edge cases + {"Killed without RunOn", model.StatusKilled, nil, false}, + {"Killed with failure RunOn", model.StatusKilled, []string{"failure"}, true}, + {"Success with success RunOn only", model.StatusSuccess, []string{"success"}, true}, + {"Failure with success RunOn only", model.StatusFailure, []string{"success"}, false}, } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + task := &model.Task{ + ID: "2", + Dependencies: []string{"1"}, + DepStatus: map[string]model.StatusValue{"1": tt.depStatus}, + RunOn: tt.runOn, + } + assert.Equal(t, tt.expected, task.ShouldRun()) + }) + } + + // Edge case: multiple dependencies with mixed statuses + t.Run("multiple deps mixed status", func(t *testing.T) { + task := &model.Task{ + ID: "3", + Dependencies: []string{"1", "2"}, + DepStatus: map[string]model.StatusValue{ + "1": model.StatusSuccess, + "2": model.StatusFailure, + }, + RunOn: nil, + } + // With default RunOn (nil), needs all deps successful + assert.False(t, task.ShouldRun()) + + task.RunOn = []string{"success", "failure"} + // With both RunOn, should run regardless + assert.True(t, task.ShouldRun()) + }) +} + +func findTaskByAgent(tasks map[string]int64, agentID int64) string { + for taskID, aid := range tasks { + if aid == agentID { + return taskID + } + } + return "" } diff --git a/server/queue/mocks/mock_Queue.go b/server/queue/mocks/mock_Queue.go index 97a215ed9..0ae4eb09d 100644 --- a/server/queue/mocks/mock_Queue.go +++ b/server/queue/mocks/mock_Queue.go @@ -228,63 +228,6 @@ func (_c *MockQueue_ErrorAtOnce_Call) RunAndReturn(run func(c context.Context, i return _c } -// EvictAtOnce provides a mock function for the type MockQueue -func (_mock *MockQueue) EvictAtOnce(c context.Context, ids []string) error { - ret := _mock.Called(c, ids) - - if len(ret) == 0 { - panic("no return value specified for EvictAtOnce") - } - - var r0 error - if returnFunc, ok := ret.Get(0).(func(context.Context, []string) error); ok { - r0 = returnFunc(c, ids) - } else { - r0 = ret.Error(0) - } - return r0 -} - -// MockQueue_EvictAtOnce_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'EvictAtOnce' -type MockQueue_EvictAtOnce_Call struct { - *mock.Call -} - -// EvictAtOnce is a helper method to define mock.On call -// - c context.Context -// - ids []string -func (_e *MockQueue_Expecter) EvictAtOnce(c interface{}, ids interface{}) *MockQueue_EvictAtOnce_Call { - return &MockQueue_EvictAtOnce_Call{Call: _e.mock.On("EvictAtOnce", c, ids)} -} - -func (_c *MockQueue_EvictAtOnce_Call) Run(run func(c context.Context, ids []string)) *MockQueue_EvictAtOnce_Call { - _c.Call.Run(func(args mock.Arguments) { - var arg0 context.Context - if args[0] != nil { - arg0 = args[0].(context.Context) - } - var arg1 []string - if args[1] != nil { - arg1 = args[1].([]string) - } - run( - arg0, - arg1, - ) - }) - return _c -} - -func (_c *MockQueue_EvictAtOnce_Call) Return(err error) *MockQueue_EvictAtOnce_Call { - _c.Call.Return(err) - return _c -} - -func (_c *MockQueue_EvictAtOnce_Call) RunAndReturn(run func(c context.Context, ids []string) error) *MockQueue_EvictAtOnce_Call { - _c.Call.Return(run) - return _c -} - // Extend provides a mock function for the type MockQueue func (_mock *MockQueue) Extend(c context.Context, agentID int64, workflowID string) error { ret := _mock.Called(c, agentID, workflowID) diff --git a/server/queue/persistent.go b/server/queue/persistent.go index b5a887ed5..0c18f9af1 100644 --- a/server/queue/persistent.go +++ b/server/queue/persistent.go @@ -17,11 +17,14 @@ package queue import ( "context" + "errors" + "fmt" "github.com/rs/zerolog/log" "go.woodpecker-ci.org/woodpecker/v3/server/model" "go.woodpecker-ci.org/woodpecker/v3/server/store" + "go.woodpecker-ci.org/woodpecker/v3/server/store/types" ) // WithTaskStore returns a queue that is backed by the TaskStore. This @@ -72,36 +75,37 @@ func (q *persistentQueue) Poll(c context.Context, agentID int64, f FilterFn) (*m return task, err } -// EvictAtOnce removes multiple pending tasks from the queue. -func (q *persistentQueue) EvictAtOnce(c context.Context, ids []string) error { - if err := q.Queue.EvictAtOnce(c, ids); err != nil { - return err - } - for _, id := range ids { - if err := q.store.TaskDelete(id); err != nil { - return err - } - } - return nil -} - // Error signals the task is done with an error. func (q *persistentQueue) Error(c context.Context, id string, err error) error { if err := q.Queue.Error(c, id, err); err != nil { return err } - return q.store.TaskDelete(id) + + if deleteErr := q.store.TaskDelete(id); deleteErr != nil { + if !errors.Is(deleteErr, types.RecordNotExist) { + return deleteErr + } + log.Debug().Msgf("task %s already removed from store", id) + } + return nil } -// ErrorAtOnce signals multiple tasks are done with an error. +// ErrorAtOnce signals multiple tasks are done and complete with an error. +// If still pending they will just get removed from the queue. func (q *persistentQueue) ErrorAtOnce(c context.Context, ids []string, err error) error { if err := q.Queue.ErrorAtOnce(c, ids, err); err != nil { return err } + + var errs []error for _, id := range ids { - if err := q.store.TaskDelete(id); err != nil { - return err + if deleteErr := q.store.TaskDelete(id); deleteErr != nil && !errors.Is(deleteErr, types.RecordNotExist) { + errs = append(errs, fmt.Errorf("task id [%s]: %w", id, deleteErr)) } } + + if len(errs) != 0 { + return fmt.Errorf("failed to delete tasks from persistent store: %w", errors.Join(errs...)) + } return nil } diff --git a/server/queue/queue.go b/server/queue/queue.go index e40588711..a73ebee12 100644 --- a/server/queue/queue.go +++ b/server/queue/queue.go @@ -36,8 +36,39 @@ var ( // ErrTaskExpired indicates a running task exceeded its lease/deadline and was resubmitted. ErrTaskExpired = errors.New("queue: task expired") + + // ErrWorkerKicked worker of an agent got kicked. + ErrWorkerKicked = errors.New("worker was kicked") ) +// ErrExternal wraps an external error. +type ErrExternal struct { + err error +} + +func (e *ErrExternal) Error() string { + return fmt.Sprintf("external error: %s", e.err) +} + +// Unwrap allows errors.Is and errors.As to work with the wrapped error. +func (e *ErrExternal) Unwrap() error { + return e.err +} + +// Is allows errors.Is to match against ErrExternal types. +func (e *ErrExternal) Is(target error) bool { + _, ok := target.(*ErrExternal) + return ok +} + +// NewErrExternal wraps an error as external one so queue can filter it out if needed. +func NewErrExternal(err error) error { + if err == nil { + return nil + } + return &ErrExternal{err: err} +} + // InfoT provides runtime information. type InfoT struct { Pending []*model.Task `json:"pending"` @@ -93,13 +124,12 @@ type Queue interface { // Error signals the task is done with an error. Error(c context.Context, id string, err error) error - // ErrorAtOnce signals multiple done are complete with an error. + // ErrorAtOnce signals multiple tasks are done and complete with an error. + // If still pending they will just get removed from the queue. ErrorAtOnce(c context.Context, ids []string, err error) error - // EvictAtOnce removes multiple pending tasks from the queue. - EvictAtOnce(c context.Context, ids []string) error - // Wait waits until the task is complete. + // Also signals via error ErrCancel if workflow got canceled. Wait(c context.Context, id string) error // Info returns internal queue information. diff --git a/server/router/middleware/session/repo.go b/server/router/middleware/session/repo.go index 55e5e620a..519b462f4 100644 --- a/server/router/middleware/session/repo.go +++ b/server/router/middleware/session/repo.go @@ -128,7 +128,6 @@ func SetPerm() gin.HandlerFunc { log.Debug().Msgf("synced user permission for %s %s", user.Login, repo.FullName) _repo.ForgeID = user.ForgeID perm = _repo.Perm - perm.Repo = repo perm.RepoID = repo.ID perm.UserID = user.ID perm.Synced = time.Now().Unix() diff --git a/server/grpc/auth_server.go b/server/rpc/auth_server.go similarity index 97% rename from server/grpc/auth_server.go rename to server/rpc/auth_server.go index c009b6eca..45621b113 100644 --- a/server/grpc/auth_server.go +++ b/server/rpc/auth_server.go @@ -21,7 +21,7 @@ import ( "github.com/rs/zerolog/log" - "go.woodpecker-ci.org/woodpecker/v3/pipeline/rpc/proto" + "go.woodpecker-ci.org/woodpecker/v3/rpc/proto" "go.woodpecker-ci.org/woodpecker/v3/server/model" "go.woodpecker-ci.org/woodpecker/v3/server/store" "go.woodpecker-ci.org/woodpecker/v3/server/store/types" diff --git a/server/grpc/authorizer.go b/server/rpc/authorizer.go similarity index 59% rename from server/grpc/authorizer.go rename to server/rpc/authorizer.go index 545e8e98e..bdf21d432 100644 --- a/server/grpc/authorizer.go +++ b/server/rpc/authorizer.go @@ -12,6 +12,38 @@ // See the License for the specific language governing permissions and // limitations under the License. +// Package grpc provides gRPC server implementation with JWT-based authentication. +// +// # Authentication Flow +// +// Uses a two-token approach: +// +// 1. Agent Token (long-lived): Configured via WOODPECKER_AGENT_SECRET, used only for initial Auth() call +// 2. JWT Access Token (short-lived, 1 hour): Obtained from Auth(), included in metadata["token"] for all service calls +// +// # Interceptor Architecture +// +// Authorizer interceptors validate JWT tokens on every request: +// 1. Extract JWT from metadata["token"] +// 2. Verify signature and expiration +// 3. Extract and add agent_id to metadata for downstream handlers +// +// Auth endpoint (/proto.WoodpeckerAuth/Auth) bypasses validation to allow initial authentication. +// +// # Usage +// +// // Server setup +// jwtManager := NewJWTManager(c.String("grpc-secret")) +// authorizer := NewAuthorizer(jwtManager) +// grpcServer := grpc.NewServer( +// grpc.StreamInterceptor(authorizer.StreamInterceptor), +// grpc.UnaryInterceptor(authorizer.UnaryInterceptor), +// ) +// +// // Client usage +// resp, _ := authClient.Auth(ctx, &proto.AuthRequest{AgentToken: "secret", AgentId: -1}) +// ctx = metadata.AppendToOutgoingContext(ctx, "token", resp.AccessToken) +// workflow, _ := woodpeckerClient.Next(ctx, &proto.NextRequest{...}) package grpc import ( @@ -24,6 +56,7 @@ import ( "google.golang.org/grpc/status" ) +// StreamContextWrapper wraps gRPC ServerStream to allow context modification. type StreamContextWrapper interface { grpc.ServerStream SetContext(context.Context) @@ -50,14 +83,17 @@ func newStreamContextWrapper(inner grpc.ServerStream) StreamContextWrapper { } } +// Authorizer validates JWT tokens and enriches context with agent information. type Authorizer struct { jwtManager *JWTManager } +// NewAuthorizer creates a new JWT authorizer. func NewAuthorizer(jwtManager *JWTManager) *Authorizer { return &Authorizer{jwtManager: jwtManager} } +// StreamInterceptor validates JWT tokens for streaming gRPC calls. func (a *Authorizer) StreamInterceptor(srv any, stream grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error { _stream := newStreamContextWrapper(stream) @@ -71,7 +107,8 @@ func (a *Authorizer) StreamInterceptor(srv any, stream grpc.ServerStream, info * return handler(srv, _stream) } -func (a *Authorizer) UnaryInterceptor(ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp any, err error) { +// UnaryInterceptor validates JWT tokens for unary gRPC calls. +func (a *Authorizer) UnaryInterceptor(ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (any, error) { newCtx, err := a.authorize(ctx, info.FullMethod) if err != nil { return nil, err @@ -79,6 +116,8 @@ func (a *Authorizer) UnaryInterceptor(ctx context.Context, req any, info *grpc.U return handler(newCtx, req) } +// authorize validates JWT and enriches context with agent_id metadata. +// Bypasses validation for /proto.WoodpeckerAuth/Auth endpoint. func (a *Authorizer) authorize(ctx context.Context, fullMethod string) (context.Context, error) { // bypass auth for token endpoint if fullMethod == "/proto.WoodpeckerAuth/Auth" { diff --git a/server/grpc/filter.go b/server/rpc/filter.go similarity index 97% rename from server/grpc/filter.go rename to server/rpc/filter.go index 177499abe..3a1edc8fd 100644 --- a/server/grpc/filter.go +++ b/server/rpc/filter.go @@ -19,7 +19,7 @@ import ( "strings" pipelineConsts "go.woodpecker-ci.org/woodpecker/v3/pipeline" - "go.woodpecker-ci.org/woodpecker/v3/pipeline/rpc" + "go.woodpecker-ci.org/woodpecker/v3/rpc" "go.woodpecker-ci.org/woodpecker/v3/server/model" "go.woodpecker-ci.org/woodpecker/v3/server/queue" ) diff --git a/server/grpc/filter_test.go b/server/rpc/filter_test.go similarity index 98% rename from server/grpc/filter_test.go rename to server/rpc/filter_test.go index 4a4b01f79..04d0e13dc 100644 --- a/server/grpc/filter_test.go +++ b/server/rpc/filter_test.go @@ -19,7 +19,7 @@ import ( "github.com/stretchr/testify/assert" - "go.woodpecker-ci.org/woodpecker/v3/pipeline/rpc" + "go.woodpecker-ci.org/woodpecker/v3/rpc" "go.woodpecker-ci.org/woodpecker/v3/server/model" ) diff --git a/server/grpc/jwt_manager.go b/server/rpc/jwt_manager.go similarity index 100% rename from server/grpc/jwt_manager.go rename to server/rpc/jwt_manager.go diff --git a/server/grpc/rpc.go b/server/rpc/rpc.go similarity index 92% rename from server/grpc/rpc.go rename to server/rpc/rpc.go index bef1b7fdd..6fa97735d 100644 --- a/server/grpc/rpc.go +++ b/server/rpc/rpc.go @@ -29,7 +29,7 @@ import ( "github.com/rs/zerolog/log" grpcMetadata "google.golang.org/grpc/metadata" - "go.woodpecker-ci.org/woodpecker/v3/pipeline/rpc" + "go.woodpecker-ci.org/woodpecker/v3/rpc" "go.woodpecker-ci.org/woodpecker/v3/server" "go.woodpecker-ci.org/woodpecker/v3/server/forge" "go.woodpecker-ci.org/woodpecker/v3/server/logging" @@ -53,6 +53,7 @@ type RPC struct { } // Next blocks until it provides the next workflow to execute. +// TODO (6038): Server does not release waiting agents on graceful shutdown. func (s *RPC) Next(c context.Context, agentFilter rpc.Filter) (*rpc.Workflow, error) { if hostname, err := s.getHostnameFromContext(c); err == nil { log.Debug().Msgf("agent connected: %s: polling", hostname) @@ -100,18 +101,29 @@ func (s *RPC) Next(c context.Context, agentFilter rpc.Filter) (*rpc.Workflow, er } } -// Wait blocks until the workflow with the given ID is done. -func (s *RPC) Wait(c context.Context, workflowID string) error { +// Wait blocks until the workflow with the given ID is completed or got canceled. +// Used to let agents wait for cancel signals from server side. +func (s *RPC) Wait(c context.Context, workflowID string) (canceled bool, err error) { agent, err := s.getAgentFromContext(c) if err != nil { - return err + return false, err } if err := s.checkAgentPermissionByWorkflow(c, agent, workflowID, nil, nil); err != nil { - return err + return false, err } - return s.queue.Wait(c, workflowID) + if err := s.queue.Wait(c, workflowID); err != nil { + if errors.Is(err, queue.ErrCancel) { + // we explicit send a cancel signal + return true, nil + } + // unknown error happened + return false, err + } + + // workflow finished and on issues appeared + return false, nil } // Extend extends the lease for the workflow with the given ID. @@ -133,7 +145,7 @@ func (s *RPC) Extend(c context.Context, workflowID string) error { return s.queue.Extend(c, agent.ID, workflowID) } -// Update updates the state of a step. +// Update let agent updates the step state at the server. func (s *RPC) Update(c context.Context, strWorkflowID string, state rpc.StepState) error { workflowID, err := strconv.ParseInt(strWorkflowID, 10, 64) if err != nil { @@ -213,7 +225,7 @@ func (s *RPC) Update(c context.Context, strWorkflowID string, state rpc.StepStat return nil } -// Init implements the rpc.Init function. +// Init signals the workflow is initialized. func (s *RPC) Init(c context.Context, strWorkflowID string, state rpc.WorkflowState) error { workflowID, err := strconv.ParseInt(strWorkflowID, 10, 64) if err != nil { @@ -286,7 +298,7 @@ func (s *RPC) Init(c context.Context, strWorkflowID string, state rpc.WorkflowSt return s.updateAgentLastWork(agent) } -// Done marks the workflow with the given ID as done. +// Done marks the workflow with the given ID as stope. func (s *RPC) Done(c context.Context, strWorkflowID string, state rpc.WorkflowState) error { workflowID, err := strconv.ParseInt(strWorkflowID, 10, 64) if err != nil { @@ -331,20 +343,23 @@ func (s *RPC) Done(c context.Context, strWorkflowID string, state rpc.WorkflowSt Str("pipeline_id", fmt.Sprint(currentPipeline.ID)). Str("workflow_id", strWorkflowID).Logger() - logger.Trace().Msgf("gRPC Done with state: %#v", state) + logger.Debug().Msgf("workflow state in store: %#v", workflow) + logger.Debug().Msgf("gRPC Done with state: %#v", state) if workflow, err = pipeline.UpdateWorkflowStatusToDone(s.store, *workflow, state); err != nil { logger.Error().Err(err).Msgf("pipeline.UpdateWorkflowStatusToDone: cannot update workflow state: %s", err) } - var queueErr error - if workflow.Failing() { - queueErr = s.queue.Error(c, strWorkflowID, fmt.Errorf("workflow finished with error %s", state.Error)) - } else { - queueErr = s.queue.Done(c, strWorkflowID, workflow.State) - } - if queueErr != nil { - logger.Error().Err(queueErr).Msg("queue.Done: cannot ack workflow") + if !state.Canceled { + var queueErr error + if workflow.Failing() { + queueErr = s.queue.Error(c, strWorkflowID, fmt.Errorf("workflow finished with error %s", state.Error)) + } else { + queueErr = s.queue.Done(c, strWorkflowID, workflow.State) + } + if queueErr != nil { + logger.Error().Err(queueErr).Msg("queue.Done: cannot ack workflow") + } } currentPipeline.Workflows, err = s.store.WorkflowGetTree(currentPipeline) @@ -354,7 +369,7 @@ func (s *RPC) Done(c context.Context, strWorkflowID string, state rpc.WorkflowSt s.completeChildrenIfParentCompleted(workflow) if !model.IsThereRunningStage(currentPipeline.Workflows) { - if currentPipeline, err = pipeline.UpdateStatusToDone(s.store, *currentPipeline, model.PipelineStatus(currentPipeline.Workflows), workflow.Finished); err != nil { + if currentPipeline, err = pipeline.UpdateStatusToDone(s.store, *currentPipeline, pipeline.PipelineStatus(currentPipeline.Workflows), workflow.Finished); err != nil { logger.Error().Err(err).Msgf("pipeline.UpdateStatusToDone: cannot update workflows final state") } } diff --git a/server/grpc/rpc_test.go b/server/rpc/rpc_test.go similarity index 96% rename from server/grpc/rpc_test.go rename to server/rpc/rpc_test.go index 1a20abdc5..04a6a6f60 100644 --- a/server/grpc/rpc_test.go +++ b/server/rpc/rpc_test.go @@ -20,9 +20,10 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" "google.golang.org/grpc/metadata" - "go.woodpecker-ci.org/woodpecker/v3/pipeline/rpc" + "go.woodpecker-ci.org/woodpecker/v3/rpc" "go.woodpecker-ci.org/woodpecker/v3/server/model" store_mocks "go.woodpecker-ci.org/woodpecker/v3/server/store/mocks" ) @@ -62,9 +63,7 @@ func TestRegisterAgent(t *testing.T) { Backend: "backend", Capacity: 2, }) - if !assert.NoError(t, err) { - return - } + require.NoError(t, err) assert.EqualValues(t, 1337, agentID) }) @@ -104,9 +103,7 @@ func TestRegisterAgent(t *testing.T) { Backend: "backend", Capacity: 2, }) - if !assert.NoError(t, err) { - return - } + require.NoError(t, err) assert.EqualValues(t, 1337, agentID) }) diff --git a/server/grpc/server.go b/server/rpc/server.go similarity index 86% rename from server/grpc/server.go rename to server/rpc/server.go index 4a79ef447..c9115ede5 100644 --- a/server/grpc/server.go +++ b/server/rpc/server.go @@ -22,8 +22,8 @@ import ( prometheus_auto "github.com/prometheus/client_golang/prometheus/promauto" "github.com/rs/zerolog/log" - "go.woodpecker-ci.org/woodpecker/v3/pipeline/rpc" - "go.woodpecker-ci.org/woodpecker/v3/pipeline/rpc/proto" + "go.woodpecker-ci.org/woodpecker/v3/rpc" + "go.woodpecker-ci.org/woodpecker/v3/rpc/proto" "go.woodpecker-ci.org/woodpecker/v3/server/logging" "go.woodpecker-ci.org/woodpecker/v3/server/pubsub" "go.woodpecker-ci.org/woodpecker/v3/server/queue" @@ -59,6 +59,7 @@ func NewWoodpeckerServer(queue queue.Queue, logger logging.Log, pubsub *pubsub.P return &WoodpeckerServer{peer: peer} } +// Version returns the server- & grpc-version. func (s *WoodpeckerServer) Version(_ context.Context, _ *proto.Empty) (*proto.VersionResponse, error) { return &proto.VersionResponse{ GrpcVersion: proto.Version, @@ -66,6 +67,7 @@ func (s *WoodpeckerServer) Version(_ context.Context, _ *proto.Empty) (*proto.Ve }, nil } +// Next blocks until it provides the next workflow to execute from the queue. func (s *WoodpeckerServer) Next(c context.Context, req *proto.NextRequest) (*proto.NextResponse, error) { filter := rpc.Filter{ Labels: req.GetFilter().GetLabels(), @@ -85,6 +87,7 @@ func (s *WoodpeckerServer) Next(c context.Context, req *proto.NextRequest) (*pro return res, err } +// Init let agent signals to server the workflow is initialized. func (s *WoodpeckerServer) Init(c context.Context, req *proto.InitRequest) (*proto.Empty, error) { state := rpc.WorkflowState{ Started: req.GetState().GetStarted(), @@ -96,6 +99,7 @@ func (s *WoodpeckerServer) Init(c context.Context, req *proto.InitRequest) (*pro return res, err } +// Update let agent updates the step state at the server. func (s *WoodpeckerServer) Update(c context.Context, req *proto.UpdateRequest) (*proto.Empty, error) { state := rpc.StepState{ StepUUID: req.GetState().GetStepUuid(), @@ -104,29 +108,36 @@ func (s *WoodpeckerServer) Update(c context.Context, req *proto.UpdateRequest) ( Exited: req.GetState().GetExited(), Error: req.GetState().GetError(), ExitCode: int(req.GetState().GetExitCode()), + Canceled: req.GetState().GetCanceled(), } res := new(proto.Empty) err := s.peer.Update(c, req.GetId(), state) return res, err } +// Done let agent signal to server the workflow has stopped. func (s *WoodpeckerServer) Done(c context.Context, req *proto.DoneRequest) (*proto.Empty, error) { state := rpc.WorkflowState{ Started: req.GetState().GetStarted(), Finished: req.GetState().GetFinished(), Error: req.GetState().GetError(), + Canceled: req.GetState().GetCanceled(), } res := new(proto.Empty) err := s.peer.Done(c, req.GetId(), state) return res, err } -func (s *WoodpeckerServer) Wait(c context.Context, req *proto.WaitRequest) (*proto.Empty, error) { - res := new(proto.Empty) - err := s.peer.Wait(c, req.GetId()) +// Wait blocks until the workflow is complete. +// Also signals via err if workflow got canceled. +func (s *WoodpeckerServer) Wait(c context.Context, req *proto.WaitRequest) (*proto.WaitResponse, error) { + res := new(proto.WaitResponse) + canceled, err := s.peer.Wait(c, req.GetId()) + res.Canceled = canceled return res, err } +// Extend extends the workflow deadline. func (s *WoodpeckerServer) Extend(c context.Context, req *proto.ExtendRequest) (*proto.Empty, error) { res := new(proto.Empty) err := s.peer.Extend(c, req.GetId()) @@ -170,6 +181,7 @@ func (s *WoodpeckerServer) Log(c context.Context, req *proto.LogRequest) (*proto return res, err } +// RegisterAgent register our agent to the server. func (s *WoodpeckerServer) RegisterAgent(c context.Context, req *proto.RegisterAgentRequest) (*proto.RegisterAgentResponse, error) { res := new(proto.RegisterAgentResponse) agentInfo := req.GetInfo() @@ -184,11 +196,13 @@ func (s *WoodpeckerServer) RegisterAgent(c context.Context, req *proto.RegisterA return res, err } +// UnregisterAgent unregister our agent from the server. func (s *WoodpeckerServer) UnregisterAgent(ctx context.Context, _ *proto.Empty) (*proto.Empty, error) { err := s.peer.UnregisterAgent(ctx) return new(proto.Empty), err } +// ReportHealth reports health status of the agent to the server. func (s *WoodpeckerServer) ReportHealth(c context.Context, req *proto.ReportHealthRequest) (*proto.Empty, error) { res := new(proto.Empty) err := s.peer.ReportHealth(c, req.GetStatus()) diff --git a/server/services/config/combined_test.go b/server/services/config/combined_test.go index 2b34b9a79..e4a71596c 100644 --- a/server/services/config/combined_test.go +++ b/server/services/config/combined_test.go @@ -28,6 +28,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" "github.com/yaronf/httpsign" "go.woodpecker-ci.org/woodpecker/v3/server/forge/mocks" @@ -188,9 +189,7 @@ func TestFetchFromConfigService(t *testing.T) { defer ts.Close() client, err := utils.NewHTTPClient(privEd25519Key, "loopback") - if !assert.NoError(t, err) { - return - } + require.NoError(t, err) httpFetcher := config.NewHTTP(ts.URL+"/", client) diff --git a/server/services/config/forge.go b/server/services/config/forge.go index ec76c8346..57bf040e8 100644 --- a/server/services/config/forge.go +++ b/server/services/config/forge.go @@ -146,7 +146,9 @@ func (f *forgeFetcherContext) getFirstAvailableConfig(c context.Context, configs files, err := f.forge.Dir(c, f.user, f.repo, f.pipeline, strings.TrimSuffix(fileOrFolder, "/")) // if folder is not supported we will get a "Not implemented" error and continue if err != nil { - if !errors.Is(err, types.ErrNotImplemented) && !errors.Is(err, &types.ErrConfigNotFound{}) { + if errors.Is(err, types.ErrNotImplemented) { + log.Debug().Msg("Could not fetch config folder as forge adapter did not implement it") + } else if !errors.Is(err, &types.ErrConfigNotFound{}) { log.Error().Err(err).Str("repo", f.repo.FullName).Str("user", f.user.Login).Msgf("could not get folder from forge: %s", err) forgeErr = append(forgeErr, err) } diff --git a/server/services/config/http.go b/server/services/config/http.go index 18a239896..6c2d3f34c 100644 --- a/server/services/config/http.go +++ b/server/services/config/http.go @@ -40,7 +40,7 @@ type requestStructure struct { Repo *model.Repo `json:"repo"` Pipeline *model.Pipeline `json:"pipeline"` Netrc *model.Netrc `json:"netrc"` - Configuration []*configData `json:"configuration"` + Configuration []*configData `json:"configuration,omitempty"` } type responseStructure struct { diff --git a/server/services/encryption/aes.go b/server/services/encryption/aes.go index 00d6e3983..e23877918 100644 --- a/server/services/encryption/aes.go +++ b/server/services/encryption/aes.go @@ -19,7 +19,7 @@ import ( "encoding/base64" "fmt" - "github.com/google/tink/go/subtle/random" + "github.com/tink-crypto/tink-go/v2/subtle/random" "go.woodpecker-ci.org/woodpecker/v3/server/services/encryption/types" "go.woodpecker-ci.org/woodpecker/v3/server/store" diff --git a/server/services/encryption/aes_test.go b/server/services/encryption/aes_test.go index 1a2bc5abb..cd2eb995c 100644 --- a/server/services/encryption/aes_test.go +++ b/server/services/encryption/aes_test.go @@ -15,10 +15,12 @@ package encryption import ( + "encoding/base64" "testing" - "github.com/google/tink/go/subtle/random" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/tink-crypto/tink-go/v2/subtle/random" ) func TestShortMessageLongKey(t *testing.T) { @@ -48,3 +50,115 @@ func TestLongMessageShortKey(t *testing.T) { assert.NoError(t, err) assert.Equal(t, input, output) } + +func TestEncryptDecryptWithAssociatedData(t *testing.T) { + aes := &aesEncryptionService{} + err := aes.loadCipher(string(random.GetRandomBytes(32))) + require.NoError(t, err) + + plaintext := "secret-value-12345" + associatedData := "repo:123" + + ciphertext, err := aes.Encrypt(plaintext, associatedData) + require.NoError(t, err) + + // Decrypt with correct associated data should succeed + decrypted, err := aes.Decrypt(ciphertext, associatedData) + require.NoError(t, err) + assert.Equal(t, plaintext, decrypted) + + // Decrypt with wrong associated data should fail + _, err = aes.Decrypt(ciphertext, "repo:456") + assert.Error(t, err, "decryption should fail with wrong associated data") + + // Decrypt with empty associated data should fail + _, err = aes.Decrypt(ciphertext, "") + assert.Error(t, err, "decryption should fail with missing associated data") +} + +func TestEncryptProducesUniqueCiphertexts(t *testing.T) { + aes := &aesEncryptionService{} + err := aes.loadCipher(string(random.GetRandomBytes(32))) + require.NoError(t, err) + + plaintext := "same-message" + ciphertexts := make(map[string]bool) + + // Encrypt the same message multiple times + for range 100 { + ct, err := aes.Encrypt(plaintext, "") + require.NoError(t, err) + assert.False(t, ciphertexts[ct], "ciphertext should be unique due to random nonce") + ciphertexts[ct] = true + } +} + +func TestDecryptTamperedCiphertext(t *testing.T) { + aes := &aesEncryptionService{} + err := aes.loadCipher(string(random.GetRandomBytes(32))) + require.NoError(t, err) + + plaintext := "sensitive-data" + ciphertext, err := aes.Encrypt(plaintext, "") + require.NoError(t, err) + + // Decode, tamper, re-encode + decoded, err := base64.StdEncoding.DecodeString(ciphertext) + require.NoError(t, err) + + // Tamper with the ciphertext (flip a bit in the middle) + if len(decoded) > AES_GCM_SIV_NonceSize+1 { + decoded[AES_GCM_SIV_NonceSize+1] ^= 0xFF + } + tampered := base64.StdEncoding.EncodeToString(decoded) + + _, err = aes.Decrypt(tampered, "") + assert.Error(t, err, "decryption of tampered ciphertext should fail") +} + +func TestDecryptInvalidBase64(t *testing.T) { + aes := &aesEncryptionService{} + err := aes.loadCipher(string(random.GetRandomBytes(32))) + require.NoError(t, err) + + _, err = aes.Decrypt("not-valid-base64!!!", "") + assert.Error(t, err, "decryption of invalid base64 should fail") +} + +func TestDecryptTruncatedCiphertext(t *testing.T) { + aes := &aesEncryptionService{} + err := aes.loadCipher(string(random.GetRandomBytes(32))) + require.NoError(t, err) + + plaintext := "test-message" + ciphertext, err := aes.Encrypt(plaintext, "") + require.NoError(t, err) + + // Truncate the ciphertext + decoded, err := base64.StdEncoding.DecodeString(ciphertext) + require.NoError(t, err) + + truncated := base64.StdEncoding.EncodeToString(decoded[:len(decoded)/2]) + _, err = aes.Decrypt(truncated, "") + assert.Error(t, err, "decryption of truncated ciphertext should fail") +} + +func TestRandomBytesUniqueness(t *testing.T) { + seen := make(map[string]bool) + + for range 1000 { + bytes := random.GetRandomBytes(32) + key := string(bytes) + assert.False(t, seen[key], "random bytes should be unique") + seen[key] = true + } +} + +func TestRandomBytesLength(t *testing.T) { + tests := []uint32{1, 12, 16, 32, 64, 128, 256} + + for _, length := range tests { + bytes := random.GetRandomBytes(length) + assert.Len(t, bytes, int(length), "random bytes should have requested length") + } +} diff --git a/server/services/encryption/tink.go b/server/services/encryption/tink.go index 033315be7..0b59a993c 100644 --- a/server/services/encryption/tink.go +++ b/server/services/encryption/tink.go @@ -19,7 +19,7 @@ import ( "fmt" "github.com/fsnotify/fsnotify" - "github.com/google/tink/go/tink" + "github.com/tink-crypto/tink-go/v2/tink" "go.woodpecker-ci.org/woodpecker/v3/server/services/encryption/types" "go.woodpecker-ci.org/woodpecker/v3/server/store" diff --git a/server/services/encryption/tink_keyset.go b/server/services/encryption/tink_keyset.go index a3e7ae4b3..0b989e91a 100644 --- a/server/services/encryption/tink_keyset.go +++ b/server/services/encryption/tink_keyset.go @@ -20,10 +20,10 @@ import ( "os" "strconv" - "github.com/google/tink/go/aead" - insecure_clear_text_keyset "github.com/google/tink/go/insecurecleartextkeyset" - "github.com/google/tink/go/keyset" "github.com/rs/zerolog/log" + "github.com/tink-crypto/tink-go/v2/aead" + insecure_clear_text_keyset "github.com/tink-crypto/tink-go/v2/insecurecleartextkeyset" + "github.com/tink-crypto/tink-go/v2/keyset" "go.woodpecker-ci.org/woodpecker/v3/server/store/types" ) diff --git a/server/services/log/file/file.go b/server/services/log/file/file.go index c150b4b53..e5c400728 100644 --- a/server/services/log/file/file.go +++ b/server/services/log/file/file.go @@ -50,6 +50,7 @@ func (l logStore) LogFind(step *model.Step) ([]*model.LogEntry, error) { } return nil, err } + defer file.Close() buf := make([]byte, 0, bufio.MaxScanTokenSize) s := bufio.NewScanner(file) diff --git a/server/services/manager.go b/server/services/manager.go index 43e370cd5..7c6417ed6 100644 --- a/server/services/manager.go +++ b/server/services/manager.go @@ -119,6 +119,9 @@ func (m *manager) RegistryService() registry.Service { func (m *manager) ConfigServiceFromRepo(repo *model.Repo) config.Service { if repo.ConfigExtensionEndpoint != "" { + if repo.ConfigExtensionExclusive { + return config.NewHTTP(strings.TrimRight(repo.ConfigExtensionEndpoint, "/"), m.client) + } return config.NewCombined(m.config, config.NewHTTP(strings.TrimRight(repo.ConfigExtensionEndpoint, "/"), m.client)) } diff --git a/server/services/setup.go b/server/services/setup.go index 1079326f6..c6677aec2 100644 --- a/server/services/setup.go +++ b/server/services/setup.go @@ -68,6 +68,9 @@ func setupConfigService(c *cli.Command, client *utils.Client) (config.Service, e if endpoint := c.String("config-service-endpoint"); endpoint != "" { httpFetcher := config.NewHTTP(endpoint, client) + if c.Bool("config-service-exclusive") { + return httpFetcher, nil + } return config.NewCombined(configFetcher, httpFetcher), nil } diff --git a/server/services/utils/http.go b/server/services/utils/http.go index 711b665b6..6aad37e6f 100644 --- a/server/services/utils/http.go +++ b/server/services/utils/http.go @@ -21,12 +21,17 @@ import ( "crypto/ed25519" "crypto/tls" "encoding/json" + "errors" "fmt" "io" + "net" "net/http" "net/url" + "strings" "time" + "github.com/cenkalti/backoff/v5" + "github.com/rs/zerolog/log" "github.com/yaronf/httpsign" host_matcher "go.woodpecker-ci.org/woodpecker/v3/server/services/utils/hostmatcher" @@ -89,49 +94,146 @@ func NewHTTPClient(privateKey crypto.PrivateKey, allowedHostList string) (*Clien }, nil } -// Send makes an http request to the given endpoint, writing the input -// to the request body and un-marshaling the output from the response body. +// Send makes an http request with retry logic. func (e *Client) Send(ctx context.Context, method, path string, in, out any) (int, error) { + // Maximum number of retries + const maxRetries = 3 + + log.Debug().Msgf("HTTP request: %s %s, retries enabled (max: %d)", method, path, maxRetries) + + // Prepare request body bytes for possible retries + var bodyBytes []byte + if in != nil { + buf := new(bytes.Buffer) + if err := json.NewEncoder(buf).Encode(in); err != nil { + return 0, err + } + bodyBytes = buf.Bytes() + } + + // Parse URI once uri, err := url.Parse(path) if err != nil { return 0, err } - // if we are posting or putting data, we need to write it to the body of the request. - var buf io.ReadWriter - if in != nil { - buf = new(bytes.Buffer) - jsonErr := json.NewEncoder(buf).Encode(in) - if jsonErr != nil { - return 0, jsonErr + // Create backoff configuration + exponentialBackoff := backoff.NewExponentialBackOff() + + // Execute with backoff retry + return backoff.Retry(ctx, func() (int, error) { + // Check if context is already canceled + if ctx.Err() != nil { + return 0, ctx.Err() } - } - // creates a new http request to the endpoint. - req, err := http.NewRequestWithContext(ctx, method, uri.String(), buf) - if err != nil { - return 0, err - } - if in != nil { - req.Header.Set("Content-Type", "application/json") - } + // Create request body for this attempt + var body io.Reader + if len(bodyBytes) > 0 { + body = bytes.NewReader(bodyBytes) + } - resp, err := e.Do(req) - if err != nil { - return 0, err - } - defer resp.Body.Close() - - if resp.StatusCode < http.StatusOK || resp.StatusCode >= http.StatusMultipleChoices { - body, err := io.ReadAll(resp.Body) + // Create new request for each attempt + req, err := http.NewRequestWithContext(ctx, method, uri.String(), body) if err != nil { - return resp.StatusCode, err + return 0, err + } + if in != nil { + req.Header.Set("Content-Type", "application/json") } - return resp.StatusCode, fmt.Errorf("response: %s", string(body)) + // Send request + resp, err := e.Do(req) + if err != nil { + // Check if this is a retryable error + if !isRetryableError(err) { + log.Error().Err(err).Msgf("HTTP request failed (not retryable): %s %s", method, path) + return 0, backoff.Permanent(err) + } + return 0, err + } + + statusCode := resp.StatusCode + // Read body immediately to ensure proper resource cleanup for retries + respBody, readErr := io.ReadAll(resp.Body) + resp.Body.Close() + if readErr != nil { + // Check if this is a retryable error + if !isRetryableError(readErr) { + log.Error().Err(readErr).Msgf("HTTP response read failed (not retryable): %s %s", method, path) + return statusCode, backoff.Permanent(readErr) + } + return statusCode, readErr + } + + // Check if status code is retryable + if isRetryableStatusCode(statusCode) { + return statusCode, fmt.Errorf("response: %d", statusCode) + } + + // If status code is client error (4xx), don't retry + if statusCode >= http.StatusBadRequest && statusCode < http.StatusInternalServerError { + log.Debug().Int("status", statusCode).Msgf("HTTP request returned client error (not retryable): %s %s", method, path) + return statusCode, backoff.Permanent(fmt.Errorf("response: %s", string(respBody))) + } + + // If status code is OK (2xx), parse and return response + if statusCode >= http.StatusOK && statusCode < http.StatusMultipleChoices { + if out != nil { + err = json.NewDecoder(bytes.NewReader(respBody)).Decode(out) + // Check for EOF error during response body parsing + if err != nil && (errors.Is(err, io.EOF) || strings.Contains(err.Error(), "unexpected EOF")) { + return statusCode, err + } + if err != nil { + log.Error().Err(err).Msgf("HTTP response parsing failed (not retryable): %s %s", method, path) + return statusCode, backoff.Permanent(err) + } + } + log.Debug().Int("status", statusCode).Msgf("HTTP request succeeded: %s %s", method, path) + return statusCode, nil + } + + // For any other status code, don't retry + log.Error().Int("status", statusCode).Msgf("HTTP request returned unexpected status code (not retryable): %s %s", method, path) + return statusCode, backoff.Permanent(fmt.Errorf("response: %s", string(respBody))) + }, backoff.WithBackOff(exponentialBackoff), backoff.WithMaxTries(maxRetries), + backoff.WithNotify(func(err error, delay time.Duration) { + // Log retry attempts + log.Debug().Err(err).Msgf("HTTP request failed, retrying in %v: %s %s", delay, method, path) + }), + ) +} + +// isRetryableError checks if an error is transient and suitable for retry. +func isRetryableError(err error) bool { + // Check for network-related errors + var netErr net.Error + if errors.As(err, &netErr) { + // Retry on timeout errors + if netErr.Timeout() { + return true + } } - // if no other errors parse and return the json response. - err = json.NewDecoder(resp.Body).Decode(out) - return resp.StatusCode, err + // Check for specific error types + switch { + case errors.Is(err, net.ErrClosed), + errors.Is(err, io.EOF), + errors.Is(err, io.ErrUnexpectedEOF): + return true + } + + // Check for error strings that indicate retryable conditions + errStr := err.Error() + return strings.Contains(errStr, "connection refused") || + strings.Contains(errStr, "connection reset by peer") || + strings.Contains(errStr, "no such host") || + strings.Contains(errStr, "TLS handshake timeout") +} + +// isRetryableStatusCode checks if an HTTP status code is suitable for retry. +func isRetryableStatusCode(statusCode int) bool { + // Retry on server errors (5xx) + return statusCode >= http.StatusInternalServerError && statusCode < http.StatusNetworkAuthenticationRequired } diff --git a/server/services/utils/http_test.go b/server/services/utils/http_test.go index dc6cd3d91..d3137aa03 100644 --- a/server/services/utils/http_test.go +++ b/server/services/utils/http_test.go @@ -24,6 +24,7 @@ import ( "time" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "github.com/yaronf/httpsign" "go.woodpecker-ci.org/woodpecker/v3/server/services/utils" @@ -33,9 +34,7 @@ func TestSignClient(t *testing.T) { pubKeyID := "woodpecker-ci-extensions" pubEd25519Key, privEd25519Key, err := ed25519.GenerateKey(rand.Reader) - if !assert.NoError(t, err) { - return - } + require.NoError(t, err) body := []byte("{\"foo\":\"bar\"}") @@ -54,17 +53,13 @@ func TestSignClient(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(verifyHandler)) req, err := http.NewRequest("GET", server.URL+"/", bytes.NewBuffer(body)) - if !assert.NoError(t, err) { - return - } + require.NoError(t, err) req.Header.Set("Date", time.Now().Format(time.RFC3339)) req.Header.Set("Content-Type", "application/json") client, err := utils.NewHTTPClient(privEd25519Key, "loopback") - if !assert.NoError(t, err) { - return - } + require.NoError(t, err) rr, err := client.Do(req) assert.NoError(t, err) @@ -72,3 +67,35 @@ func TestSignClient(t *testing.T) { assert.Equal(t, http.StatusOK, rr.StatusCode) } + +func TestRetry(t *testing.T) { + _, privEd25519Key, err := ed25519.GenerateKey(rand.Reader) + require.NoError(t, err) + + numRetry := 0 + body := []byte("{\"foo\":\"bar\"}") + + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + numRetry++ + if numRetry >= 6 { + w.WriteHeader(http.StatusNoContent) + } else { + w.WriteHeader(http.StatusInternalServerError) + } + })) + + client, err := utils.NewHTTPClient(privEd25519Key, "loopback") + require.NoError(t, err) + + // first time: retry fails all the times + _, err = client.Send(t.Context(), http.MethodGet, server.URL+"/", bytes.NewBuffer(body), nil) + assert.Error(t, err) + assert.Equal(t, 3, numRetry) + + // second time: retry succeeds after two failed times + rr, err := client.Send(t.Context(), http.MethodGet, server.URL+"/", bytes.NewBuffer(body), nil) + assert.NoError(t, err) + + assert.Equal(t, http.StatusNoContent, rr) + assert.Equal(t, 6, numRetry) +} diff --git a/server/store/datastore/cron.go b/server/store/datastore/cron.go index e790c74c9..85530036f 100644 --- a/server/store/datastore/cron.go +++ b/server/store/datastore/cron.go @@ -50,7 +50,7 @@ func (s storage) CronDelete(repo *model.Repo, id int64) error { // CronListNextExecute returns limited number of jobs with NextExec being less or equal to the provided unix timestamp. func (s storage) CronListNextExecute(nextExec, limit int64) ([]*model.Cron, error) { crons := make([]*model.Cron, 0, limit) - return crons, s.engine.Where(builder.Lte{"next_exec": nextExec}).Limit(int(limit)).Find(&crons) + return crons, s.engine.Join("INNER", "repos", "repos.id = crons.repo_id").Where(builder.Lte{"next_exec": nextExec}).And(builder.Eq{"repos.active": true, "enabled": true}).Limit(int(limit)).Find(&crons) } // CronGetLock try to get a lock by updating NextExec. diff --git a/server/store/datastore/cron_test.go b/server/store/datastore/cron_test.go index 88710f91f..289c57a27 100644 --- a/server/store/datastore/cron_test.go +++ b/server/store/datastore/cron_test.go @@ -43,20 +43,27 @@ func TestCronCreate(t *testing.T) { } func TestCronListNextExecute(t *testing.T) { - store, closer := newTestStore(t, new(model.Cron)) + store, closer := newTestStore(t, new(model.Cron), new(model.Repo)) defer closer() + repo1 := &model.Repo{Name: "aaaa", Owner: "a", FullName: "a/aaaa", ForgeRemoteID: "1", IsActive: true} + repo2 := &model.Repo{Name: "bbbb", Owner: "a", FullName: "a/bbbb", ForgeRemoteID: "2", IsActive: false} + assert.NoError(t, store.CreateRepo(repo1)) + assert.NoError(t, store.CreateRepo(repo2)) + jobs, err := store.CronListNextExecute(0, 10) assert.NoError(t, err) assert.Len(t, jobs, 0) now := time.Now().Unix() - assert.NoError(t, store.CronCreate(&model.Cron{Schedule: "@every 1h", Name: "some", RepoID: 1, NextExec: now})) - assert.NoError(t, store.CronCreate(&model.Cron{Schedule: "@every 1h", Name: "aaaa", RepoID: 1, NextExec: now})) - assert.NoError(t, store.CronCreate(&model.Cron{Schedule: "@every 1h", Name: "bbbb", RepoID: 1, NextExec: now})) - assert.NoError(t, store.CronCreate(&model.Cron{Schedule: "@every 1h", Name: "none", RepoID: 1, NextExec: now + 1000})) - assert.NoError(t, store.CronCreate(&model.Cron{Schedule: "@every 1h", Name: "test", RepoID: 1, NextExec: now + 2000})) + assert.NoError(t, store.CronCreate(&model.Cron{Schedule: "@every 1h", Name: "some", RepoID: repo1.ID, NextExec: now, Enabled: true})) + assert.NoError(t, store.CronCreate(&model.Cron{Schedule: "@every 1h", Name: "aaaa", RepoID: repo1.ID, NextExec: now, Enabled: true})) + assert.NoError(t, store.CronCreate(&model.Cron{Schedule: "@every 1h", Name: "bbbb", RepoID: repo1.ID, NextExec: now, Enabled: true})) + assert.NoError(t, store.CronCreate(&model.Cron{Schedule: "@every 1h", Name: "none", RepoID: repo1.ID, NextExec: now + 1000, Enabled: true})) + assert.NoError(t, store.CronCreate(&model.Cron{Schedule: "@every 1h", Name: "test", RepoID: repo1.ID, NextExec: now + 2000, Enabled: true})) + assert.NoError(t, store.CronCreate(&model.Cron{Schedule: "@every 1h", Name: "disabled-repo", RepoID: repo2.ID, NextExec: now, Enabled: true})) + assert.NoError(t, store.CronCreate(&model.Cron{Schedule: "@every 1h", Name: "disabled-cron", RepoID: repo1.ID, NextExec: now, Enabled: false})) jobs, err = store.CronListNextExecute(now, 10) assert.NoError(t, err) diff --git a/server/store/datastore/engine_test.go b/server/store/datastore/engine_test.go index e567e7566..74ed9032c 100644 --- a/server/store/datastore/engine_test.go +++ b/server/store/datastore/engine_test.go @@ -19,7 +19,7 @@ import ( "testing" "time" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "xorm.io/xorm" "xorm.io/xorm/schemas" ) @@ -40,9 +40,7 @@ func testDriverConfig() (driver, config string) { // environment variables, with fallback to in-memory sqlite. func newTestStore(t *testing.T, tables ...any) (*storage, func()) { engine, err := xorm.NewEngine(testDriverConfig()) - if !assert.NoError(t, err) { - t.FailNow() - } + require.NoError(t, err) for _, table := range tables { if err := engine.Sync(table); err != nil { diff --git a/server/store/datastore/feed_test.go b/server/store/datastore/feed_test.go index 9f26b2289..705603c06 100644 --- a/server/store/datastore/feed_test.go +++ b/server/store/datastore/feed_test.go @@ -43,7 +43,7 @@ func TestGetPipelineQueue(t *testing.T) { assert.NoError(t, store.CreateRepo(repo1)) for _, perm := range []*model.Perm{ - {UserID: user.ID, Repo: repo1, Push: true, Admin: false}, + {UserID: user.ID, RepoID: repo1.ID, Push: true, Admin: false}, } { assert.NoError(t, store.PermUpsert(perm)) } @@ -111,7 +111,7 @@ func TestUserFeed(t *testing.T) { assert.NoError(t, store.CreateRepo(repo2)) for _, perm := range []*model.Perm{ - {UserID: user.ID, Repo: repo1, Push: true, Admin: false}, + {UserID: user.ID, RepoID: repo1.ID, Push: true, Admin: false}, } { assert.NoError(t, store.PermUpsert(perm)) } @@ -167,8 +167,8 @@ func TestRepoListLatest(t *testing.T) { assert.NoError(t, store.CreateRepo(repo3)) for _, perm := range []*model.Perm{ - {UserID: user.ID, Repo: repo1, Push: true, Admin: false}, - {UserID: user.ID, Repo: repo2, Push: true, Admin: true}, + {UserID: user.ID, RepoID: repo1.ID, Push: true, Admin: false}, + {UserID: user.ID, RepoID: repo2.ID, Push: true, Admin: true}, } { assert.NoError(t, store.PermUpsert(perm)) } diff --git a/server/store/datastore/migration/migration_test.go b/server/store/datastore/migration/migration_test.go index f38c004d7..374d6771b 100644 --- a/server/store/datastore/migration/migration_test.go +++ b/server/store/datastore/migration/migration_test.go @@ -50,9 +50,7 @@ func createSQLiteDB(t *testing.T) string { dbF, err := os.ReadFile(sqliteDB) require.NoError(t, err) - if !assert.NoError(t, os.WriteFile(tmpF.Name(), dbF, 0o644)) { - t.FailNow() - } + require.NoError(t, os.WriteFile(tmpF.Name(), dbF, 0o644)) return tmpF.Name() } diff --git a/server/store/datastore/permission.go b/server/store/datastore/permission.go index 6bbf3dc1c..51a42a2de 100644 --- a/server/store/datastore/permission.go +++ b/server/store/datastore/permission.go @@ -16,6 +16,7 @@ package datastore import ( "fmt" + "time" "xorm.io/builder" "xorm.io/xorm" @@ -45,17 +46,12 @@ func (s storage) PermUpsert(perm *model.Perm) error { } func (s storage) permUpsert(sess *xorm.Session, perm *model.Perm) error { - if perm.RepoID == 0 && perm.Repo == nil { + if perm.RepoID == 0 { return fmt.Errorf("could not determine repo for permission: %v", perm) } - // lookup repo based on name or forge ID if possible - if perm.RepoID == 0 && perm.Repo != nil { - r, err := s.getRepoNameFallback(sess, perm.Repo.ForgeID, perm.Repo.ForgeRemoteID, perm.Repo.FullName) - if err != nil { - return err - } - perm.RepoID = r.ID + if perm.UserID == 0 { + return fmt.Errorf("could not determine user for permission: %v", perm) } exist, err := sess.Where(userIDAndRepoIDCond(perm)).Exist(new(model.Perm)) @@ -64,9 +60,12 @@ func (s storage) permUpsert(sess *xorm.Session, perm *model.Perm) error { } if exist { + perm.Updated = time.Now().Unix() _, err = sess.Where(userIDAndRepoIDCond(perm)).AllCols().Update(perm) } else { - // only Insert set auto created ID back to object + // insert will set auto created ID back to perm object + perm.Created = time.Now().Unix() + perm.Updated = perm.Created _, err = sess.Insert(perm) } return err diff --git a/server/store/datastore/permission_test.go b/server/store/datastore/permission_test.go index f048bcb6f..392865780 100644 --- a/server/store/datastore/permission_test.go +++ b/server/store/datastore/permission_test.go @@ -41,7 +41,6 @@ func TestPermFind(t *testing.T) { &model.Perm{ UserID: user.ID, RepoID: repo.ID, - Repo: repo, Pull: true, Push: false, Admin: false, @@ -74,7 +73,6 @@ func TestPermUpsert(t *testing.T) { &model.Perm{ UserID: user.ID, RepoID: repo.ID, - Repo: repo, Pull: true, Push: false, Admin: false, @@ -97,7 +95,6 @@ func TestPermUpsert(t *testing.T) { &model.Perm{ UserID: user.ID, RepoID: repo.ID, - Repo: repo, Pull: true, Push: true, Admin: true, @@ -135,8 +132,8 @@ func TestPermPruneDeleteAll(t *testing.T) { assert.NoError(t, store.CreateRepo(repo1)) assert.NoError(t, store.CreateRepo(repo2)) - assert.NoError(t, store.PermUpsert(&model.Perm{UserID: user.ID, RepoID: repo1.ID, Repo: repo1, Pull: true})) - assert.NoError(t, store.PermUpsert(&model.Perm{UserID: user.ID, RepoID: repo2.ID, Repo: repo2, Pull: true})) + assert.NoError(t, store.PermUpsert(&model.Perm{UserID: user.ID, RepoID: repo1.ID, Pull: true})) + assert.NoError(t, store.PermUpsert(&model.Perm{UserID: user.ID, RepoID: repo2.ID, Pull: true})) _, err := store.PermFind(user, repo1) assert.NoError(t, err) @@ -174,8 +171,8 @@ func TestPermPruneKeepOne(t *testing.T) { assert.NoError(t, store.CreateRepo(repo1)) assert.NoError(t, store.CreateRepo(repo2)) - assert.NoError(t, store.PermUpsert(&model.Perm{UserID: user.ID, RepoID: repo1.ID, Repo: repo1, Pull: true})) - assert.NoError(t, store.PermUpsert(&model.Perm{UserID: user.ID, RepoID: repo2.ID, Repo: repo2, Pull: true})) + assert.NoError(t, store.PermUpsert(&model.Perm{UserID: user.ID, RepoID: repo1.ID, Pull: true})) + assert.NoError(t, store.PermUpsert(&model.Perm{UserID: user.ID, RepoID: repo2.ID, Pull: true})) _, err := store.PermFind(user, repo1) assert.NoError(t, err) diff --git a/server/store/datastore/pipeline.go b/server/store/datastore/pipeline.go index 602ccc78e..de1bca84e 100644 --- a/server/store/datastore/pipeline.go +++ b/server/store/datastore/pipeline.go @@ -15,8 +15,11 @@ package datastore import ( + "context" + "strings" "time" + "github.com/cenkalti/backoff/v5" "xorm.io/builder" "xorm.io/xorm" @@ -45,7 +48,7 @@ func (s storage) GetPipelineBadge(repo *model.Repo, branch string, events []mode Get(pipeline)) } -func (s storage) GetPipelineLast(repo *model.Repo, branch string) (*model.Pipeline, error) { +func (s storage) GetPipelineLastByBranch(repo *model.Repo, branch string) (*model.Pipeline, error) { pipeline := new(model.Pipeline) return pipeline, wrapGet(s.engine. Desc("number"). @@ -128,47 +131,80 @@ func (s storage) GetPipelineCount() (int64, error) { return s.engine.Count(new(model.Pipeline)) } +// CreatePipeline creates a new pipeline with retry logic for unique constraint errors. func (s storage) CreatePipeline(pipeline *model.Pipeline, stepList ...*model.Step) error { - sess := s.engine.NewSession() - defer sess.Close() - if err := sess.Begin(); err != nil { - return err - } + // Maximum number of retries + const maxRetries = 3 - repoExist, err := sess.Where("id = ?", pipeline.RepoID).Exist(&model.Repo{}) - if err != nil { - return err - } + // Create backoff configuration + exponentialBackoff := backoff.NewExponentialBackOff() - if !repoExist { - return ErrorRepoNotExist{RepoID: pipeline.RepoID} - } - - // calc pipeline number - var number int64 - if _, err := sess.Select("MAX(number)"). - Table(new(model.Pipeline)). - Where("repo_id = ?", pipeline.RepoID). - Get(&number); err != nil { - return err - } - pipeline.Number = number + 1 - - pipeline.Created = time.Now().UTC().Unix() - // only Insert set auto created ID back to object - if _, err := sess.Insert(pipeline); err != nil { - return err - } - - for i := range stepList { - stepList[i].PipelineID = pipeline.ID - // only Insert set auto created ID back to object - if _, err := sess.Insert(stepList[i]); err != nil { - return err + // Execute with backoff retry + _, err := backoff.Retry(context.Background(), func() (struct{}, error) { + sess := s.engine.NewSession() + defer sess.Close() + if err := sess.Begin(); err != nil { + return struct{}{}, err } + + repoExist, err := sess.Where("id = ?", pipeline.RepoID).Exist(&model.Repo{}) + if err != nil { + return struct{}{}, err + } + + if !repoExist { + return struct{}{}, ErrorRepoNotExist{RepoID: pipeline.RepoID} + } + + // calc pipeline number + var number int64 + if _, err := sess.Select("MAX(number)"). + Table(new(model.Pipeline)). + Where("repo_id = ?", pipeline.RepoID). + Get(&number); err != nil { + return struct{}{}, err + } + pipeline.Number = number + 1 + + pipeline.Created = time.Now().UTC().Unix() + // only Insert set auto created ID back to object + if _, err := sess.Insert(pipeline); err != nil { + if isUniqueConstraintError(err) { + return struct{}{}, err + } + return struct{}{}, backoff.Permanent(err) + } + + for i := range stepList { + stepList[i].PipelineID = pipeline.ID + // only Insert set auto created ID back to object + if _, err := sess.Insert(stepList[i]); err != nil { + if isUniqueConstraintError(err) { + return struct{}{}, err + } + return struct{}{}, backoff.Permanent(err) + } + } + + return struct{}{}, sess.Commit() + }, backoff.WithBackOff(exponentialBackoff), backoff.WithMaxTries(maxRetries)) + + return err +} + +// isUniqueConstraintError checks if an error is a unique constraint violation error. +func isUniqueConstraintError(err error) bool { + if err == nil { + return false } - return sess.Commit() + errStr := err.Error() + // Check for common unique constraint error patterns across different databases + return strings.Contains(errStr, "duplicate key") || + strings.Contains(errStr, "Duplicate entry") || + strings.Contains(errStr, "UNIQUE constraint failed") || + strings.Contains(errStr, "unique constraint") || + strings.Contains(errStr, "UNIQUE violation") } func (s storage) UpdatePipeline(pipeline *model.Pipeline) error { diff --git a/server/store/datastore/pipeline_test.go b/server/store/datastore/pipeline_test.go index 44d42fcf6..4dae15b7f 100644 --- a/server/store/datastore/pipeline_test.go +++ b/server/store/datastore/pipeline_test.go @@ -20,6 +20,7 @@ import ( "time" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "go.woodpecker-ci.org/woodpecker/v3/server/model" "go.woodpecker-ci.org/woodpecker/v3/server/store/types" @@ -55,6 +56,7 @@ func TestPipelines(t *testing.T) { RepoID: repo.ID, Status: model.StatusSuccess, Commit: "85f8c029b902ed9400bc600bac301a0aadb144ac", + Event: model.EventPush, Branch: "some-branch", } err = store.CreatePipeline(&pipeline) @@ -75,10 +77,9 @@ func TestPipelines(t *testing.T) { // update pipeline pipeline.Status = model.StatusRunning - err1 := store.UpdatePipeline(&pipeline) - GetPipeline, err2 := store.GetPipeline(pipeline.ID) - assert.NoError(t, err1) - assert.NoError(t, err2) + require.NoError(t, store.UpdatePipeline(&pipeline)) + GetPipeline, err1 := store.GetPipeline(pipeline.ID) + require.NoError(t, err1) assert.Equal(t, pipeline.ID, GetPipeline.ID) assert.Equal(t, pipeline.RepoID, GetPipeline.RepoID) assert.Equal(t, pipeline.Status, GetPipeline.Status) @@ -90,38 +91,33 @@ func TestPipelines(t *testing.T) { Event: model.EventPush, Branch: "main", } - err2 = store.CreatePipeline(pipeline2, []*model.Step{}...) - assert.NoError(t, err2) + require.NoError(t, store.CreatePipeline(pipeline2, []*model.Step{}...)) GetPipeline, err3 := store.GetPipelineNumber(&model.Repo{ID: 1}, pipeline2.Number) - assert.NoError(t, err3) + require.NoError(t, err3) assert.Equal(t, pipeline2.ID, GetPipeline.ID) assert.Equal(t, pipeline2.RepoID, GetPipeline.RepoID) assert.Equal(t, pipeline2.Number, GetPipeline.Number) - GetPipeline, err3 = store.GetPipelineLast(&model.Repo{ID: repo.ID}, pipeline2.Branch) - assert.NoError(t, err3) + GetPipeline, err4 := store.GetPipelineLastByBranch(&model.Repo{ID: repo.ID}, pipeline2.Branch) + require.NoError(t, err4) assert.Equal(t, pipeline2.ID, GetPipeline.ID) assert.Equal(t, pipeline2.RepoID, GetPipeline.RepoID) assert.Equal(t, pipeline2.Number, GetPipeline.Number) assert.Equal(t, pipeline2.Status, GetPipeline.Status) pipeline3 := &model.Pipeline{ - RepoID: repo.ID, - Status: model.StatusRunning, - Branch: "main", - Commit: "85f8c029b902ed9400bc600bac301a0aadb144aa", + RepoID: repo.ID, + Status: model.StatusRunning, + Branch: "main", + Event: model.EventPull, + Commit: "85f8c029b902ed9400bc600bac301a0aadb144aa", + ForgeURL: "example.com/id3", } - err1 = store.CreatePipeline(pipeline3, []*model.Step{}...) - assert.NoError(t, err1) + require.NoError(t, store.CreatePipeline(pipeline3)) - GetPipeline, err4 := store.GetPipelineLastBefore(&model.Repo{ID: 1}, pipeline3.Branch, pipeline3.ID) - assert.NoError(t, err4) - assert.Equal(t, pipeline2.ID, GetPipeline.ID) - assert.Equal(t, pipeline2.RepoID, GetPipeline.RepoID) - assert.Equal(t, pipeline2.Number, GetPipeline.Number) - assert.Equal(t, pipeline2.Status, GetPipeline.Status) - assert.Equal(t, pipeline2.Branch, GetPipeline.Branch) - assert.Equal(t, pipeline2.Commit, GetPipeline.Commit) + GetPipeline, err5 := store.GetPipelineLastBefore(&model.Repo{ID: 1}, pipeline3.Branch, pipeline3.ID) + require.NoError(t, err5) + assert.EqualValues(t, pipeline2, GetPipeline) } func TestPipelineListFilter(t *testing.T) { @@ -210,9 +206,7 @@ func TestPipelineIncrement(t *testing.T) { assert.NoError(t, store.CreateRepo(&model.Repo{ID: 2, Owner: "2", Name: "2", FullName: "2/2", ForgeRemoteID: "2"})) pipelineA := &model.Pipeline{RepoID: 1} - if !assert.NoError(t, store.CreatePipeline(pipelineA)) { - return - } + require.NoError(t, store.CreatePipeline(pipelineA)) assert.EqualValues(t, 1, pipelineA.Number) pipelineB := &model.Pipeline{RepoID: 1} diff --git a/server/store/datastore/registry_test.go b/server/store/datastore/registry_test.go index a1cbfa0d8..29dcece61 100644 --- a/server/store/datastore/registry_test.go +++ b/server/store/datastore/registry_test.go @@ -114,9 +114,7 @@ func TestRegistryDelete(t *testing.T) { Username: "foo", Password: "bar", } - if !assert.NoError(t, store.RegistryCreate(reg1)) { - return - } + require.NoError(t, store.RegistryCreate(reg1)) assert.NoError(t, store.RegistryDelete(reg1)) assert.ErrorIs(t, store.RegistryDelete(reg1), types.RecordNotExist) diff --git a/server/store/datastore/repo_test.go b/server/store/datastore/repo_test.go index edc05b817..8ff01e5cb 100644 --- a/server/store/datastore/repo_test.go +++ b/server/store/datastore/repo_test.go @@ -146,8 +146,8 @@ func TestRepoList(t *testing.T) { assert.NoError(t, store.CreateRepo(repo3)) for _, perm := range []*model.Perm{ - {UserID: user.ID, Repo: repo1}, - {UserID: user.ID, Repo: repo2}, + {UserID: user.ID, RepoID: repo1.ID}, + {UserID: user.ID, RepoID: repo2.ID}, } { assert.NoError(t, store.PermUpsert(perm)) } @@ -234,10 +234,10 @@ func TestOwnedRepoList(t *testing.T) { assert.NoError(t, store.CreateRepo(repo4)) for _, perm := range []*model.Perm{ - {UserID: user.ID, Repo: repo1, Push: true, Admin: false}, - {UserID: user.ID, Repo: repo2, Push: false, Admin: true}, - {UserID: user.ID, Repo: repo3}, - {UserID: user.ID, Repo: repo4}, + {UserID: user.ID, RepoID: repo1.ID, Push: true, Admin: false}, + {UserID: user.ID, RepoID: repo2.ID, Push: false, Admin: true}, + {UserID: user.ID, RepoID: repo3.ID}, + {UserID: user.ID, RepoID: repo4.ID}, } { assert.NoError(t, store.PermUpsert(perm)) } diff --git a/server/store/datastore/step_test.go b/server/store/datastore/step_test.go index 95d7bba88..0cfa651f7 100644 --- a/server/store/datastore/step_test.go +++ b/server/store/datastore/step_test.go @@ -19,6 +19,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "go.woodpecker-ci.org/woodpecker/v3/server/model" "go.woodpecker-ci.org/woodpecker/v3/server/store/types" @@ -48,9 +49,7 @@ func TestStepFind(t *testing.T) { assert.NoError(t, sess.Close()) step, err := store.StepFind(&model.Pipeline{ID: 1000}, 1) - if !assert.NoError(t, err) { - return - } + require.NoError(t, err) assert.Equal(t, steps[0], step) } diff --git a/server/store/datastore/workflow.go b/server/store/datastore/workflow.go index 714c7a674..20bd773a2 100644 --- a/server/store/datastore/workflow.go +++ b/server/store/datastore/workflow.go @@ -85,9 +85,9 @@ func (s storage) WorkflowsReplace(pipeline *model.Pipeline, workflows []*model.W func (s storage) workflowsDelete(sess *xorm.Session, pipelineID int64) error { // delete related steps - for startSteps := 0; ; startSteps += perPage { + for { stepIDs := make([]int64, 0, perPage) - if err := sess.Limit(perPage, startSteps).Table("steps").Cols("id").Where("pipeline_id = ?", pipelineID).Find(&stepIDs); err != nil { + if err := sess.Limit(perPage).Table("steps").Cols("id").Where("pipeline_id = ?", pipelineID).Find(&stepIDs); err != nil { return err } if len(stepIDs) == 0 { diff --git a/server/store/mocks/mock_Store.go b/server/store/mocks/mock_Store.go index 7566c0005..7a0a6ba7a 100644 --- a/server/store/mocks/mock_Store.go +++ b/server/store/mocks/mock_Store.go @@ -1948,74 +1948,6 @@ func (_c *MockStore_GetPipelineCount_Call) RunAndReturn(run func() (int64, error return _c } -// GetPipelineLast provides a mock function for the type MockStore -func (_mock *MockStore) GetPipelineLast(repo *model.Repo, s string) (*model.Pipeline, error) { - ret := _mock.Called(repo, s) - - if len(ret) == 0 { - panic("no return value specified for GetPipelineLast") - } - - var r0 *model.Pipeline - var r1 error - if returnFunc, ok := ret.Get(0).(func(*model.Repo, string) (*model.Pipeline, error)); ok { - return returnFunc(repo, s) - } - if returnFunc, ok := ret.Get(0).(func(*model.Repo, string) *model.Pipeline); ok { - r0 = returnFunc(repo, s) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*model.Pipeline) - } - } - if returnFunc, ok := ret.Get(1).(func(*model.Repo, string) error); ok { - r1 = returnFunc(repo, s) - } else { - r1 = ret.Error(1) - } - return r0, r1 -} - -// MockStore_GetPipelineLast_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPipelineLast' -type MockStore_GetPipelineLast_Call struct { - *mock.Call -} - -// GetPipelineLast is a helper method to define mock.On call -// - repo *model.Repo -// - s string -func (_e *MockStore_Expecter) GetPipelineLast(repo interface{}, s interface{}) *MockStore_GetPipelineLast_Call { - return &MockStore_GetPipelineLast_Call{Call: _e.mock.On("GetPipelineLast", repo, s)} -} - -func (_c *MockStore_GetPipelineLast_Call) Run(run func(repo *model.Repo, s string)) *MockStore_GetPipelineLast_Call { - _c.Call.Run(func(args mock.Arguments) { - var arg0 *model.Repo - if args[0] != nil { - arg0 = args[0].(*model.Repo) - } - var arg1 string - if args[1] != nil { - arg1 = args[1].(string) - } - run( - arg0, - arg1, - ) - }) - return _c -} - -func (_c *MockStore_GetPipelineLast_Call) Return(pipeline *model.Pipeline, err error) *MockStore_GetPipelineLast_Call { - _c.Call.Return(pipeline, err) - return _c -} - -func (_c *MockStore_GetPipelineLast_Call) RunAndReturn(run func(repo *model.Repo, s string) (*model.Pipeline, error)) *MockStore_GetPipelineLast_Call { - _c.Call.Return(run) - return _c -} - // GetPipelineLastBefore provides a mock function for the type MockStore func (_mock *MockStore) GetPipelineLastBefore(repo *model.Repo, s string, n int64) (*model.Pipeline, error) { ret := _mock.Called(repo, s, n) @@ -2090,6 +2022,74 @@ func (_c *MockStore_GetPipelineLastBefore_Call) RunAndReturn(run func(repo *mode return _c } +// GetPipelineLastByBranch provides a mock function for the type MockStore +func (_mock *MockStore) GetPipelineLastByBranch(repo *model.Repo, s string) (*model.Pipeline, error) { + ret := _mock.Called(repo, s) + + if len(ret) == 0 { + panic("no return value specified for GetPipelineLastByBranch") + } + + var r0 *model.Pipeline + var r1 error + if returnFunc, ok := ret.Get(0).(func(*model.Repo, string) (*model.Pipeline, error)); ok { + return returnFunc(repo, s) + } + if returnFunc, ok := ret.Get(0).(func(*model.Repo, string) *model.Pipeline); ok { + r0 = returnFunc(repo, s) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*model.Pipeline) + } + } + if returnFunc, ok := ret.Get(1).(func(*model.Repo, string) error); ok { + r1 = returnFunc(repo, s) + } else { + r1 = ret.Error(1) + } + return r0, r1 +} + +// MockStore_GetPipelineLastByBranch_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPipelineLastByBranch' +type MockStore_GetPipelineLastByBranch_Call struct { + *mock.Call +} + +// GetPipelineLastByBranch is a helper method to define mock.On call +// - repo *model.Repo +// - s string +func (_e *MockStore_Expecter) GetPipelineLastByBranch(repo interface{}, s interface{}) *MockStore_GetPipelineLastByBranch_Call { + return &MockStore_GetPipelineLastByBranch_Call{Call: _e.mock.On("GetPipelineLastByBranch", repo, s)} +} + +func (_c *MockStore_GetPipelineLastByBranch_Call) Run(run func(repo *model.Repo, s string)) *MockStore_GetPipelineLastByBranch_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 *model.Repo + if args[0] != nil { + arg0 = args[0].(*model.Repo) + } + var arg1 string + if args[1] != nil { + arg1 = args[1].(string) + } + run( + arg0, + arg1, + ) + }) + return _c +} + +func (_c *MockStore_GetPipelineLastByBranch_Call) Return(pipeline *model.Pipeline, err error) *MockStore_GetPipelineLastByBranch_Call { + _c.Call.Return(pipeline, err) + return _c +} + +func (_c *MockStore_GetPipelineLastByBranch_Call) RunAndReturn(run func(repo *model.Repo, s string) (*model.Pipeline, error)) *MockStore_GetPipelineLastByBranch_Call { + _c.Call.Return(run) + return _c +} + // GetPipelineList provides a mock function for the type MockStore func (_mock *MockStore) GetPipelineList(repo *model.Repo, listOptions *model.ListOptions, pipelineFilter *model.PipelineFilter) ([]*model.Pipeline, error) { ret := _mock.Called(repo, listOptions, pipelineFilter) diff --git a/server/store/store.go b/server/store/store.go index 7ec56ee49..504174908 100644 --- a/server/store/store.go +++ b/server/store/store.go @@ -72,8 +72,8 @@ type Store interface { GetPipelineNumber(*model.Repo, int64) (*model.Pipeline, error) // GetPipelineBadge gets the last relevant pipeline for the badge. GetPipelineBadge(*model.Repo, string, []model.WebhookEvent) (*model.Pipeline, error) - // GetPipelineLast gets the last pipeline for the branch. - GetPipelineLast(*model.Repo, string) (*model.Pipeline, error) + // GetPipelineLastByBranch gets the last pipeline for the branch. + GetPipelineLastByBranch(*model.Repo, string) (*model.Pipeline, error) // GetPipelineLastBefore gets the last pipeline before pipeline number N. GetPipelineLastBefore(*model.Repo, string, int64) (*model.Pipeline, error) // GetPipelineList gets a list of pipelines for the repository diff --git a/shared/constant/constant.go b/shared/constant/constant.go index ea06cdcc4..675ac8d91 100644 --- a/shared/constant/constant.go +++ b/shared/constant/constant.go @@ -27,7 +27,7 @@ var DefaultConfigOrder = [...]string{ const ( // DefaultClonePlugin can be changed by 'WOODPECKER_DEFAULT_CLONE_PLUGIN' at runtime. // renovate: datasource=docker depName=woodpeckerci/plugin-git - DefaultClonePlugin = "docker.io/woodpeckerci/plugin-git:2.7.0" + DefaultClonePlugin = "docker.io/woodpeckerci/plugin-git:2.8.1" ) // TrustedClonePlugins can be changed by 'WOODPECKER_PLUGINS_TRUSTED_CLONE' at runtime. diff --git a/web/eslint.config.js b/web/eslint.config.js index 9b2a9515a..726b9367b 100644 --- a/web/eslint.config.js +++ b/web/eslint.config.js @@ -95,6 +95,7 @@ export default antfu( }, ], 'vue/singleline-html-element-content-newline': ['off'], + 'no-useless-assignment': ['off'], }, }, diff --git a/web/package.json b/web/package.json index c54dcc17e..28cd7048c 100644 --- a/web/package.json +++ b/web/package.json @@ -35,16 +35,16 @@ "tailwindcss": "4", "vue": "^3.5.18", "vue-i18n": "^11.1.11", - "vue-router": "^4.5.1" + "vue-router": "^5.0.0" }, "devDependencies": { - "@antfu/eslint-config": "^6.0.0", - "@eslint/js": "^9.17.0", + "@antfu/eslint-config": "^7.0.0", + "@eslint/js": "^10.0.0", "@ianvs/prettier-plugin-sort-imports": "^4.5.1", - "@intlify/eslint-plugin-vue-i18n": "4.1.0", + "@intlify/eslint-plugin-vue-i18n": "4.1.1", "@intlify/unplugin-vue-i18n": "^11.0.0", "@tailwindcss/typography": "^0.5.16", - "@tailwindcss/vite": "4.1.18", + "@tailwindcss/vite": "4.2.0", "@types/lodash": "^4.17.20", "@types/node": "^24.0.0", "@types/prismjs": "^1.26.5", @@ -54,10 +54,10 @@ "@vue/compiler-sfc": "^3.5.18", "@vue/test-utils": "^2.4.6", "dotenv": "^17.2.0", - "eslint": "^9.17.0", + "eslint": "^10.0.0", "eslint-plugin-promise": "^7.2.1", "eslint-plugin-vue-scoped-css": "^2.9.0", - "jsdom": "^27.0.0", + "jsdom": "^28.0.0", "prettier": "^3.6.2", "prettier-plugin-tailwindcss": "^0.7.0", "tinycolor2": "^1.6.0", diff --git a/web/pnpm-lock.yaml b/web/pnpm-lock.yaml index dc6f1f729..4741f4e1d 100644 --- a/web/pnpm-lock.yaml +++ b/web/pnpm-lock.yaml @@ -13,13 +13,13 @@ importers: dependencies: '@kyvg/vue3-notification': specifier: ^3.4.1 - version: 3.4.2(vue@3.5.25(typescript@5.9.3)) + version: 3.4.2(vue@3.5.28(typescript@5.9.3)) '@mdi/js': specifier: ^7.4.47 version: 7.4.47 '@vueuse/core': specifier: ^14.0.0 - version: 14.1.0(vue@3.5.25(typescript@5.9.3)) + version: 14.2.1(vue@3.5.28(typescript@5.9.3)) ansi_up: specifier: ^6.0.6 version: 6.0.6 @@ -34,68 +34,68 @@ importers: version: 3.7.8 lodash: specifier: ^4.17.21 - version: 4.17.21 + version: 4.17.23 marked: specifier: ^17.0.0 - version: 17.0.1 + version: 17.0.3 node-emoji: specifier: ^2.2.0 version: 2.2.0 pinia: specifier: ^3.0.3 - version: 3.0.4(typescript@5.9.3)(vue@3.5.25(typescript@5.9.3)) + version: 3.0.4(typescript@5.9.3)(vue@3.5.28(typescript@5.9.3)) prismjs: specifier: ^1.30.0 version: 1.30.0 semver: specifier: ^7.7.2 - version: 7.7.3 + version: 7.7.4 simple-icons: specifier: ^16.0.0 - version: 16.2.0 + version: 16.9.0 tailwindcss: specifier: '4' - version: 4.1.18 + version: 4.2.0 vue: specifier: ^3.5.18 - version: 3.5.25(typescript@5.9.3) + version: 3.5.28(typescript@5.9.3) vue-i18n: specifier: ^11.1.11 - version: 11.2.2(vue@3.5.25(typescript@5.9.3)) + version: 11.2.8(vue@3.5.28(typescript@5.9.3)) vue-router: - specifier: ^4.5.1 - version: 4.6.4(vue@3.5.25(typescript@5.9.3)) + specifier: ^5.0.0 + version: 5.0.3(@vue/compiler-sfc@3.5.28)(pinia@3.0.4(typescript@5.9.3)(vue@3.5.28(typescript@5.9.3)))(vue@3.5.28(typescript@5.9.3)) devDependencies: '@antfu/eslint-config': - specifier: ^6.0.0 - version: 6.7.1(@vue/compiler-sfc@3.5.25)(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)(vitest@4.0.15(@types/node@24.10.4)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(stylus@0.57.0)(yaml@2.8.2)) + specifier: ^7.0.0 + version: 7.4.3(@vue/compiler-sfc@3.5.28)(eslint@10.0.1(jiti@2.6.1))(typescript@5.9.3)(vitest@4.0.18(@types/node@24.10.13)(jiti@2.6.1)(jsdom@28.1.0)(lightningcss@1.31.1)(stylus@0.57.0)(yaml@2.8.2)) '@eslint/js': - specifier: ^9.17.0 - version: 9.39.2 + specifier: ^10.0.0 + version: 10.0.1(eslint@10.0.1(jiti@2.6.1)) '@ianvs/prettier-plugin-sort-imports': specifier: ^4.5.1 - version: 4.7.0(@vue/compiler-sfc@3.5.25)(prettier@3.7.4) + version: 4.7.1(@vue/compiler-sfc@3.5.28)(prettier@3.8.1) '@intlify/eslint-plugin-vue-i18n': - specifier: 4.1.0 - version: 4.1.0(eslint@9.39.2(jiti@2.6.1))(jsonc-eslint-parser@2.4.2)(vue-eslint-parser@10.2.0(eslint@9.39.2(jiti@2.6.1)))(yaml-eslint-parser@1.3.2) + specifier: 4.1.1 + version: 4.1.1(eslint@10.0.1(jiti@2.6.1))(jsonc-eslint-parser@2.4.2)(vue-eslint-parser@10.4.0(eslint@10.0.1(jiti@2.6.1)))(yaml-eslint-parser@2.0.0) '@intlify/unplugin-vue-i18n': specifier: ^11.0.0 - version: 11.0.3(@vue/compiler-dom@3.5.25)(eslint@9.39.2(jiti@2.6.1))(rollup@4.53.3)(typescript@5.9.3)(vue-i18n@11.2.2(vue@3.5.25(typescript@5.9.3)))(vue@3.5.25(typescript@5.9.3)) + version: 11.0.7(@vue/compiler-dom@3.5.28)(eslint@10.0.1(jiti@2.6.1))(rollup@4.59.0)(typescript@5.9.3)(vue-i18n@11.2.8(vue@3.5.28(typescript@5.9.3)))(vue@3.5.28(typescript@5.9.3)) '@tailwindcss/typography': specifier: ^0.5.16 - version: 0.5.19(tailwindcss@4.1.18) + version: 0.5.19(tailwindcss@4.2.0) '@tailwindcss/vite': - specifier: 4.1.18 - version: 4.1.18(vite@7.2.7(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(stylus@0.57.0)(yaml@2.8.2)) + specifier: 4.2.0 + version: 4.2.0(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(stylus@0.57.0)(yaml@2.8.2)) '@types/lodash': specifier: ^4.17.20 - version: 4.17.21 + version: 4.17.23 '@types/node': specifier: ^24.0.0 - version: 24.10.4 + version: 24.10.13 '@types/prismjs': specifier: ^1.26.5 - version: 1.26.5 + version: 1.26.6 '@types/semver': specifier: ^7.7.0 version: 7.7.1 @@ -104,79 +104,82 @@ importers: version: 1.4.6 '@vitejs/plugin-vue': specifier: ^6.0.0 - version: 6.0.3(vite@7.2.7(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(stylus@0.57.0)(yaml@2.8.2))(vue@3.5.25(typescript@5.9.3)) + version: 6.0.4(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(stylus@0.57.0)(yaml@2.8.2))(vue@3.5.28(typescript@5.9.3)) '@vue/compiler-sfc': specifier: ^3.5.18 - version: 3.5.25 + version: 3.5.28 '@vue/test-utils': specifier: ^2.4.6 version: 2.4.6 dotenv: specifier: ^17.2.0 - version: 17.2.3 + version: 17.3.1 eslint: - specifier: ^9.17.0 - version: 9.39.2(jiti@2.6.1) + specifier: ^10.0.0 + version: 10.0.1(jiti@2.6.1) eslint-plugin-promise: specifier: ^7.2.1 - version: 7.2.1(eslint@9.39.2(jiti@2.6.1)) + version: 7.2.1(eslint@10.0.1(jiti@2.6.1)) eslint-plugin-vue-scoped-css: specifier: ^2.9.0 - version: 2.12.0(eslint@9.39.2(jiti@2.6.1))(vue-eslint-parser@10.2.0(eslint@9.39.2(jiti@2.6.1))) + version: 2.12.0(eslint@10.0.1(jiti@2.6.1))(vue-eslint-parser@10.4.0(eslint@10.0.1(jiti@2.6.1))) jsdom: - specifier: ^27.0.0 - version: 27.3.0(postcss@8.5.6) + specifier: ^28.0.0 + version: 28.1.0 prettier: specifier: ^3.6.2 - version: 3.7.4 + version: 3.8.1 prettier-plugin-tailwindcss: specifier: ^0.7.0 - version: 0.7.2(@ianvs/prettier-plugin-sort-imports@4.7.0(@vue/compiler-sfc@3.5.25)(prettier@3.7.4))(prettier@3.7.4) + version: 0.7.2(@ianvs/prettier-plugin-sort-imports@4.7.1(@vue/compiler-sfc@3.5.28)(prettier@3.8.1))(prettier@3.8.1) tinycolor2: specifier: ^1.6.0 version: 1.6.0 ts-node: specifier: ^10.9.2 - version: 10.9.2(@types/node@24.10.4)(typescript@5.9.3) + version: 10.9.2(@types/node@24.10.13)(typescript@5.9.3) typescript: specifier: 5.9.3 version: 5.9.3 vite: specifier: ^7.0.5 - version: 7.2.7(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(stylus@0.57.0)(yaml@2.8.2) + version: 7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(stylus@0.57.0)(yaml@2.8.2) vite-plugin-prismjs: specifier: ^0.0.11 version: 0.0.11(prismjs@1.30.0) vite-svg-loader: specifier: ^5.1.0 - version: 5.1.0(vue@3.5.25(typescript@5.9.3)) + version: 5.1.0(vue@3.5.28(typescript@5.9.3)) vitest: specifier: ^4.0.0 - version: 4.0.15(@types/node@24.10.4)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(stylus@0.57.0)(yaml@2.8.2) + version: 4.0.18(@types/node@24.10.13)(jiti@2.6.1)(jsdom@28.1.0)(lightningcss@1.31.1)(stylus@0.57.0)(yaml@2.8.2) vue-tsc: specifier: ^3.0.3 - version: 3.1.8(typescript@5.9.3) + version: 3.2.5(typescript@5.9.3) packages: - '@acemir/cssom@0.9.29': - resolution: {integrity: sha512-G90x0VW+9nW4dFajtjCoT+NM0scAfH9Mb08IcjgFHYbfiL/lU04dTF9JuVOi3/OH+DJCQdcIseSXkdCB9Ky6JA==} + '@acemir/cssom@0.9.31': + resolution: {integrity: sha512-ZnR3GSaH+/vJ0YlHau21FjfLYjMpYVIzTD8M8vIEQvIGxeOXyXdzCI140rrCY862p/C/BbzWsjc1dgnM9mkoTA==} - '@antfu/eslint-config@6.7.1': - resolution: {integrity: sha512-+8GIMmOfrtAVXoqVK9sfovAlHPkp35ilntqZ6XloO/Rty36gOxaa8dvwCh8/eqwwIsloA/hDJo3Ef95TRbdyEg==} + '@antfu/eslint-config@7.4.3': + resolution: {integrity: sha512-qHOG2408wBz21x191n0Mm9r2q/PqMYul+YE+DUBqZMtJYUn+bd+Dh3g8LIkyItMJR+Xs9f9TKXJehZLRYxJlHg==} hasBin: true peerDependencies: - '@eslint-react/eslint-plugin': ^2.0.1 + '@angular-eslint/eslint-plugin': ^21.1.0 + '@angular-eslint/eslint-plugin-template': ^21.1.0 + '@angular-eslint/template-parser': ^21.1.0 + '@eslint-react/eslint-plugin': ^2.11.0 '@next/eslint-plugin-next': '>=15.0.0' '@prettier/plugin-xml': ^3.4.1 '@unocss/eslint-plugin': '>=0.50.0' astro-eslint-parser: ^1.0.2 - eslint: ^9.10.0 + eslint: ^9.10.0 || ^10.0.0 eslint-plugin-astro: ^1.2.0 eslint-plugin-format: '>=0.1.0' eslint-plugin-jsx-a11y: '>=6.10.2' eslint-plugin-react-hooks: ^7.0.0 - eslint-plugin-react-refresh: ^0.4.19 + eslint-plugin-react-refresh: ^0.5.0 eslint-plugin-solid: ^0.14.3 eslint-plugin-svelte: '>=2.35.1' eslint-plugin-vuejs-accessibility: ^2.4.1 @@ -184,6 +187,12 @@ packages: prettier-plugin-slidev: ^1.0.5 svelte-eslint-parser: '>=0.37.0' peerDependenciesMeta: + '@angular-eslint/eslint-plugin': + optional: true + '@angular-eslint/eslint-plugin-template': + optional: true + '@angular-eslint/template-parser': + optional: true '@eslint-react/eslint-plugin': optional: true '@next/eslint-plugin-next': @@ -220,45 +229,46 @@ packages: '@antfu/install-pkg@1.1.0': resolution: {integrity: sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==} - '@asamuzakjp/css-color@4.1.0': - resolution: {integrity: sha512-9xiBAtLn4aNsa4mDnpovJvBn72tNEIACyvlqaNJ+ADemR+yeMJWnBudOi2qGDviJa7SwcDOU/TRh5dnET7qk0w==} + '@asamuzakjp/css-color@5.0.0': + resolution: {integrity: sha512-SYGMdSLugOBvpa6ciOp9DptcoyluCo0IJln5v47NtadGbSfkhvANzFozKNsuJ0A7ElOuXeIVQcPAd0TMQ1ZCkg==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} - '@asamuzakjp/dom-selector@6.7.6': - resolution: {integrity: sha512-hBaJER6A9MpdG3WgdlOolHmbOYvSk46y7IQN/1+iqiCuUu6iWdQrs9DGKF8ocqsEqWujWf/V7b7vaDgiUmIvUg==} + '@asamuzakjp/dom-selector@6.8.1': + resolution: {integrity: sha512-MvRz1nCqW0fsy8Qz4dnLIvhOlMzqDVBabZx6lH+YywFDdjXhMY37SmpV1XFX3JzG5GWHn63j6HX6QPr3lZXHvQ==} '@asamuzakjp/nwsapi@2.3.9': resolution: {integrity: sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==} - '@babel/code-frame@7.27.1': - resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} + '@babel/code-frame@7.29.0': + resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} engines: {node: '>=6.9.0'} - '@babel/compat-data@7.28.5': - resolution: {integrity: sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==} + '@babel/compat-data@7.29.0': + resolution: {integrity: sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==} engines: {node: '>=6.9.0'} - '@babel/core@7.28.5': - resolution: {integrity: sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==} + '@babel/core@7.29.0': + resolution: {integrity: sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==} engines: {node: '>=6.9.0'} - '@babel/generator@7.28.5': - resolution: {integrity: sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==} + '@babel/generator@7.29.1': + resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==} engines: {node: '>=6.9.0'} - '@babel/helper-compilation-targets@7.27.2': - resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==} + '@babel/helper-compilation-targets@7.28.6': + resolution: {integrity: sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==} engines: {node: '>=6.9.0'} '@babel/helper-globals@7.28.0': resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} engines: {node: '>=6.9.0'} - '@babel/helper-module-imports@7.27.1': - resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==} + '@babel/helper-module-imports@7.28.6': + resolution: {integrity: sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==} engines: {node: '>=6.9.0'} - '@babel/helper-module-transforms@7.28.3': - resolution: {integrity: sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==} + '@babel/helper-module-transforms@7.28.6': + resolution: {integrity: sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 @@ -275,83 +285,84 @@ packages: resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} engines: {node: '>=6.9.0'} - '@babel/helpers@7.28.4': - resolution: {integrity: sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==} + '@babel/helpers@7.28.6': + resolution: {integrity: sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==} engines: {node: '>=6.9.0'} - '@babel/parser@7.28.5': - resolution: {integrity: sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==} + '@babel/parser@7.29.0': + resolution: {integrity: sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==} engines: {node: '>=6.0.0'} hasBin: true - '@babel/runtime@7.28.4': - resolution: {integrity: sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==} + '@babel/runtime@7.28.6': + resolution: {integrity: sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==} engines: {node: '>=6.9.0'} - '@babel/template@7.27.2': - resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} + '@babel/template@7.28.6': + resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} engines: {node: '>=6.9.0'} - '@babel/traverse@7.28.5': - resolution: {integrity: sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==} + '@babel/traverse@7.29.0': + resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==} engines: {node: '>=6.9.0'} - '@babel/types@7.28.5': - resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==} + '@babel/types@7.29.0': + resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} engines: {node: '>=6.9.0'} - '@clack/core@0.5.0': - resolution: {integrity: sha512-p3y0FIOwaYRUPRcMO7+dlmLh8PSRcrjuTndsiA0WAFbWES0mLZlrjVoBRZ9DzkPFJZG6KGkJmoEAY0ZcVWTkow==} + '@bramus/specificity@2.4.2': + resolution: {integrity: sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==} + hasBin: true - '@clack/prompts@0.11.0': - resolution: {integrity: sha512-pMN5FcrEw9hUkZA4f+zLlzivQSeQf5dRGJjSUbvVYDLvpKCdQx5OaknvKzgbtXOizhP+SJJJjqEbOe55uKKfAw==} + '@clack/core@1.0.1': + resolution: {integrity: sha512-WKeyK3NOBwDOzagPR5H08rFk9D/WuN705yEbuZvKqlkmoLM2woKtXb10OO2k1NoSU4SFG947i2/SCYh+2u5e4g==} + + '@clack/prompts@1.0.1': + resolution: {integrity: sha512-/42G73JkuYdyWZ6m8d/CJtBrGl1Hegyc7Fy78m5Ob+jF85TOUmLR5XLce/U3LxYAw0kJ8CT5aI99RIvPHcGp/Q==} '@cspotcode/source-map-support@0.8.1': resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} engines: {node: '>=12'} - '@csstools/color-helpers@5.1.0': - resolution: {integrity: sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==} - engines: {node: '>=18'} + '@csstools/color-helpers@6.0.2': + resolution: {integrity: sha512-LMGQLS9EuADloEFkcTBR3BwV/CGHV7zyDxVRtVDTwdI2Ca4it0CCVTT9wCkxSgokjE5Ho41hEPgb8OEUwoXr6Q==} + engines: {node: '>=20.19.0'} - '@csstools/css-calc@2.1.4': - resolution: {integrity: sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==} - engines: {node: '>=18'} + '@csstools/css-calc@3.1.1': + resolution: {integrity: sha512-HJ26Z/vmsZQqs/o3a6bgKslXGFAungXGbinULZO3eMsOyNJHeBBZfup5FiZInOghgoM4Hwnmw+OgbJCNg1wwUQ==} + engines: {node: '>=20.19.0'} peerDependencies: - '@csstools/css-parser-algorithms': ^3.0.5 - '@csstools/css-tokenizer': ^3.0.4 + '@csstools/css-parser-algorithms': ^4.0.0 + '@csstools/css-tokenizer': ^4.0.0 - '@csstools/css-color-parser@3.1.0': - resolution: {integrity: sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==} - engines: {node: '>=18'} + '@csstools/css-color-parser@4.0.2': + resolution: {integrity: sha512-0GEfbBLmTFf0dJlpsNU7zwxRIH0/BGEMuXLTCvFYxuL1tNhqzTbtnFICyJLTNK4a+RechKP75e7w42ClXSnJQw==} + engines: {node: '>=20.19.0'} peerDependencies: - '@csstools/css-parser-algorithms': ^3.0.5 - '@csstools/css-tokenizer': ^3.0.4 + '@csstools/css-parser-algorithms': ^4.0.0 + '@csstools/css-tokenizer': ^4.0.0 - '@csstools/css-parser-algorithms@3.0.5': - resolution: {integrity: sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==} - engines: {node: '>=18'} + '@csstools/css-parser-algorithms@4.0.0': + resolution: {integrity: sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==} + engines: {node: '>=20.19.0'} peerDependencies: - '@csstools/css-tokenizer': ^3.0.4 + '@csstools/css-tokenizer': ^4.0.0 - '@csstools/css-syntax-patches-for-csstree@1.0.14': - resolution: {integrity: sha512-zSlIxa20WvMojjpCSy8WrNpcZ61RqfTfX3XTaOeVlGJrt/8HF3YbzgFZa01yTbT4GWQLwfTcC3EB8i3XnB647Q==} - engines: {node: '>=18'} - peerDependencies: - postcss: ^8.4 + '@csstools/css-syntax-patches-for-csstree@1.0.28': + resolution: {integrity: sha512-1NRf1CUBjnr3K7hu8BLxjQrKCxEe8FP/xmPTenAxCRZWVLbmGotkFvG9mfNpjA6k7Bw1bw4BilZq9cu19RA5pg==} - '@csstools/css-tokenizer@3.0.4': - resolution: {integrity: sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==} - engines: {node: '>=18'} - - '@es-joy/jsdoccomment@0.76.0': - resolution: {integrity: sha512-g+RihtzFgGTx2WYCuTHbdOXJeAlGnROws0TeALx9ow/ZmOROOZkVg5wp/B44n0WJgI4SQFP1eWM2iRPlU2Y14w==} - engines: {node: '>=20.11.0'} + '@csstools/css-tokenizer@4.0.0': + resolution: {integrity: sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==} + engines: {node: '>=20.19.0'} '@es-joy/jsdoccomment@0.78.0': resolution: {integrity: sha512-rQkU5u8hNAq2NVRzHnIUUvR6arbO0b6AOlvpTNS48CkiKSn/xtNfOzBK23JE4SiW89DgvU7GtxLVgV4Vn2HBAw==} engines: {node: '>=20.11.0'} + '@es-joy/jsdoccomment@0.84.0': + resolution: {integrity: sha512-0xew1CxOam0gV5OMjh2KjFQZsKL2bByX1+q4j3E73MpYIdyUxcZb/xQct9ccUb+ve5KGUYbCUxyPnYB7RbuP+w==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + '@es-joy/resolve.exports@1.2.0': resolution: {integrity: sha512-Q9hjxWI5xBM+qW2enxfe8wDKdFWMfd0Z29k5ZJnuBqD/CasY5Zryj09aCA6owbGATWz+39p5uIdaHXpopOcG8g==} engines: {node: '>=10'} @@ -362,164 +373,320 @@ packages: cpu: [ppc64] os: [aix] + '@esbuild/aix-ppc64@0.27.3': + resolution: {integrity: sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + '@esbuild/android-arm64@0.25.12': resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} engines: {node: '>=18'} cpu: [arm64] os: [android] + '@esbuild/android-arm64@0.27.3': + resolution: {integrity: sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + '@esbuild/android-arm@0.25.12': resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} engines: {node: '>=18'} cpu: [arm] os: [android] + '@esbuild/android-arm@0.27.3': + resolution: {integrity: sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + '@esbuild/android-x64@0.25.12': resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} engines: {node: '>=18'} cpu: [x64] os: [android] + '@esbuild/android-x64@0.27.3': + resolution: {integrity: sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + '@esbuild/darwin-arm64@0.25.12': resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] + '@esbuild/darwin-arm64@0.27.3': + resolution: {integrity: sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + '@esbuild/darwin-x64@0.25.12': resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} engines: {node: '>=18'} cpu: [x64] os: [darwin] + '@esbuild/darwin-x64@0.27.3': + resolution: {integrity: sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + '@esbuild/freebsd-arm64@0.25.12': resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] + '@esbuild/freebsd-arm64@0.27.3': + resolution: {integrity: sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + '@esbuild/freebsd-x64@0.25.12': resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] + '@esbuild/freebsd-x64@0.27.3': + resolution: {integrity: sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + '@esbuild/linux-arm64@0.25.12': resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} engines: {node: '>=18'} cpu: [arm64] os: [linux] + '@esbuild/linux-arm64@0.27.3': + resolution: {integrity: sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + '@esbuild/linux-arm@0.25.12': resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} engines: {node: '>=18'} cpu: [arm] os: [linux] + '@esbuild/linux-arm@0.27.3': + resolution: {integrity: sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + '@esbuild/linux-ia32@0.25.12': resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} engines: {node: '>=18'} cpu: [ia32] os: [linux] + '@esbuild/linux-ia32@0.27.3': + resolution: {integrity: sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + '@esbuild/linux-loong64@0.25.12': resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} engines: {node: '>=18'} cpu: [loong64] os: [linux] + '@esbuild/linux-loong64@0.27.3': + resolution: {integrity: sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + '@esbuild/linux-mips64el@0.25.12': resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] + '@esbuild/linux-mips64el@0.27.3': + resolution: {integrity: sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + '@esbuild/linux-ppc64@0.25.12': resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] + '@esbuild/linux-ppc64@0.27.3': + resolution: {integrity: sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + '@esbuild/linux-riscv64@0.25.12': resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] + '@esbuild/linux-riscv64@0.27.3': + resolution: {integrity: sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + '@esbuild/linux-s390x@0.25.12': resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} engines: {node: '>=18'} cpu: [s390x] os: [linux] + '@esbuild/linux-s390x@0.27.3': + resolution: {integrity: sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + '@esbuild/linux-x64@0.25.12': resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} engines: {node: '>=18'} cpu: [x64] os: [linux] + '@esbuild/linux-x64@0.27.3': + resolution: {integrity: sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + '@esbuild/netbsd-arm64@0.25.12': resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] + '@esbuild/netbsd-arm64@0.27.3': + resolution: {integrity: sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + '@esbuild/netbsd-x64@0.25.12': resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] + '@esbuild/netbsd-x64@0.27.3': + resolution: {integrity: sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + '@esbuild/openbsd-arm64@0.25.12': resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] + '@esbuild/openbsd-arm64@0.27.3': + resolution: {integrity: sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + '@esbuild/openbsd-x64@0.25.12': resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] + '@esbuild/openbsd-x64@0.27.3': + resolution: {integrity: sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + '@esbuild/openharmony-arm64@0.25.12': resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] + '@esbuild/openharmony-arm64@0.27.3': + resolution: {integrity: sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + '@esbuild/sunos-x64@0.25.12': resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} engines: {node: '>=18'} cpu: [x64] os: [sunos] + '@esbuild/sunos-x64@0.27.3': + resolution: {integrity: sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + '@esbuild/win32-arm64@0.25.12': resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} engines: {node: '>=18'} cpu: [arm64] os: [win32] + '@esbuild/win32-arm64@0.27.3': + resolution: {integrity: sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + '@esbuild/win32-ia32@0.25.12': resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} engines: {node: '>=18'} cpu: [ia32] os: [win32] + '@esbuild/win32-ia32@0.27.3': + resolution: {integrity: sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + '@esbuild/win32-x64@0.25.12': resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} engines: {node: '>=18'} cpu: [x64] os: [win32] - '@eslint-community/eslint-plugin-eslint-comments@4.5.0': - resolution: {integrity: sha512-MAhuTKlr4y/CE3WYX26raZjy+I/kS2PLKSzvfmDCGrBLTFHOYwqROZdr4XwPgXwX3K9rjzMr4pSmUWGnzsUyMg==} + '@esbuild/win32-x64@0.27.3': + resolution: {integrity: sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@eslint-community/eslint-plugin-eslint-comments@4.6.0': + resolution: {integrity: sha512-2EX2bBQq1ez++xz2o9tEeEQkyvfieWgUFMH4rtJJri2q0Azvhja3hZGXsjPXs31R4fQkZDtWzNDDK2zQn5UE5g==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 - '@eslint-community/eslint-utils@4.9.0': - resolution: {integrity: sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==} + '@eslint-community/eslint-utils@4.9.1': + resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 @@ -528,47 +695,69 @@ packages: resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - '@eslint/compat@1.4.1': - resolution: {integrity: sha512-cfO82V9zxxGBxcQDr1lfaYB7wykTa0b00mGa36FrJl7iTFd0Z2cHfEYuxcBRP/iNijCsWsEkA+jzT8hGYmv33w==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/compat@2.0.2': + resolution: {integrity: sha512-pR1DoD0h3HfF675QZx0xsyrsU8q70Z/plx7880NOhS02NuWLgBCOMDL787nUeQ7EWLkxv3bPQJaarjcPQb2Dwg==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} peerDependencies: - eslint: ^8.40 || 9 + eslint: ^8.40 || 9 || 10 peerDependenciesMeta: eslint: optional: true - '@eslint/config-array@0.21.1': - resolution: {integrity: sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/config-array@0.23.2': + resolution: {integrity: sha512-YF+fE6LV4v5MGWRGj7G404/OZzGNepVF8fxk7jqmqo3lrza7a0uUcDnROGRBG1WFC1omYUS/Wp1f42i0M+3Q3A==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} - '@eslint/config-helpers@0.4.2': - resolution: {integrity: sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/config-helpers@0.5.2': + resolution: {integrity: sha512-a5MxrdDXEvqnIq+LisyCX6tQMPF/dSJpCfBgBauY+pNZ28yCtSsTvyTYrMhaI+LK26bVyCJfJkT0u8KIj2i1dQ==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} '@eslint/core@0.17.0': resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/core@1.1.0': + resolution: {integrity: sha512-/nr9K9wkr3P1EzFTdFdMoLuo1PmIxjmwvPozwoSodjNBdefGujXQUF93u1DDZpEaTuDvMsIQddsd35BwtrW9Xw==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + '@eslint/eslintrc@3.3.3': resolution: {integrity: sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/js@9.39.2': - resolution: {integrity: sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/js@10.0.1': + resolution: {integrity: sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + peerDependencies: + eslint: ^10.0.0 + peerDependenciesMeta: + eslint: + optional: true '@eslint/markdown@7.5.1': resolution: {integrity: sha512-R8uZemG9dKTbru/DQRPblbJyXpObwKzo8rv1KYGGuPUPtjM4LXBYM9q5CIZAComzZupws3tWbDwam5AFpPLyJQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/object-schema@2.1.7': - resolution: {integrity: sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/object-schema@3.0.2': + resolution: {integrity: sha512-HOy56KJt48Bx8KmJ+XGQNSUMT/6dZee/M54XyUyuvTvPXJmsERRvBchsUVx1UMe1WwIH49XLAczNC7V2INsuUw==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} '@eslint/plugin-kit@0.4.1': resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/plugin-kit@0.6.0': + resolution: {integrity: sha512-bIZEUzOI1jkhviX2cp5vNyXQc6olzb2ohewQubuYlMXZ2Q/XjBO0x0XhGPvc9fjSIiUN0vw+0hq53BJ4eQSJKQ==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + '@exodus/bytes@1.14.1': + resolution: {integrity: sha512-OhkBFWI6GcRMUroChZiopRiSp2iAMvEBK47NhJooDqz1RERO4QuZIZnjP63TXX8GAiLABkYmX+fuQsdJ1dd2QQ==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + peerDependencies: + '@noble/hashes': ^1.8.0 || ^2.0.0 + peerDependenciesMeta: + '@noble/hashes': + optional: true + '@humanfs/core@0.19.1': resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} engines: {node: '>=18.18.0'} @@ -585,10 +774,10 @@ packages: resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} engines: {node: '>=18.18'} - '@ianvs/prettier-plugin-sort-imports@4.7.0': - resolution: {integrity: sha512-soa2bPUJAFruLL4z/CnMfSEKGznm5ebz29fIa9PxYtu8HHyLKNE1NXAs6dylfw1jn/ilEIfO2oLLN6uAafb7DA==} + '@ianvs/prettier-plugin-sort-imports@4.7.1': + resolution: {integrity: sha512-jmTNYGlg95tlsoG3JLCcuC4BrFELJtLirLAkQW/71lXSyOhVt/Xj7xWbbGcuVbNq1gwWgSyMrPjJc9Z30hynVw==} peerDependencies: - '@prettier/plugin-oxc': ^0.0.4 + '@prettier/plugin-oxc': ^0.0.4 || ^0.1.0 '@vue/compiler-sfc': 2.7.x || 3.x content-tag: ^4.0.0 prettier: 2 || 3 || ^4.0.0-0 @@ -603,8 +792,8 @@ packages: prettier-plugin-ember-template-tag: optional: true - '@intlify/bundle-utils@11.0.3': - resolution: {integrity: sha512-dURCDz1rQXwAb1+Hv4NDit6aZSRaAt4zUYBPEeaDCe3FSs8dMtdF6kEvgd9JwsYFSTAHcvbTs2CqwBjjt9Ltsw==} + '@intlify/bundle-utils@11.0.7': + resolution: {integrity: sha512-fEO3CJGPymxieGh8BHox7d6stgajDQae7wgpH6YYw7WX+cdW6jTTXyljZqz7OV3JcwlS9M9UHSoO+YwiO56IhA==} engines: {node: '>= 20'} peerDependencies: petite-vue-i18n: '*' @@ -615,12 +804,12 @@ packages: vue-i18n: optional: true - '@intlify/core-base@11.2.2': - resolution: {integrity: sha512-0mCTBOLKIqFUP3BzwuFW23hYEl9g/wby6uY//AC5hTgQfTsM2srCYF2/hYGp+a5DZ/HIFIgKkLJMzXTt30r0JQ==} + '@intlify/core-base@11.2.8': + resolution: {integrity: sha512-nBq6Y1tVkjIUsLsdOjDSJj4AsjvD0UG3zsg9Fyc+OivwlA/oMHSKooUy9tpKj0HqZ+NWFifweHavdljlBLTwdA==} engines: {node: '>= 16'} - '@intlify/eslint-plugin-vue-i18n@4.1.0': - resolution: {integrity: sha512-MPAr3LGTrkB5CZBHN5eUf4kASUEiSaDM371jADmxNbTL1Ew7IAyCIBGm3+/1sWcvsfVHe4wz8RFoo6FpeQZ4Nw==} + '@intlify/eslint-plugin-vue-i18n@4.1.1': + resolution: {integrity: sha512-TgeLqdNEwt9wDOxXwJ7lSxw4f2saXd0QfZ4ZM3oCU4m1H1r1tBbuV6nRuhtsy4DwGqC0nlFFhsvKONlEyUxZkg==} engines: {node: '>=18.0.0'} peerDependencies: eslint: ^8.0.0 || ^9.0.0-0 @@ -628,16 +817,16 @@ packages: vue-eslint-parser: ^10.0.0 yaml-eslint-parser: ^1.2.2 - '@intlify/message-compiler@11.2.2': - resolution: {integrity: sha512-XS2p8Ff5JxWsKhgfld4/MRQzZRQ85drMMPhb7Co6Be4ZOgqJX1DzcZt0IFgGTycgqL8rkYNwgnD443Q+TapOoA==} + '@intlify/message-compiler@11.2.8': + resolution: {integrity: sha512-A5n33doOjmHsBtCN421386cG1tWp5rpOjOYPNsnpjIJbQ4POF0QY2ezhZR9kr0boKwaHjbOifvyQvHj2UTrDFQ==} engines: {node: '>= 16'} - '@intlify/shared@11.2.2': - resolution: {integrity: sha512-OtCmyFpSXxNu/oET/aN6HtPCbZ01btXVd0f3w00YsHOb13Kverk1jzA2k47pAekM55qbUw421fvPF1yxZ+gicw==} + '@intlify/shared@11.2.8': + resolution: {integrity: sha512-l6e4NZyUgv8VyXXH4DbuucFOBmxLF56C/mqh2tvApbzl2Hrhi1aTDcuv5TKdxzfHYmpO3UB0Cz04fgDT9vszfw==} engines: {node: '>= 16'} - '@intlify/unplugin-vue-i18n@11.0.3': - resolution: {integrity: sha512-iQuik0nXfdVZ5ab+IEyBFEuvMQ213zfbUpBXaEdHPk8DV+qB2CT/SdFuDhfUDRRBZc/e0qoLlfmc9urhnRYVWw==} + '@intlify/unplugin-vue-i18n@11.0.7': + resolution: {integrity: sha512-wswKprS1D8VfnxxVhKxug5wa3MbDSOcCoXOBjnzhMK+6NfP6h6UI8pFqSBIvcW8nPDuzweTc0Sk3PeBCcubfoQ==} engines: {node: '>= 20'} peerDependencies: petite-vue-i18n: '*' @@ -713,6 +902,10 @@ packages: '@one-ini/wasm@0.1.1': resolution: {integrity: sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==} + '@ota-meshi/ast-token-store@0.3.0': + resolution: {integrity: sha512-XRO0zi2NIUKq2lUk3T1ecFSld1fMWRKE6naRFGkgkdeosx7IslyUKNv5Dcb5PJTja9tHJoFu0v/7yEpAkrkrTg==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + '@pkgjs/parseargs@0.11.0': resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} @@ -721,8 +914,8 @@ packages: resolution: {integrity: sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} - '@rolldown/pluginutils@1.0.0-beta.53': - resolution: {integrity: sha512-vENRlFU4YbrwVqNDZ7fLvy+JR1CRkyr01jhSiDpE1u6py3OMzQfztQU2jxykW3ALNxO4kSlqIDeYyD0Y9RcQeQ==} + '@rolldown/pluginutils@1.0.0-rc.2': + resolution: {integrity: sha512-izyXV/v+cHiRfozX62W9htOAvwMo4/bXKDrQ+vom1L1qRuexPock/7VZDAhnpHCLNejd3NJ6hiab+tO0D44Rgw==} '@rollup/pluginutils@5.3.0': resolution: {integrity: sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==} @@ -733,113 +926,141 @@ packages: rollup: optional: true - '@rollup/rollup-android-arm-eabi@4.53.3': - resolution: {integrity: sha512-mRSi+4cBjrRLoaal2PnqH82Wqyb+d3HsPUN/W+WslCXsZsyHa9ZeQQX/pQsZaVIWDkPcpV6jJ+3KLbTbgnwv8w==} + '@rollup/rollup-android-arm-eabi@4.59.0': + resolution: {integrity: sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.53.3': - resolution: {integrity: sha512-CbDGaMpdE9sh7sCmTrTUyllhrg65t6SwhjlMJsLr+J8YjFuPmCEjbBSx4Z/e4SmDyH3aB5hGaJUP2ltV/vcs4w==} + '@rollup/rollup-android-arm64@4.59.0': + resolution: {integrity: sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.53.3': - resolution: {integrity: sha512-Nr7SlQeqIBpOV6BHHGZgYBuSdanCXuw09hon14MGOLGmXAFYjx1wNvquVPmpZnl0tLjg25dEdr4IQ6GgyToCUA==} + '@rollup/rollup-darwin-arm64@4.59.0': + resolution: {integrity: sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.53.3': - resolution: {integrity: sha512-DZ8N4CSNfl965CmPktJ8oBnfYr3F8dTTNBQkRlffnUarJ2ohudQD17sZBa097J8xhQ26AwhHJ5mvUyQW8ddTsQ==} + '@rollup/rollup-darwin-x64@4.59.0': + resolution: {integrity: sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.53.3': - resolution: {integrity: sha512-yMTrCrK92aGyi7GuDNtGn2sNW+Gdb4vErx4t3Gv/Tr+1zRb8ax4z8GWVRfr3Jw8zJWvpGHNpss3vVlbF58DZ4w==} + '@rollup/rollup-freebsd-arm64@4.59.0': + resolution: {integrity: sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.53.3': - resolution: {integrity: sha512-lMfF8X7QhdQzseM6XaX0vbno2m3hlyZFhwcndRMw8fbAGUGL3WFMBdK0hbUBIUYcEcMhVLr1SIamDeuLBnXS+Q==} + '@rollup/rollup-freebsd-x64@4.59.0': + resolution: {integrity: sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.53.3': - resolution: {integrity: sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw==} + '@rollup/rollup-linux-arm-gnueabihf@4.59.0': + resolution: {integrity: sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==} cpu: [arm] os: [linux] + libc: [glibc] - '@rollup/rollup-linux-arm-musleabihf@4.53.3': - resolution: {integrity: sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg==} + '@rollup/rollup-linux-arm-musleabihf@4.59.0': + resolution: {integrity: sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==} cpu: [arm] os: [linux] + libc: [musl] - '@rollup/rollup-linux-arm64-gnu@4.53.3': - resolution: {integrity: sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w==} + '@rollup/rollup-linux-arm64-gnu@4.59.0': + resolution: {integrity: sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==} cpu: [arm64] os: [linux] + libc: [glibc] - '@rollup/rollup-linux-arm64-musl@4.53.3': - resolution: {integrity: sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A==} + '@rollup/rollup-linux-arm64-musl@4.59.0': + resolution: {integrity: sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==} cpu: [arm64] os: [linux] + libc: [musl] - '@rollup/rollup-linux-loong64-gnu@4.53.3': - resolution: {integrity: sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g==} + '@rollup/rollup-linux-loong64-gnu@4.59.0': + resolution: {integrity: sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==} cpu: [loong64] os: [linux] + libc: [glibc] - '@rollup/rollup-linux-ppc64-gnu@4.53.3': - resolution: {integrity: sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw==} + '@rollup/rollup-linux-loong64-musl@4.59.0': + resolution: {integrity: sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==} + cpu: [loong64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-ppc64-gnu@4.59.0': + resolution: {integrity: sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==} cpu: [ppc64] os: [linux] + libc: [glibc] - '@rollup/rollup-linux-riscv64-gnu@4.53.3': - resolution: {integrity: sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g==} + '@rollup/rollup-linux-ppc64-musl@4.59.0': + resolution: {integrity: sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==} + cpu: [ppc64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-riscv64-gnu@4.59.0': + resolution: {integrity: sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==} cpu: [riscv64] os: [linux] + libc: [glibc] - '@rollup/rollup-linux-riscv64-musl@4.53.3': - resolution: {integrity: sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A==} + '@rollup/rollup-linux-riscv64-musl@4.59.0': + resolution: {integrity: sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==} cpu: [riscv64] os: [linux] + libc: [musl] - '@rollup/rollup-linux-s390x-gnu@4.53.3': - resolution: {integrity: sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg==} + '@rollup/rollup-linux-s390x-gnu@4.59.0': + resolution: {integrity: sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==} cpu: [s390x] os: [linux] + libc: [glibc] - '@rollup/rollup-linux-x64-gnu@4.53.3': - resolution: {integrity: sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w==} + '@rollup/rollup-linux-x64-gnu@4.59.0': + resolution: {integrity: sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==} cpu: [x64] os: [linux] + libc: [glibc] - '@rollup/rollup-linux-x64-musl@4.53.3': - resolution: {integrity: sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q==} + '@rollup/rollup-linux-x64-musl@4.59.0': + resolution: {integrity: sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==} cpu: [x64] os: [linux] + libc: [musl] - '@rollup/rollup-openharmony-arm64@4.53.3': - resolution: {integrity: sha512-OueLAWgrNSPGAdUdIjSWXw+u/02BRTcnfw9PN41D2vq/JSEPnJnVuBgw18VkN8wcd4fjUs+jFHVM4t9+kBSNLw==} + '@rollup/rollup-openbsd-x64@4.59.0': + resolution: {integrity: sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==} + cpu: [x64] + os: [openbsd] + + '@rollup/rollup-openharmony-arm64@4.59.0': + resolution: {integrity: sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==} cpu: [arm64] os: [openharmony] - '@rollup/rollup-win32-arm64-msvc@4.53.3': - resolution: {integrity: sha512-GOFuKpsxR/whszbF/bzydebLiXIHSgsEUp6M0JI8dWvi+fFa1TD6YQa4aSZHtpmh2/uAlj/Dy+nmby3TJ3pkTw==} + '@rollup/rollup-win32-arm64-msvc@4.59.0': + resolution: {integrity: sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.53.3': - resolution: {integrity: sha512-iah+THLcBJdpfZ1TstDFbKNznlzoxa8fmnFYK4V67HvmuNYkVdAywJSoteUszvBQ9/HqN2+9AZghbajMsFT+oA==} + '@rollup/rollup-win32-ia32-msvc@4.59.0': + resolution: {integrity: sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-gnu@4.53.3': - resolution: {integrity: sha512-J9QDiOIZlZLdcot5NXEepDkstocktoVjkaKUtqzgzpt2yWjGlbYiKyp05rWwk4nypbYUNoFAztEgixoLaSETkg==} + '@rollup/rollup-win32-x64-gnu@4.59.0': + resolution: {integrity: sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==} cpu: [x64] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.53.3': - resolution: {integrity: sha512-UhTd8u31dXadv0MopwGgNOBpUVROFKWVQgAg5N1ESyCz8AuBcMqm4AuTjrwgQKGDfoFuz02EuMRHQIw/frmYKQ==} + '@rollup/rollup-win32-x64-msvc@4.59.0': + resolution: {integrity: sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==} cpu: [x64] os: [win32] @@ -851,74 +1072,78 @@ packages: resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==} engines: {node: '>=10'} - '@standard-schema/spec@1.0.0': - resolution: {integrity: sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==} + '@standard-schema/spec@1.1.0': + resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} - '@stylistic/eslint-plugin@5.6.1': - resolution: {integrity: sha512-JCs+MqoXfXrRPGbGmho/zGS/jMcn3ieKl/A8YImqib76C8kjgZwq5uUFzc30lJkMvcchuRn6/v8IApLxli3Jyw==} + '@stylistic/eslint-plugin@5.9.0': + resolution: {integrity: sha512-FqqSkvDMYJReydrMhlugc71M76yLLQWNfmGq+SIlLa7N3kHp8Qq8i2PyWrVNAfjOyOIY+xv9XaaYwvVW7vroMA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - eslint: '>=9.0.0' + eslint: ^9.0.0 || ^10.0.0 - '@tailwindcss/node@4.1.18': - resolution: {integrity: sha512-DoR7U1P7iYhw16qJ49fgXUlry1t4CpXeErJHnQ44JgTSKMaZUdf17cfn5mHchfJ4KRBZRFA/Coo+MUF5+gOaCQ==} + '@tailwindcss/node@4.2.0': + resolution: {integrity: sha512-Yv+fn/o2OmL5fh/Ir62VXItdShnUxfpkMA4Y7jdeC8O81WPB8Kf6TT6GSHvnqgSwDzlB5iT7kDpeXxLsUS0T6Q==} - '@tailwindcss/oxide-android-arm64@4.1.18': - resolution: {integrity: sha512-dJHz7+Ugr9U/diKJA0W6N/6/cjI+ZTAoxPf9Iz9BFRF2GzEX8IvXxFIi/dZBloVJX/MZGvRuFA9rqwdiIEZQ0Q==} - engines: {node: '>= 10'} + '@tailwindcss/oxide-android-arm64@4.2.0': + resolution: {integrity: sha512-F0QkHAVaW/JNBWl4CEKWdZ9PMb0khw5DCELAOnu+RtjAfx5Zgw+gqCHFvqg3AirU1IAd181fwOtJQ5I8Yx5wtw==} + engines: {node: '>= 20'} cpu: [arm64] os: [android] - '@tailwindcss/oxide-darwin-arm64@4.1.18': - resolution: {integrity: sha512-Gc2q4Qhs660bhjyBSKgq6BYvwDz4G+BuyJ5H1xfhmDR3D8HnHCmT/BSkvSL0vQLy/nkMLY20PQ2OoYMO15Jd0A==} - engines: {node: '>= 10'} + '@tailwindcss/oxide-darwin-arm64@4.2.0': + resolution: {integrity: sha512-I0QylkXsBsJMZ4nkUNSR04p6+UptjcwhcVo3Zu828ikiEqHjVmQL9RuQ6uT/cVIiKpvtVA25msu/eRV97JeNSA==} + engines: {node: '>= 20'} cpu: [arm64] os: [darwin] - '@tailwindcss/oxide-darwin-x64@4.1.18': - resolution: {integrity: sha512-FL5oxr2xQsFrc3X9o1fjHKBYBMD1QZNyc1Xzw/h5Qu4XnEBi3dZn96HcHm41c/euGV+GRiXFfh2hUCyKi/e+yw==} - engines: {node: '>= 10'} + '@tailwindcss/oxide-darwin-x64@4.2.0': + resolution: {integrity: sha512-6TmQIn4p09PBrmnkvbYQ0wbZhLtbaksCDx7Y7R3FYYx0yxNA7xg5KP7dowmQ3d2JVdabIHvs3Hx4K3d5uCf8xg==} + engines: {node: '>= 20'} cpu: [x64] os: [darwin] - '@tailwindcss/oxide-freebsd-x64@4.1.18': - resolution: {integrity: sha512-Fj+RHgu5bDodmV1dM9yAxlfJwkkWvLiRjbhuO2LEtwtlYlBgiAT4x/j5wQr1tC3SANAgD+0YcmWVrj8R9trVMA==} - engines: {node: '>= 10'} + '@tailwindcss/oxide-freebsd-x64@4.2.0': + resolution: {integrity: sha512-qBudxDvAa2QwGlq9y7VIzhTvp2mLJ6nD/G8/tI70DCDoneaUeLWBJaPcbfzqRIWraj+o969aDQKvKW9dvkUizw==} + engines: {node: '>= 20'} cpu: [x64] os: [freebsd] - '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.18': - resolution: {integrity: sha512-Fp+Wzk/Ws4dZn+LV2Nqx3IilnhH51YZoRaYHQsVq3RQvEl+71VGKFpkfHrLM/Li+kt5c0DJe/bHXK1eHgDmdiA==} - engines: {node: '>= 10'} + '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.0': + resolution: {integrity: sha512-7XKkitpy5NIjFZNUQPeUyNJNJn1CJeV7rmMR+exHfTuOsg8rxIO9eNV5TSEnqRcaOK77zQpsyUkBWmPy8FgdSg==} + engines: {node: '>= 20'} cpu: [arm] os: [linux] - '@tailwindcss/oxide-linux-arm64-gnu@4.1.18': - resolution: {integrity: sha512-S0n3jboLysNbh55Vrt7pk9wgpyTTPD0fdQeh7wQfMqLPM/Hrxi+dVsLsPrycQjGKEQk85Kgbx+6+QnYNiHalnw==} - engines: {node: '>= 10'} + '@tailwindcss/oxide-linux-arm64-gnu@4.2.0': + resolution: {integrity: sha512-Mff5a5Q3WoQR01pGU1gr29hHM1N93xYrKkGXfPw/aRtK4bOc331Ho4Tgfsm5WDGvpevqMpdlkCojT3qlCQbCpA==} + engines: {node: '>= 20'} cpu: [arm64] os: [linux] + libc: [glibc] - '@tailwindcss/oxide-linux-arm64-musl@4.1.18': - resolution: {integrity: sha512-1px92582HkPQlaaCkdRcio71p8bc8i/ap5807tPRDK/uw953cauQBT8c5tVGkOwrHMfc2Yh6UuxaH4vtTjGvHg==} - engines: {node: '>= 10'} + '@tailwindcss/oxide-linux-arm64-musl@4.2.0': + resolution: {integrity: sha512-XKcSStleEVnbH6W/9DHzZv1YhjE4eSS6zOu2eRtYAIh7aV4o3vIBs+t/B15xlqoxt6ef/0uiqJVB6hkHjWD/0A==} + engines: {node: '>= 20'} cpu: [arm64] os: [linux] + libc: [musl] - '@tailwindcss/oxide-linux-x64-gnu@4.1.18': - resolution: {integrity: sha512-v3gyT0ivkfBLoZGF9LyHmts0Isc8jHZyVcbzio6Wpzifg/+5ZJpDiRiUhDLkcr7f/r38SWNe7ucxmGW3j3Kb/g==} - engines: {node: '>= 10'} + '@tailwindcss/oxide-linux-x64-gnu@4.2.0': + resolution: {integrity: sha512-/hlXCBqn9K6fi7eAM0RsobHwJYa5V/xzWspVTzxnX+Ft9v6n+30Pz8+RxCn7sQL/vRHHLS30iQPrHQunu6/vJA==} + engines: {node: '>= 20'} cpu: [x64] os: [linux] + libc: [glibc] - '@tailwindcss/oxide-linux-x64-musl@4.1.18': - resolution: {integrity: sha512-bhJ2y2OQNlcRwwgOAGMY0xTFStt4/wyU6pvI6LSuZpRgKQwxTec0/3Scu91O8ir7qCR3AuepQKLU/kX99FouqQ==} - engines: {node: '>= 10'} + '@tailwindcss/oxide-linux-x64-musl@4.2.0': + resolution: {integrity: sha512-lKUaygq4G7sWkhQbfdRRBkaq4LY39IriqBQ+Gk6l5nKq6Ay2M2ZZb1tlIyRNgZKS8cbErTwuYSor0IIULC0SHw==} + engines: {node: '>= 20'} cpu: [x64] os: [linux] + libc: [musl] - '@tailwindcss/oxide-wasm32-wasi@4.1.18': - resolution: {integrity: sha512-LffYTvPjODiP6PT16oNeUQJzNVyJl1cjIebq/rWWBF+3eDst5JGEFSc5cWxyRCJ0Mxl+KyIkqRxk1XPEs9x8TA==} + '@tailwindcss/oxide-wasm32-wasi@4.2.0': + resolution: {integrity: sha512-xuDjhAsFdUuFP5W9Ze4k/o4AskUtI8bcAGU4puTYprr89QaYFmhYOPfP+d1pH+k9ets6RoE23BXZM1X1jJqoyw==} engines: {node: '>=14.0.0'} cpu: [wasm32] bundledDependencies: @@ -929,29 +1154,29 @@ packages: - '@emnapi/wasi-threads' - tslib - '@tailwindcss/oxide-win32-arm64-msvc@4.1.18': - resolution: {integrity: sha512-HjSA7mr9HmC8fu6bdsZvZ+dhjyGCLdotjVOgLA2vEqxEBZaQo9YTX4kwgEvPCpRh8o4uWc4J/wEoFzhEmjvPbA==} - engines: {node: '>= 10'} + '@tailwindcss/oxide-win32-arm64-msvc@4.2.0': + resolution: {integrity: sha512-2UU/15y1sWDEDNJXxEIrfWKC2Yb4YgIW5Xz2fKFqGzFWfoMHWFlfa1EJlGO2Xzjkq/tvSarh9ZTjvbxqWvLLXA==} + engines: {node: '>= 20'} cpu: [arm64] os: [win32] - '@tailwindcss/oxide-win32-x64-msvc@4.1.18': - resolution: {integrity: sha512-bJWbyYpUlqamC8dpR7pfjA0I7vdF6t5VpUGMWRkXVE3AXgIZjYUYAK7II1GNaxR8J1SSrSrppRar8G++JekE3Q==} - engines: {node: '>= 10'} + '@tailwindcss/oxide-win32-x64-msvc@4.2.0': + resolution: {integrity: sha512-CrFadmFoc+z76EV6LPG1jx6XceDsaCG3lFhyLNo/bV9ByPrE+FnBPckXQVP4XRkN76h3Fjt/a+5Er/oA/nCBvQ==} + engines: {node: '>= 20'} cpu: [x64] os: [win32] - '@tailwindcss/oxide@4.1.18': - resolution: {integrity: sha512-EgCR5tTS5bUSKQgzeMClT6iCY3ToqE1y+ZB0AKldj809QXk1Y+3jB0upOYZrn9aGIzPtUsP7sX4QQ4XtjBB95A==} - engines: {node: '>= 10'} + '@tailwindcss/oxide@4.2.0': + resolution: {integrity: sha512-AZqQzADaj742oqn2xjl5JbIOzZB/DGCYF/7bpvhA8KvjUj9HJkag6bBuwZvH1ps6dfgxNHyuJVlzSr2VpMgdTQ==} + engines: {node: '>= 20'} '@tailwindcss/typography@0.5.19': resolution: {integrity: sha512-w31dd8HOx3k9vPtcQh5QHP9GwKcgbMp87j58qi6xgiBnFFtKEAgCWnDw4qUT8aHwkCp8bKvb/KGKWWHedP0AAg==} peerDependencies: tailwindcss: '>=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1' - '@tailwindcss/vite@4.1.18': - resolution: {integrity: sha512-jVA+/UpKL1vRLg6Hkao5jldawNmRo7mQYrZtNHMIVpLfLhDml5nMRUo/8MwoX2vNXvnaXNNMedrMfMugAVX1nA==} + '@tailwindcss/vite@4.2.0': + resolution: {integrity: sha512-da9mFCaHpoOgtQiWtDGIikTrSpUFBtIZCG3jy/u2BGV+l/X1/pbxzmIUxNt6JWm19N3WtGi4KlJdSH/Si83WOA==} peerDependencies: vite: ^5.2.0 || ^6 || ^7 @@ -980,14 +1205,17 @@ packages: '@types/deep-eql@4.0.2': resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} + '@types/esrecurse@4.3.1': + resolution: {integrity: sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==} + '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} - '@types/lodash@4.17.21': - resolution: {integrity: sha512-FOvQ0YPD5NOfPgMzJihoT+Za5pdkDJWcbpuj1DjaKZIr/gxodQjY/uWEFlTNqW2ugXHUiL8lRQgw63dzKHZdeQ==} + '@types/lodash@4.17.23': + resolution: {integrity: sha512-RDvF6wTulMPjrNdCoYRC8gNR880JNGT8uB+REUpC2Ns4pRqQJhGz90wh7rgdXDPpCczF3VGktDuFGVnz8zP7HA==} '@types/mdast@4.0.4': resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} @@ -995,11 +1223,11 @@ packages: '@types/ms@2.1.0': resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} - '@types/node@24.10.4': - resolution: {integrity: sha512-vnDVpYPMzs4wunl27jHrfmwojOGKya0xyM3sH+UE5iv5uPS6vX7UIoh6m+vQc5LGBq52HBKPIn/zcSZVzeDEZg==} + '@types/node@24.10.13': + resolution: {integrity: sha512-oH72nZRfDv9lADUBSo104Aq7gPHpQZc4BTx38r9xf9pg5LfP6EzSyH2n7qFmmxRQXh7YlUXODcYsg6PuTDSxGg==} - '@types/prismjs@1.26.5': - resolution: {integrity: sha512-AUZTa7hQ2KY5L7AmtSiqxlhWxb4ina0yd8hNbl4TWuqnv/pFP0nDMb3YrfSBf4hJVGLh2YEIBfKaBW/9UEl6IQ==} + '@types/prismjs@1.26.6': + resolution: {integrity: sha512-vqlvI7qlMvcCBbVe0AKAb4f97//Hy0EBTaiW8AalRnG/xAN5zOiWWyrNqNXeq8+KAuvRewjCVY1+IPxk4RdNYw==} '@types/semver@7.7.1': resolution: {integrity: sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA==} @@ -1016,74 +1244,74 @@ packages: '@types/web-bluetooth@0.0.21': resolution: {integrity: sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==} - '@typescript-eslint/eslint-plugin@8.49.0': - resolution: {integrity: sha512-JXij0vzIaTtCwu6SxTh8qBc66kmf1xs7pI4UOiMDFVct6q86G0Zs7KRcEoJgY3Cav3x5Tq0MF5jwgpgLqgKG3A==} + '@typescript-eslint/eslint-plugin@8.56.0': + resolution: {integrity: sha512-lRyPDLzNCuae71A3t9NEINBiTn7swyOhvUj3MyUOxb8x6g6vPEFoOU+ZRmGMusNC3X3YMhqMIX7i8ShqhT74Pw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.49.0 - eslint: ^8.57.0 || ^9.0.0 + '@typescript-eslint/parser': ^8.56.0 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/parser@8.49.0': - resolution: {integrity: sha512-N9lBGA9o9aqb1hVMc9hzySbhKibHmB+N3IpoShyV6HyQYRGIhlrO5rQgttypi+yEeKsKI4idxC8Jw6gXKD4THA==} + '@typescript-eslint/parser@8.56.0': + resolution: {integrity: sha512-IgSWvLobTDOjnaxAfDTIHaECbkNlAlKv2j5SjpB2v7QHKv1FIfjwMy8FsDbVfDX/KjmCmYICcw7uGaXLhtsLNg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - eslint: ^8.57.0 || ^9.0.0 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/project-service@8.49.0': - resolution: {integrity: sha512-/wJN0/DKkmRUMXjZUXYZpD1NEQzQAAn9QWfGwo+Ai8gnzqH7tvqS7oNVdTjKqOcPyVIdZdyCMoqN66Ia789e7g==} + '@typescript-eslint/project-service@8.56.0': + resolution: {integrity: sha512-M3rnyL1vIQOMeWxTWIW096/TtVP+8W3p/XnaFflhmcFp+U4zlxUxWj4XwNs6HbDeTtN4yun0GNTTDBw/SvufKg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/scope-manager@8.49.0': - resolution: {integrity: sha512-npgS3zi+/30KSOkXNs0LQXtsg9ekZ8OISAOLGWA/ZOEn0ZH74Ginfl7foziV8DT+D98WfQ5Kopwqb/PZOaIJGg==} + '@typescript-eslint/scope-manager@8.56.0': + resolution: {integrity: sha512-7UiO/XwMHquH+ZzfVCfUNkIXlp/yQjjnlYUyYz7pfvlK3/EyyN6BK+emDmGNyQLBtLGaYrTAI6KOw8tFucWL2w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/tsconfig-utils@8.49.0': - resolution: {integrity: sha512-8prixNi1/6nawsRYxet4YOhnbW+W9FK/bQPxsGB1D3ZrDzbJ5FXw5XmzxZv82X3B+ZccuSxo/X8q9nQ+mFecWA==} + '@typescript-eslint/tsconfig-utils@8.56.0': + resolution: {integrity: sha512-bSJoIIt4o3lKXD3xmDh9chZcjCz5Lk8xS7Rxn+6l5/pKrDpkCwtQNQQwZ2qRPk7TkUYhrq3WPIHXOXlbXP0itg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/type-utils@8.49.0': - resolution: {integrity: sha512-KTExJfQ+svY8I10P4HdxKzWsvtVnsuCifU5MvXrRwoP2KOlNZ9ADNEWWsQTJgMxLzS5VLQKDjkCT/YzgsnqmZg==} + '@typescript-eslint/type-utils@8.56.0': + resolution: {integrity: sha512-qX2L3HWOU2nuDs6GzglBeuFXviDODreS58tLY/BALPC7iu3Fa+J7EOTwnX9PdNBxUI7Uh0ntP0YWGnxCkXzmfA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - eslint: ^8.57.0 || ^9.0.0 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/types@8.49.0': - resolution: {integrity: sha512-e9k/fneezorUo6WShlQpMxXh8/8wfyc+biu6tnAqA81oWrEic0k21RHzP9uqqpyBBeBKu4T+Bsjy9/b8u7obXQ==} + '@typescript-eslint/types@8.56.0': + resolution: {integrity: sha512-DBsLPs3GsWhX5HylbP9HNG15U0bnwut55Lx12bHB9MpXxQ+R5GC8MwQe+N1UFXxAeQDvEsEDY6ZYwX03K7Z6HQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@8.49.0': - resolution: {integrity: sha512-jrLdRuAbPfPIdYNppHJ/D0wN+wwNfJ32YTAm10eJVsFmrVpXQnDWBn8niCSMlWjvml8jsce5E/O+86IQtTbJWA==} + '@typescript-eslint/typescript-estree@8.56.0': + resolution: {integrity: sha512-ex1nTUMWrseMltXUHmR2GAQ4d+WjkZCT4f+4bVsps8QEdh0vlBsaCokKTPlnqBFqqGaxilDNJG7b8dolW2m43Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/utils@8.49.0': - resolution: {integrity: sha512-N3W7rJw7Rw+z1tRsHZbK395TWSYvufBXumYtEGzypgMUthlg0/hmCImeA8hgO2d2G4pd7ftpxxul2J8OdtdaFA==} + '@typescript-eslint/utils@8.56.0': + resolution: {integrity: sha512-RZ3Qsmi2nFGsS+n+kjLAYDPVlrzf7UhTffrDIKr+h2yzAlYP/y5ZulU0yeDEPItos2Ph46JAL5P/On3pe7kDIQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - eslint: ^8.57.0 || ^9.0.0 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/visitor-keys@8.49.0': - resolution: {integrity: sha512-LlKaciDe3GmZFphXIc79THF/YYBugZ7FS1pO581E/edlVVNbZKDy93evqmrfQ9/Y4uN0vVhX4iuchq26mK/iiA==} + '@typescript-eslint/visitor-keys@8.56.0': + resolution: {integrity: sha512-q+SL+b+05Ud6LbEE35qe4A99P+htKTKVbyiNEe45eCbJFyh/HVK9QXwlrbz+Q4L8SOW4roxSVwXYj4DMBT7Ieg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@vitejs/plugin-vue@6.0.3': - resolution: {integrity: sha512-TlGPkLFLVOY3T7fZrwdvKpjprR3s4fxRln0ORDo1VQ7HHyxJwTlrjKU3kpVWTlaAjIEuCTokmjkZnr8Tpc925w==} + '@vitejs/plugin-vue@6.0.4': + resolution: {integrity: sha512-uM5iXipgYIn13UUQCZNdWkYk+sysBeA97d5mHsAoAt1u/wpN3+zxOmsVJWosuzX+IMGRzeYUNytztrYznboIkQ==} engines: {node: ^20.19.0 || >=22.12.0} peerDependencies: vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 vue: ^3.2.25 - '@vitest/eslint-plugin@1.5.2': - resolution: {integrity: sha512-2t1F2iecXB/b1Ox4U137lhD3chihEE3dRVtu3qMD35tc6UqUjg1VGRJoS1AkFKwpT8zv8OQInzPQO06hrRkeqw==} + '@vitest/eslint-plugin@1.6.9': + resolution: {integrity: sha512-9WfPx1OwJ19QLCSRLkqVO7//1WcWnK3fE/3fJhKMAmDe8+9G4rB47xCNIIeCq3FdEzkIoLTfDlwDlPBaUTMhow==} engines: {node: '>=18'} peerDependencies: eslint: '>=8.57.0' @@ -1095,11 +1323,11 @@ packages: vitest: optional: true - '@vitest/expect@4.0.15': - resolution: {integrity: sha512-Gfyva9/GxPAWXIWjyGDli9O+waHDC0Q0jaLdFP1qPAUUfo1FEXPXUfUkp3eZA0sSq340vPycSyOlYUeM15Ft1w==} + '@vitest/expect@4.0.18': + resolution: {integrity: sha512-8sCWUyckXXYvx4opfzVY03EOiYVxyNrHS5QxX3DAIi5dpJAAkyJezHCP77VMX4HKA2LDT/Jpfo8i2r5BE3GnQQ==} - '@vitest/mocker@4.0.15': - resolution: {integrity: sha512-CZ28GLfOEIFkvCFngN8Sfx5h+Se0zN+h4B7yOsPVCcgtiO7t5jt9xQh2E1UkFep+eb9fjyMfuC5gBypwb07fvQ==} + '@vitest/mocker@4.0.18': + resolution: {integrity: sha512-HhVd0MDnzzsgevnOWCBj5Otnzobjy5wLBe4EdeeFGv8luMsGcYqDuFRMcttKWZA5vVO8RFjexVovXvAM4JoJDQ==} peerDependencies: msw: ^2.4.9 vite: ^6.0.0 || ^7.0.0-0 @@ -1109,41 +1337,50 @@ packages: vite: optional: true - '@vitest/pretty-format@4.0.15': - resolution: {integrity: sha512-SWdqR8vEv83WtZcrfLNqlqeQXlQLh2iilO1Wk1gv4eiHKjEzvgHb2OVc3mIPyhZE6F+CtfYjNlDJwP5MN6Km7A==} + '@vitest/pretty-format@4.0.18': + resolution: {integrity: sha512-P24GK3GulZWC5tz87ux0m8OADrQIUVDPIjjj65vBXYG17ZeU3qD7r+MNZ1RNv4l8CGU2vtTRqixrOi9fYk/yKw==} - '@vitest/runner@4.0.15': - resolution: {integrity: sha512-+A+yMY8dGixUhHmNdPUxOh0la6uVzun86vAbuMT3hIDxMrAOmn5ILBHm8ajrqHE0t8R9T1dGnde1A5DTnmi3qw==} + '@vitest/runner@4.0.18': + resolution: {integrity: sha512-rpk9y12PGa22Jg6g5M3UVVnTS7+zycIGk9ZNGN+m6tZHKQb7jrP7/77WfZy13Y/EUDd52NDsLRQhYKtv7XfPQw==} - '@vitest/snapshot@4.0.15': - resolution: {integrity: sha512-A7Ob8EdFZJIBjLjeO0DZF4lqR6U7Ydi5/5LIZ0xcI+23lYlsYJAfGn8PrIWTYdZQRNnSRlzhg0zyGu37mVdy5g==} + '@vitest/snapshot@4.0.18': + resolution: {integrity: sha512-PCiV0rcl7jKQjbgYqjtakly6T1uwv/5BQ9SwBLekVg/EaYeQFPiXcgrC2Y7vDMA8dM1SUEAEV82kgSQIlXNMvA==} - '@vitest/spy@4.0.15': - resolution: {integrity: sha512-+EIjOJmnY6mIfdXtE/bnozKEvTC4Uczg19yeZ2vtCz5Yyb0QQ31QWVQ8hswJ3Ysx/K2EqaNsVanjr//2+P3FHw==} + '@vitest/spy@4.0.18': + resolution: {integrity: sha512-cbQt3PTSD7P2OARdVW3qWER5EGq7PHlvE+QfzSC0lbwO+xnt7+XH06ZzFjFRgzUX//JmpxrCu92VdwvEPlWSNw==} - '@vitest/utils@4.0.15': - resolution: {integrity: sha512-HXjPW2w5dxhTD0dLwtYHDnelK3j8sR8cWIaLxr22evTyY6q8pRCjZSmhRWVjBaOVXChQd6AwMzi9pucorXCPZA==} + '@vitest/utils@4.0.18': + resolution: {integrity: sha512-msMRKLMVLWygpK3u2Hybgi4MNjcYJvwTb0Ru09+fOyCXIgT5raYP041DRRdiJiI3k/2U6SEbAETB3YtBrUkCFA==} - '@volar/language-core@2.4.26': - resolution: {integrity: sha512-hH0SMitMxnB43OZpyF1IFPS9bgb2I3bpCh76m2WEK7BE0A0EzpYsRp0CCH2xNKshr7kacU5TQBLYn4zj7CG60A==} + '@volar/language-core@2.4.28': + resolution: {integrity: sha512-w4qhIJ8ZSitgLAkVay6AbcnC7gP3glYM3fYwKV3srj8m494E3xtrCv6E+bWviiK/8hs6e6t1ij1s2Endql7vzQ==} - '@volar/source-map@2.4.26': - resolution: {integrity: sha512-JJw0Tt/kSFsIRmgTQF4JSt81AUSI1aEye5Zl65EeZ8H35JHnTvFGmpDOBn5iOxd48fyGE+ZvZBp5FcgAy/1Qhw==} + '@volar/source-map@2.4.28': + resolution: {integrity: sha512-yX2BDBqJkRXfKw8my8VarTyjv48QwxdJtvRgUpNE5erCsgEUdI2DsLbpa+rOQVAJYshY99szEcRDmyHbF10ggQ==} - '@volar/typescript@2.4.26': - resolution: {integrity: sha512-N87ecLD48Sp6zV9zID/5yuS1+5foj0DfuYGdQ6KHj/IbKvyKv1zNX6VCmnKYwtmHadEO6mFc2EKISiu3RDPAvA==} + '@volar/typescript@2.4.28': + resolution: {integrity: sha512-Ja6yvWrbis2QtN4ClAKreeUZPVYMARDYZl9LMEv1iQ1QdepB6wn0jTRxA9MftYmYa4DQ4k/DaSZpFPUfxl8giw==} - '@vue/compiler-core@3.5.25': - resolution: {integrity: sha512-vay5/oQJdsNHmliWoZfHPoVZZRmnSWhug0BYT34njkYTPqClh3DNWLkZNJBVSjsNMrg0CCrBfoKkjZQPM/QVUw==} + '@vue-macros/common@3.1.2': + resolution: {integrity: sha512-h9t4ArDdniO9ekYHAD95t9AZcAbb19lEGK+26iAjUODOIJKmObDNBSe4+6ELQAA3vtYiFPPBtHh7+cQCKi3Dng==} + engines: {node: '>=20.19.0'} + peerDependencies: + vue: ^2.7.0 || ^3.2.25 + peerDependenciesMeta: + vue: + optional: true - '@vue/compiler-dom@3.5.25': - resolution: {integrity: sha512-4We0OAcMZsKgYoGlMjzYvaoErltdFI2/25wqanuTu+S4gismOTRTBPi4IASOjxWdzIwrYSjnqONfKvuqkXzE2Q==} + '@vue/compiler-core@3.5.28': + resolution: {integrity: sha512-kviccYxTgoE8n6OCw96BNdYlBg2GOWfBuOW4Vqwrt7mSKWKwFVvI8egdTltqRgITGPsTFYtKYfxIG8ptX2PJHQ==} - '@vue/compiler-sfc@3.5.25': - resolution: {integrity: sha512-PUgKp2rn8fFsI++lF2sO7gwO2d9Yj57Utr5yEsDf3GNaQcowCLKL7sf+LvVFvtJDXUp/03+dC6f2+LCv5aK1ag==} + '@vue/compiler-dom@3.5.28': + resolution: {integrity: sha512-/1ZepxAb159jKR1btkefDP+J2xuWL5V3WtleRmxaT+K2Aqiek/Ab/+Ebrw2pPj0sdHO8ViAyyJWfhXXOP/+LQA==} - '@vue/compiler-ssr@3.5.25': - resolution: {integrity: sha512-ritPSKLBcParnsKYi+GNtbdbrIE1mtuFEJ4U1sWeuOMlIziK5GtOL85t5RhsNy4uWIXPgk+OUdpnXiTdzn8o3A==} + '@vue/compiler-sfc@3.5.28': + resolution: {integrity: sha512-6TnKMiNkd6u6VeVDhZn/07KhEZuBSn43Wd2No5zaP5s3xm8IqFTHBj84HJah4UepSUJTro5SoqqlOY22FKY96g==} + + '@vue/compiler-ssr@3.5.28': + resolution: {integrity: sha512-JCq//9w1qmC6UGLWJX7RXzrGpKkroubey/ZFqTpvEIDJEKGgntuDMqkuWiZvzTzTA5h2qZvFBFHY7fAAa9475g==} '@vue/devtools-api@6.6.4': resolution: {integrity: sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==} @@ -1151,50 +1388,54 @@ packages: '@vue/devtools-api@7.7.9': resolution: {integrity: sha512-kIE8wvwlcZ6TJTbNeU2HQNtaxLx3a84aotTITUuL/4bzfPxzajGBOoqjMhwZJ8L9qFYDU/lAYMEEm11dnZOD6g==} + '@vue/devtools-api@8.0.6': + resolution: {integrity: sha512-+lGBI+WTvJmnU2FZqHhEB8J1DXcvNlDeEalz77iYgOdY1jTj1ipSBaKj3sRhYcy+kqA8v/BSuvOz1XJucfQmUA==} + '@vue/devtools-kit@7.7.9': resolution: {integrity: sha512-PyQ6odHSgiDVd4hnTP+aDk2X4gl2HmLDfiyEnn3/oV+ckFDuswRs4IbBT7vacMuGdwY/XemxBoh302ctbsptuA==} + '@vue/devtools-kit@8.0.6': + resolution: {integrity: sha512-9zXZPTJW72OteDXeSa5RVML3zWDCRcO5t77aJqSs228mdopYj5AiTpihozbsfFJ0IodfNs7pSgOGO3qfCuxDtw==} + '@vue/devtools-shared@7.7.9': resolution: {integrity: sha512-iWAb0v2WYf0QWmxCGy0seZNDPdO3Sp5+u78ORnyeonS6MT4PC7VPrryX2BpMJrwlDeaZ6BD4vP4XKjK0SZqaeA==} - '@vue/language-core@3.1.8': - resolution: {integrity: sha512-PfwAW7BLopqaJbneChNL6cUOTL3GL+0l8paYP5shhgY5toBNidWnMXWM+qDwL7MC9+zDtzCF2enT8r6VPu64iw==} + '@vue/devtools-shared@8.0.6': + resolution: {integrity: sha512-Pp1JylTqlgMJvxW6MGyfTF8vGvlBSCAvMFaDCYa82Mgw7TT5eE5kkHgDvmOGHWeJE4zIDfCpCxHapsK2LtIAJg==} + + '@vue/language-core@3.2.5': + resolution: {integrity: sha512-d3OIxN/+KRedeM5wQ6H6NIpwS3P5gC9nmyaHgBk+rO6dIsjY+tOh4UlPpiZbAh3YtLdCGEX4M16RmsBqPmJV+g==} + + '@vue/reactivity@3.5.28': + resolution: {integrity: sha512-gr5hEsxvn+RNyu9/9o1WtdYdwDjg5FgjUSBEkZWqgTKlo/fvwZ2+8W6AfKsc9YN2k/+iHYdS9vZYAhpi10kNaw==} + + '@vue/runtime-core@3.5.28': + resolution: {integrity: sha512-POVHTdbgnrBBIpnbYU4y7pOMNlPn2QVxVzkvEA2pEgvzbelQq4ZOUxbp2oiyo+BOtiYlm8Q44wShHJoBvDPAjQ==} + + '@vue/runtime-dom@3.5.28': + resolution: {integrity: sha512-4SXxSF8SXYMuhAIkT+eBRqOkWEfPu6nhccrzrkioA6l0boiq7sp18HCOov9qWJA5HML61kW8p/cB4MmBiG9dSA==} + + '@vue/server-renderer@3.5.28': + resolution: {integrity: sha512-pf+5ECKGj8fX95bNincbzJ6yp6nyzuLDhYZCeFxUNp8EBrQpPpQaLX3nNCp49+UbgbPun3CeVE+5CXVV1Xydfg==} peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + vue: 3.5.28 - '@vue/reactivity@3.5.25': - resolution: {integrity: sha512-5xfAypCQepv4Jog1U4zn8cZIcbKKFka3AgWHEFQeK65OW+Ys4XybP6z2kKgws4YB43KGpqp5D/K3go2UPPunLA==} - - '@vue/runtime-core@3.5.25': - resolution: {integrity: sha512-Z751v203YWwYzy460bzsYQISDfPjHTl+6Zzwo/a3CsAf+0ccEjQ8c+0CdX1WsumRTHeywvyUFtW6KvNukT/smA==} - - '@vue/runtime-dom@3.5.25': - resolution: {integrity: sha512-a4WrkYFbb19i9pjkz38zJBg8wa/rboNERq3+hRRb0dHiJh13c+6kAbgqCPfMaJ2gg4weWD3APZswASOfmKwamA==} - - '@vue/server-renderer@3.5.25': - resolution: {integrity: sha512-UJaXR54vMG61i8XNIzTSf2Q7MOqZHpp8+x3XLGtE3+fL+nQd+k7O5+X3D/uWrnQXOdMw5VPih+Uremcw+u1woQ==} - peerDependencies: - vue: 3.5.25 - - '@vue/shared@3.5.25': - resolution: {integrity: sha512-AbOPdQQnAnzs58H2FrrDxYj/TJfmeS2jdfEEhgiKINy+bnOANmVizIEgq1r+C5zsbs6l1CCQxtcj71rwNQ4jWg==} + '@vue/shared@3.5.28': + resolution: {integrity: sha512-cfWa1fCGBxrvaHRhvV3Is0MgmrbSCxYTXCSCau2I0a1Xw1N1pHAvkWCiXPRAqjvToILvguNyEwjevUqAuBQWvQ==} '@vue/test-utils@2.4.6': resolution: {integrity: sha512-FMxEjOpYNYiFe0GkaHsnJPXFHxQ6m4t8vI/ElPGpMWxZKpmRvQ33OIrvRXemy6yha03RxhOlQuy+gZMC3CQSow==} - '@vueuse/core@14.1.0': - resolution: {integrity: sha512-rgBinKs07hAYyPF834mDTigH7BtPqvZ3Pryuzt1SD/lg5wEcWqvwzXXYGEDb2/cP0Sj5zSvHl3WkmMELr5kfWw==} + '@vueuse/core@14.2.1': + resolution: {integrity: sha512-3vwDzV+GDUNpdegRY6kzpLm4Igptq+GA0QkJ3W61Iv27YWwW/ufSlOfgQIpN6FZRMG0mkaz4gglJRtq5SeJyIQ==} peerDependencies: vue: ^3.5.0 - '@vueuse/metadata@14.1.0': - resolution: {integrity: sha512-7hK4g015rWn2PhKcZ99NyT+ZD9sbwm7SGvp7k+k+rKGWnLjS/oQozoIZzWfCewSUeBmnJkIb+CNr7Zc/EyRnnA==} + '@vueuse/metadata@14.2.1': + resolution: {integrity: sha512-1ButlVtj5Sb/HDtIy1HFr1VqCP4G6Ypqt5MAo0lCgjokrk2mvQKsK2uuy0vqu/Ks+sHfuHo0B9Y9jn9xKdjZsw==} - '@vueuse/shared@14.1.0': - resolution: {integrity: sha512-EcKxtYvn6gx1F8z9J5/rsg3+lTQnvOruQd8fUecW99DCK04BkWD7z5KQ/wTAx+DazyoEE9dJt/zV8OIEQbM6kw==} + '@vueuse/shared@14.2.1': + resolution: {integrity: sha512-shTJncjV9JTI4oVNyF1FQonetYAiTBd+Qj7cY89SWbXSkx7gyhrgtEdF2ZAVWS1S3SHlaROO6F2IesJxQEkZBw==} peerDependencies: vue: ^3.5.0 @@ -1207,12 +1448,12 @@ packages: peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - acorn-walk@8.3.4: - resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==} + acorn-walk@8.3.5: + resolution: {integrity: sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw==} engines: {node: '>=0.4.0'} - acorn@8.15.0: - resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} + acorn@8.16.0: + resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} engines: {node: '>=0.4.0'} hasBin: true @@ -1220,11 +1461,11 @@ packages: resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} engines: {node: '>= 14'} - ajv@6.12.6: - resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + ajv@6.14.0: + resolution: {integrity: sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==} - alien-signals@3.1.1: - resolution: {integrity: sha512-ogkIWbVrLwKtHY6oOAXaYkAxP+cTH7V5FZ5+Tm4NZFd8VDZ6uNMDrfzqctTZ42eTMCSR3ne3otpcxmqSnFfPYA==} + alien-signals@3.1.2: + resolution: {integrity: sha512-d9dYqZTS90WLiU0I5c6DHj/HcKkF8ZyGN3G5x8wSbslulz70KOxaqCT0hQCo9KOyhVqzqGojvNdJXoTumZOtcw==} ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} @@ -1263,6 +1504,14 @@ packages: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} + ast-kit@2.2.0: + resolution: {integrity: sha512-m1Q/RaVOnTp9JxPX+F+Zn7IcLYMzM8kZofDImfsKZd8MbR+ikdOzTeztStWqfrqIxZnYWryyI9ePm3NGjnZgGw==} + engines: {node: '>=20.19.0'} + + ast-walker-scope@0.8.3: + resolution: {integrity: sha512-cbdCP0PGOBq0ASG+sjnKIoYkWMKhhz+F/h9pRexUdX2Hd38+WOlBkRKlqkGOSm0YQpcFMQBJeK4WspUAkwsEdg==} + engines: {node: '>=20.19.0'} + atob@2.1.2: resolution: {integrity: sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==} engines: {node: '>= 4.5.0'} @@ -1276,8 +1525,13 @@ packages: balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - baseline-browser-mapping@2.9.7: - resolution: {integrity: sha512-k9xFKplee6KIio3IDbwj+uaCLpqzOwakOgmqzPezM0sFJlFKcg30vk2wOiAJtkTSfx0SSQDSe8q+mWA/fSH5Zg==} + balanced-match@4.0.4: + resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} + engines: {node: 18 || 20 || >=22} + + baseline-browser-mapping@2.10.0: + resolution: {integrity: sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA==} + engines: {node: '>=6.0.0'} hasBin: true bidi-js@1.0.3: @@ -1295,6 +1549,10 @@ packages: brace-expansion@2.0.2: resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} + brace-expansion@5.0.3: + resolution: {integrity: sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==} + engines: {node: 18 || 20 || >=22} + braces@3.0.3: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} @@ -1316,20 +1574,16 @@ packages: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} - caniuse-lite@1.0.30001760: - resolution: {integrity: sha512-7AAMPcueWELt1p3mi13HR/LHH0TJLT11cnwDJEs3xA4+CK/PLKeO9Kl1oru24htkyUKtkGCvAx4ohB0Ttry8Dw==} + caniuse-lite@1.0.30001772: + resolution: {integrity: sha512-mIwLZICj+ntVTw4BT2zfp+yu/AqV6GMKfJVJMx3MwPxs+uk/uj2GLl2dH8LQbjiLDX66amCga5nKFyDgRR43kg==} ccount@2.0.1: resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} - chai@6.2.1: - resolution: {integrity: sha512-p4Z49OGG5W/WBCPSS/dH3jQ73kD6tiMmUM+bckNK6Jr5JHMG3k9bg/BvKR8lKmtVBKmOiuVaV2ws8s9oSbwysg==} + chai@6.2.2: + resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} engines: {node: '>=18'} - chalk@4.1.2: - resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} - engines: {node: '>=10'} - change-case@5.4.4: resolution: {integrity: sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w==} @@ -1340,8 +1594,12 @@ packages: character-entities@2.0.2: resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==} - ci-info@4.3.1: - resolution: {integrity: sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==} + chokidar@5.0.0: + resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==} + engines: {node: '>= 20.19.0'} + + ci-info@4.4.0: + resolution: {integrity: sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==} engines: {node: '>=8'} clean-regexp@1.0.0: @@ -1367,14 +1625,18 @@ packages: resolution: {integrity: sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==} engines: {node: '>= 12.0.0'} + comment-parser@1.4.5: + resolution: {integrity: sha512-aRDkn3uyIlCFfk5NUA+VdwMmMsh8JGhc4hapfV4yxymHGQ3BVskMQfoXGpCo5IoBuQ9tS5iiVKhCpTcB4pW4qw==} + engines: {node: '>= 12.0.0'} + concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} confbox@0.1.8: resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} - confbox@0.2.2: - resolution: {integrity: sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==} + confbox@0.2.4: + resolution: {integrity: sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==} config-chain@1.1.13: resolution: {integrity: sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==} @@ -1386,8 +1648,8 @@ packages: resolution: {integrity: sha512-7Vv6asjS4gMOuILabD3l739tsaxFQmC+a7pLZm02zyvs8p977bL3zEgq3yDk5rn9B0PbYgIv++jmHcuUab4RhA==} engines: {node: '>=18'} - core-js-compat@3.47.0: - resolution: {integrity: sha512-IGfuznZ/n7Kp9+nypamBhvwdwLsW6KC8IOaURw2doAK5e98AG3acVLdh0woOnEqCfUtS+Vu882JE4k/DAm3ItQ==} + core-js-compat@3.48.0: + resolution: {integrity: sha512-OM4cAF3D6VtH/WkLtWvyNC56EZVXsZdU3iqaMG2B4WvYrlqU831pc4UtG5yp0sE9z8Y02wVN7PjW5Zf9Gt0f1Q==} create-require@1.1.1: resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} @@ -1427,16 +1689,16 @@ packages: resolution: {integrity: sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==} engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} - cssstyle@5.3.4: - resolution: {integrity: sha512-KyOS/kJMEq5O9GdPnaf82noigg5X5DYn0kZPJTaAsCUaBizp6Xa1y9D4Qoqf/JazEXWuruErHgVXwjN5391ZJw==} + cssstyle@6.1.0: + resolution: {integrity: sha512-Ml4fP2UT2K3CUBQnVlbdV/8aFDdlY69E+YnwJM+3VUWl08S3J8c8aRuJqCkD9Py8DHZ7zNNvsfKl8psocHZEFg==} engines: {node: '>=20'} csstype@3.2.3: resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} - data-urls@6.0.0: - resolution: {integrity: sha512-BnBS08aLUM+DKamupXs3w2tJJoqU+AkaE/+6vQxi/G/DPmIZFJJp9Dkb1kM03AZx8ADehDUZgsNxju3mPXZYIA==} - engines: {node: '>=20'} + data-urls@7.0.0: + resolution: {integrity: sha512-23XHcCF+coGYevirZceTVD7NdJOqVn+49IHyxgszm+JIiHLoB2TkmPtsYkNWT1pvRSGkc35L6NHs0yHkN2SumA==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} debug@4.4.3: resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} @@ -1450,8 +1712,8 @@ packages: decimal.js@10.6.0: resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==} - decode-named-character-reference@1.2.0: - resolution: {integrity: sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q==} + decode-named-character-reference@1.3.0: + resolution: {integrity: sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==} decode-uri-component@0.2.2: resolution: {integrity: sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==} @@ -1475,8 +1737,12 @@ packages: resolution: {integrity: sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - diff@4.0.2: - resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} + diff-sequences@29.6.3: + resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + diff@4.0.4: + resolution: {integrity: sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==} engines: {node: '>=0.3.1'} dom-serializer@2.0.0: @@ -1495,8 +1761,8 @@ packages: domutils@3.2.2: resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} - dotenv@17.2.3: - resolution: {integrity: sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==} + dotenv@17.3.1: + resolution: {integrity: sha512-IO8C/dzEb6O3F9/twg6ZLXz164a2fhTnEWb95H23Dm4OuN+92NmEAlTrupP9VW6Jm3sO26tQlqyvyi4CsnY9GA==} engines: {node: '>=12'} eastasianwidth@0.2.0: @@ -1507,8 +1773,8 @@ packages: engines: {node: '>=14'} hasBin: true - electron-to-chromium@1.5.267: - resolution: {integrity: sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==} + electron-to-chromium@1.5.302: + resolution: {integrity: sha512-sM6HAN2LyK82IyPBpznDRqlTQAtuSaO+ShzFiWTvoMJLHyZ+Y39r8VMfHzwbU8MVBzQ4Wdn85+wlZl2TLGIlwg==} emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} @@ -1523,8 +1789,8 @@ packages: resolution: {integrity: sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA==} engines: {node: '>=14'} - enhanced-resolve@5.18.4: - resolution: {integrity: sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q==} + enhanced-resolve@5.19.0: + resolution: {integrity: sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg==} engines: {node: '>=10.13.0'} entities@4.5.0: @@ -1535,6 +1801,10 @@ packages: resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} engines: {node: '>=0.12'} + entities@7.0.1: + resolution: {integrity: sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==} + engines: {node: '>=0.12'} + es-module-lexer@1.7.0: resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} @@ -1543,6 +1813,11 @@ packages: engines: {node: '>=18'} hasBin: true + esbuild@0.27.3: + resolution: {integrity: sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==} + engines: {node: '>=18'} + hasBin: true + escalade@3.2.0: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} @@ -1576,21 +1851,21 @@ packages: peerDependencies: eslint: '>=6.0.0' - eslint-config-flat-gitignore@2.1.0: - resolution: {integrity: sha512-cJzNJ7L+psWp5mXM7jBX+fjHtBvvh06RBlcweMhKD8jWqQw0G78hOW5tpVALGHGFPsBV+ot2H+pdDGJy6CV8pA==} + eslint-config-flat-gitignore@2.2.1: + resolution: {integrity: sha512-wA5EqN0era7/7Gt5Botlsfin/UNY0etJSEeBgbUlFLFrBi47rAN//+39fI7fpYcl8RENutlFtvp/zRa/M/pZNg==} peerDependencies: - eslint: ^9.5.0 + eslint: ^9.5.0 || ^10.0.0 - eslint-flat-config-utils@2.1.4: - resolution: {integrity: sha512-bEnmU5gqzS+4O+id9vrbP43vByjF+8KOs+QuuV4OlqAuXmnRW2zfI/Rza1fQvdihQ5h4DUo0NqFAiViD4mSrzQ==} + eslint-flat-config-utils@3.0.1: + resolution: {integrity: sha512-VMA3u86bLzNAwD/7DkLtQ9lolgIOx2Sj0kTMMnBvrvEz7w0rQj4aGCR+lqsqtld63gKiLyT4BnQZ3gmGDXtvjg==} - eslint-json-compat-utils@0.2.1: - resolution: {integrity: sha512-YzEodbDyW8DX8bImKhAcCeu/L31Dd/70Bidx2Qex9OFUtgzXLqtfWL4Hr5fM/aCCB8QUZLuJur0S9k6UfgFkfg==} + eslint-json-compat-utils@0.2.2: + resolution: {integrity: sha512-KcTUifi8VSSHkrOY0FzB7smuTZRU9T2nCrcCy6k2b+Q77+uylBQVIxN4baVCIWvWJEpud+IsrYgco4JJ6io05g==} engines: {node: '>=12'} peerDependencies: '@eslint/json': '*' eslint: '*' - jsonc-eslint-parser: ^2.4.0 + jsonc-eslint-parser: ^2.4.0 || ^3.0.0 peerDependenciesMeta: '@eslint/json': optional: true @@ -1600,8 +1875,8 @@ packages: peerDependencies: eslint: '*' - eslint-plugin-antfu@3.1.1: - resolution: {integrity: sha512-7Q+NhwLfHJFvopI2HBZbSxWXngTwBLKxW1AGXLr2lEGxcEIK/AsDs8pn8fvIizl5aZjBbVbVK5ujmMpBe4Tvdg==} + eslint-plugin-antfu@3.2.2: + resolution: {integrity: sha512-Qzixht2Dmd/pMbb5EnKqw2V8TiWHbotPlsORO8a+IzCLFwE0RxK8a9k4DCTFPzBwyxJzH+0m2Mn8IUGeGQkyUw==} peerDependencies: eslint: '*' @@ -1616,30 +1891,26 @@ packages: peerDependencies: eslint: '>=8' - eslint-plugin-import-lite@0.3.0: - resolution: {integrity: sha512-dkNBAL6jcoCsXZsQ/Tt2yXmMDoNt5NaBh/U7yvccjiK8cai6Ay+MK77bMykmqQA2bTF6lngaLCDij6MTO3KkvA==} + eslint-plugin-import-lite@0.5.2: + resolution: {integrity: sha512-XvfdWOC5dSLEI9krIPRlNmKSI2ViIE9pVylzfV9fCq0ZpDaNeUk6o0wZv0OzN83QdadgXp1NsY0qjLINxwYCsw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: '>=9.0.0' - typescript: '>=4.5' - peerDependenciesMeta: - typescript: - optional: true - eslint-plugin-jsdoc@61.5.0: - resolution: {integrity: sha512-PR81eOGq4S7diVnV9xzFSBE4CDENRQGP0Lckkek8AdHtbj+6Bm0cItwlFnxsLFriJHspiE3mpu8U20eODyToIg==} - engines: {node: '>=20.11.0'} + eslint-plugin-jsdoc@62.7.0: + resolution: {integrity: sha512-jootujJOIGMkCLN+/WgDFKtaclCt2MEEy9cZ1RyK19Az1JvVI3awbeMXNlJ6y4h8RWIJpcXqmxsu4t9NThYbNw==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} peerDependencies: - eslint: ^7.0.0 || ^8.0.0 || ^9.0.0 + eslint: ^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0 - eslint-plugin-jsonc@2.21.0: - resolution: {integrity: sha512-HttlxdNG5ly3YjP1cFMP62R4qKLxJURfBZo2gnMY+yQojZxkLyOpY1H1KRTKBmvQeSG9pIpSGEhDjE17vvYosg==} + eslint-plugin-jsonc@2.21.1: + resolution: {integrity: sha512-dbNR5iEnQeORwsK2WZzr3QaMtFCY3kKJVMRHPzUpKzMhmVy2zIpVgFDpX8MNoIdoqz6KCpCfOJavhfiSbZbN+w==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: '>=6.0.0' - eslint-plugin-n@17.23.1: - resolution: {integrity: sha512-68PealUpYoHOBh332JLLD9Sj7OQUDkFpmcfqt8R9sySfFSeuGJjMTJQvCRRB96zO3A/PELRLkPrzsHmzEFQQ5A==} + eslint-plugin-n@17.24.0: + resolution: {integrity: sha512-/gC7/KAYmfNnPNOb3eu8vw+TdVnV0zhdQwexsw6FLXbhzroVj20vRn2qL8lDWDGnAQ2J8DhdfvXxX9EoxvERvw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: '>=8.23.0' @@ -1648,14 +1919,14 @@ packages: resolution: {integrity: sha512-brcKcxGnISN2CcVhXJ/kEQlNa0MEfGRtwKtWA16SkqXHKitaKIMrfemJKLKX1YqDU5C/5JY3PvZXd5jEW04e0Q==} engines: {node: '>=5.0.0'} - eslint-plugin-perfectionist@4.15.1: - resolution: {integrity: sha512-MHF0cBoOG0XyBf7G0EAFCuJJu4I18wy0zAoT1OHfx2o6EOx1EFTIzr2HGeuZa1kDcusoX0xJ9V7oZmaeFd773Q==} - engines: {node: ^18.0.0 || >=20.0.0} + eslint-plugin-perfectionist@5.6.0: + resolution: {integrity: sha512-pxrLrfRp5wl1Vol1fAEa/G5yTXxefTPJjz07qC7a8iWFXcOZNuWBItMQ2OtTzfQIvMq6bMyYcrzc3Wz++na55Q==} + engines: {node: ^20.0.0 || >=22.0.0} peerDependencies: - eslint: '>=8.45.0' + eslint: ^8.45.0 || ^9.0.0 || ^10.0.0 - eslint-plugin-pnpm@1.4.3: - resolution: {integrity: sha512-wdWrkWN5mxRgEADkQvxwv0xA+0++/hYDD5OyXTL6UqPLUPdcCFQJO61NO7IKhEqb3GclWs02OoFs1METN+a3zQ==} + eslint-plugin-pnpm@1.5.0: + resolution: {integrity: sha512-ayMo1GvrQ/sF/bz1aOAiH0jv9eAqU2Z+a1ycoWz/uFFK5NxQDq49BDKQtBumcOUBf2VHyiTW4a8u+6KVqoIWzQ==} peerDependencies: eslint: ^9.0.0 @@ -1665,29 +1936,29 @@ packages: peerDependencies: eslint: ^7.0.0 || ^8.0.0 || ^9.0.0 - eslint-plugin-regexp@2.10.0: - resolution: {integrity: sha512-ovzQT8ESVn5oOe5a7gIDPD5v9bCSjIFJu57sVPDqgPRXicQzOnYfFN21WoQBQF18vrhT5o7UMKFwJQVVjyJ0ng==} - engines: {node: ^18 || >=20} + eslint-plugin-regexp@3.0.0: + resolution: {integrity: sha512-iW7hgAV8NOG6E2dz+VeKpq67YLQ9jaajOKYpoOSic2/q8y9BMdXBKkSR9gcMtbqEhNQzdW41E3wWzvhp8ExYwQ==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} peerDependencies: - eslint: '>=8.44.0' + eslint: '>=9.38.0' - eslint-plugin-toml@0.12.0: - resolution: {integrity: sha512-+/wVObA9DVhwZB1nG83D2OAQRrcQZXy+drqUnFJKymqnmbnbfg/UPmEMCKrJNcEboUGxUjYrJlgy+/Y930mURQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + eslint-plugin-toml@1.1.2: + resolution: {integrity: sha512-PgVDoT6TWmIjoMuBZPZTWJEHUezCNq17SQ2z+96L1YljNkrr8IwHHskvB9+mzGw8AguRZC4zEfMvrjlWu6Hyiw==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} peerDependencies: - eslint: '>=6.0.0' + eslint: '>=9.38.0' - eslint-plugin-unicorn@62.0.0: - resolution: {integrity: sha512-HIlIkGLkvf29YEiS/ImuDZQbP12gWyx5i3C6XrRxMvVdqMroCI9qoVYCoIl17ChN+U89pn9sVwLxhIWj5nEc7g==} + eslint-plugin-unicorn@63.0.0: + resolution: {integrity: sha512-Iqecl9118uQEXYh7adylgEmGfkn5es3/mlQTLLkd4pXkIk9CTGrAbeUux+YljSa2ohXCBmQQ0+Ej1kZaFgcfkA==} engines: {node: ^20.10.0 || >=21.0.0} peerDependencies: eslint: '>=9.38.0' - eslint-plugin-unused-imports@4.3.0: - resolution: {integrity: sha512-ZFBmXMGBYfHttdRtOG9nFFpmUvMtbHSjsKrS20vdWdbfiVYsO3yA2SGYy9i9XmZJDfMGBflZGBCm70SEnFQtOA==} + eslint-plugin-unused-imports@4.4.1: + resolution: {integrity: sha512-oZGYUz1X3sRMGUB+0cZyK2VcvRX5lm/vB56PgNNcU+7ficUCKm66oZWKUubXWnOuPjQ8PvmXtCViXBMONPe7tQ==} peerDependencies: '@typescript-eslint/eslint-plugin': ^8.0.0-0 || ^7.0.0 || ^6.0.0 || ^5.0.0 - eslint: ^9.0.0 || ^8.0.0 + eslint: ^10.0.0 || ^9.0.0 || ^8.0.0 peerDependenciesMeta: '@typescript-eslint/eslint-plugin': optional: true @@ -1699,13 +1970,13 @@ packages: eslint: '>=5.0.0' vue-eslint-parser: '>=7.1.0' - eslint-plugin-vue@10.6.2: - resolution: {integrity: sha512-nA5yUs/B1KmKzvC42fyD0+l9Yd+LtEpVhWRbXuDj0e+ZURcTtyRbMDWUeJmTAh2wC6jC83raS63anNM2YT3NPw==} + eslint-plugin-vue@10.8.0: + resolution: {integrity: sha512-f1J/tcbnrpgC8suPN5AtdJ5MQjuXbSU9pGRSSYAuF3SHoiYCOdEX6O22pLaRyLHXvDcOe+O5ENgc1owQ587agA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: '@stylistic/eslint-plugin': ^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 '@typescript-eslint/parser': ^7.0.0 || ^8.0.0 - eslint: ^8.57.0 || ^9.0.0 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 vue-eslint-parser: ^10.0.0 peerDependenciesMeta: '@stylistic/eslint-plugin': @@ -1713,11 +1984,11 @@ packages: '@typescript-eslint/parser': optional: true - eslint-plugin-yml@1.19.1: - resolution: {integrity: sha512-bYkOxyEiXh9WxUhVYPELdSHxGG5pOjCSeJOVkfdIyj6tuiHDxrES2WAW1dBxn3iaZQey57XflwLtCYRcNPOiOg==} - engines: {node: ^14.17.0 || >=16.0.0} + eslint-plugin-yml@3.2.2: + resolution: {integrity: sha512-vMluBBMGecygLzeOly0EnDhudQb9CNEXEUokTap93oF/KyASAADed4xRlFBQQNuzJK3N6u5s3M/IjIKPGZZOKA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24.0.0} peerDependencies: - eslint: '>=6.0.0' + eslint: '>=9.38.0' eslint-processor-vue-blocks@2.0.0: resolution: {integrity: sha512-u4W0CJwGoWY3bjXAuFpc/b6eK3NQEI8MoeW7ritKj3G3z/WtHrKjkqf+wk8mPEy5rlMGS+k6AZYOw2XBoN/02Q==} @@ -1725,9 +1996,9 @@ packages: '@vue/compiler-sfc': ^3.3.0 eslint: '>=9.0.0' - eslint-scope@8.4.0: - resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + eslint-scope@9.1.1: + resolution: {integrity: sha512-GaUN0sWim5qc8KVErfPBWmc31LEsOkrUJbvJZV+xuL3u2phMUK4HIvXlWAakfC8W4nzlK+chPEAkYOYb5ZScIw==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} eslint-visitor-keys@3.4.3: resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} @@ -1737,9 +2008,13 @@ packages: resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - eslint@9.39.2: - resolution: {integrity: sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + eslint-visitor-keys@5.0.1: + resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + eslint@10.0.1: + resolution: {integrity: sha512-20MV9SUdeN6Jd84xESsKhRly+/vxI+hwvpBMA93s+9dAcjdCuCojn4IqUGS3lvVaqjVYGYHSRMCpeFtF2rQYxQ==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} hasBin: true peerDependencies: jiti: '*' @@ -1751,6 +2026,10 @@ packages: resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + espree@11.1.1: + resolution: {integrity: sha512-AVHPqQoZYc+RUM4/3Ly5udlZY/U4LS8pIG05jEjWM2lQMU/oaZ7qshzAl2YP1tfNmXfftH3ohurfwNAug+MnsQ==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + espree@9.6.1: resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -1760,8 +2039,8 @@ packages: engines: {node: '>=4'} hasBin: true - esquery@1.6.0: - resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} + esquery@1.7.0: + resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} engines: {node: '>=0.10'} esrecurse@4.3.0: @@ -1805,8 +2084,8 @@ packages: fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - fastq@1.19.1: - resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==} + fastq@1.20.1: + resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} fault@2.0.1: resolution: {integrity: sha512-WtySTkS4OKev5JtpHXnib4Gxiurzh5NCGvWrFaZ34m6JehfTUhKZvn9njTfw48t6JumVQOmrKqpmGcdwxnhqBQ==} @@ -1867,8 +2146,8 @@ packages: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} - get-tsconfig@4.13.0: - resolution: {integrity: sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==} + get-tsconfig@4.13.6: + resolution: {integrity: sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==} github-slugger@2.0.0: resolution: {integrity: sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==} @@ -1883,11 +2162,12 @@ packages: glob@10.5.0: resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==} + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me hasBin: true glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} - deprecated: Glob versions prior to v9 are no longer supported + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me globals@14.0.0: resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} @@ -1901,6 +2181,10 @@ packages: resolution: {integrity: sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==} engines: {node: '>=18'} + globals@17.3.0: + resolution: {integrity: sha512-yMqGUQVVCkD4tqjOJf3TnrvaaHDMYp4VlUSObbkIiuCPe/ofdMBFIAcBbCSRFWOnos6qRiTVStDwqPLUclaxIw==} + engines: {node: '>=18'} + globrex@0.1.2: resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} @@ -1910,16 +2194,12 @@ packages: graphemer@1.4.0: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} - has-flag@4.0.0: - resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} - engines: {node: '>=8'} - hookable@5.5.3: resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==} - html-encoding-sniffer@4.0.0: - resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==} - engines: {node: '>=18'} + html-encoding-sniffer@6.0.0: + resolution: {integrity: sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} html-entities@2.6.0: resolution: {integrity: sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==} @@ -1932,10 +2212,6 @@ packages: resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} engines: {node: '>= 14'} - iconv-lite@0.6.3: - resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} - engines: {node: '>=0.10.0'} - ignore@5.3.2: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} @@ -2025,20 +2301,16 @@ packages: resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} hasBin: true - jsdoc-type-pratt-parser@4.8.0: - resolution: {integrity: sha512-iZ8Bdb84lWRuGHamRXFyML07r21pcwBrLkHEuHgEY5UbCouBwv7ECknDRKzsQIXMiqpPymqtIf8TC/shYKB5rw==} - engines: {node: '>=12.0.0'} - - jsdoc-type-pratt-parser@6.10.0: - resolution: {integrity: sha512-+LexoTRyYui5iOhJGn13N9ZazL23nAHGkXsa1p/C8yeq79WRfLBag6ZZ0FQG2aRoc9yfo59JT9EYCQonOkHKkQ==} - engines: {node: '>=20.0.0'} - jsdoc-type-pratt-parser@7.0.0: resolution: {integrity: sha512-c7YbokssPOSHmqTbSAmTtnVgAVa/7lumWNYqomgd5KOMyPrRve2anx6lonfOsXEQacqF9FKVUj7bLg4vRSvdYA==} engines: {node: '>=20.0.0'} - jsdom@27.3.0: - resolution: {integrity: sha512-GtldT42B8+jefDUC4yUKAvsaOrH7PDHmZxZXNgF2xMmymjUbRYJvpAybZAKEmXDGTM0mCsz8duOa4vTm5AY2Kg==} + jsdoc-type-pratt-parser@7.1.1: + resolution: {integrity: sha512-/2uqY7x6bsrpi3i9LVU6J89352C0rpMk0as8trXxCtvd4kPk1ke/Eyif6wqfSLvoNJqcDG9Vk4UsXgygzCt2xA==} + engines: {node: '>=20.0.0'} + + jsdom@28.1.0: + resolution: {integrity: sha512-0+MoQNYyr2rBHqO1xilltfDjV9G7ymYGlAUazgcDLQaUf8JDHbuGwsxN6U9qWaElZ4w1B2r7yEGIL3GdeW3Rug==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} peerDependencies: canvas: ^3.0.0 @@ -2076,74 +2348,78 @@ packages: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} - lightningcss-android-arm64@1.30.2: - resolution: {integrity: sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==} + lightningcss-android-arm64@1.31.1: + resolution: {integrity: sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [android] - lightningcss-darwin-arm64@1.30.2: - resolution: {integrity: sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==} + lightningcss-darwin-arm64@1.31.1: + resolution: {integrity: sha512-02uTEqf3vIfNMq3h/z2cJfcOXnQ0GRwQrkmPafhueLb2h7mqEidiCzkE4gBMEH65abHRiQvhdcQ+aP0D0g67sg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [darwin] - lightningcss-darwin-x64@1.30.2: - resolution: {integrity: sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==} + lightningcss-darwin-x64@1.31.1: + resolution: {integrity: sha512-1ObhyoCY+tGxtsz1lSx5NXCj3nirk0Y0kB/g8B8DT+sSx4G9djitg9ejFnjb3gJNWo7qXH4DIy2SUHvpoFwfTA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [darwin] - lightningcss-freebsd-x64@1.30.2: - resolution: {integrity: sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==} + lightningcss-freebsd-x64@1.31.1: + resolution: {integrity: sha512-1RINmQKAItO6ISxYgPwszQE1BrsVU5aB45ho6O42mu96UiZBxEXsuQ7cJW4zs4CEodPUioj/QrXW1r9pLUM74A==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [freebsd] - lightningcss-linux-arm-gnueabihf@1.30.2: - resolution: {integrity: sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==} + lightningcss-linux-arm-gnueabihf@1.31.1: + resolution: {integrity: sha512-OOCm2//MZJ87CdDK62rZIu+aw9gBv4azMJuA8/KB74wmfS3lnC4yoPHm0uXZ/dvNNHmnZnB8XLAZzObeG0nS1g==} engines: {node: '>= 12.0.0'} cpu: [arm] os: [linux] - lightningcss-linux-arm64-gnu@1.30.2: - resolution: {integrity: sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==} + lightningcss-linux-arm64-gnu@1.31.1: + resolution: {integrity: sha512-WKyLWztD71rTnou4xAD5kQT+982wvca7E6QoLpoawZ1gP9JM0GJj4Tp5jMUh9B3AitHbRZ2/H3W5xQmdEOUlLg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [glibc] - lightningcss-linux-arm64-musl@1.30.2: - resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==} + lightningcss-linux-arm64-musl@1.31.1: + resolution: {integrity: sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [musl] - lightningcss-linux-x64-gnu@1.30.2: - resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==} + lightningcss-linux-x64-gnu@1.31.1: + resolution: {integrity: sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [glibc] - lightningcss-linux-x64-musl@1.30.2: - resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==} + lightningcss-linux-x64-musl@1.31.1: + resolution: {integrity: sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [musl] - lightningcss-win32-arm64-msvc@1.30.2: - resolution: {integrity: sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==} + lightningcss-win32-arm64-msvc@1.31.1: + resolution: {integrity: sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [win32] - lightningcss-win32-x64-msvc@1.30.2: - resolution: {integrity: sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==} + lightningcss-win32-x64-msvc@1.31.1: + resolution: {integrity: sha512-I9aiFrbd7oYHwlnQDqr1Roz+fTz61oDDJX7n9tYF9FJymH1cIN1DtKw3iYt6b8WZgEjoNwVSncwF4wx/ZedMhw==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [win32] - lightningcss@1.30.2: - resolution: {integrity: sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==} + lightningcss@1.31.1: + resolution: {integrity: sha512-l51N2r93WmGUye3WuFoN5k10zyvrVs0qfKBhyC5ogUQ6Ew6JUSswh78mbSO+IU3nTWsyOArqPCcShdQSadghBQ==} engines: {node: '>= 12.0.0'} local-pkg@1.1.2: @@ -2154,14 +2430,11 @@ packages: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} - lodash.merge@4.6.2: - resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} - lodash.sortedlastindex@4.1.0: resolution: {integrity: sha512-s8xEQdsp2Tu5zUqVdFSe9C0kR8YlnAJYLqMdkh+pIRBRxF6/apWseLdHl3/+jv2I61dhPwtI/Ff+EqvCpc+N8w==} - lodash@4.17.21: - resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + lodash@4.17.23: + resolution: {integrity: sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==} longest-streak@3.1.0: resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} @@ -2169,13 +2442,17 @@ packages: lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} - lru-cache@11.2.4: - resolution: {integrity: sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==} + lru-cache@11.2.6: + resolution: {integrity: sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==} engines: {node: 20 || >=22} lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + magic-string-ast@1.0.3: + resolution: {integrity: sha512-CvkkH1i81zl7mmb94DsRiFeG9V2fR2JeuK8yDgS8oiZSFa++wWLEgZ5ufEOyLHbvSbD1gTRKv9NdX69Rnvr9JA==} + engines: {node: '>=20.19.0'} + magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} @@ -2185,16 +2462,16 @@ packages: markdown-table@3.0.4: resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==} - marked@17.0.1: - resolution: {integrity: sha512-boeBdiS0ghpWcSwoNm/jJBwdpFaMnZWRzjA6SkUMYb40SVaN1x7mmfGKp0jvexGcx+7y2La5zRZsYFZI6Qpypg==} + marked@17.0.3: + resolution: {integrity: sha512-jt1v2ObpyOKR8p4XaUJVk3YWRJ5n+i4+rjQopxvV32rSndTJXvIzuUdWWIy/1pFQMkQmvTXawzDNqOH/CUmx6A==} engines: {node: '>= 20'} hasBin: true mdast-util-find-and-replace@3.0.2: resolution: {integrity: sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==} - mdast-util-from-markdown@2.0.2: - resolution: {integrity: sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==} + mdast-util-from-markdown@2.0.3: + resolution: {integrity: sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q==} mdast-util-frontmatter@2.0.1: resolution: {integrity: sha512-LRqI9+wdgC25P0URIJY9vwocIzCcksduHQ9OF2joxQoyTNVduwLAFUzjoopuRJbJAReaKrNQKAZKL3uCMugWJA==} @@ -2330,19 +2607,23 @@ packages: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} - minimatch@3.1.2: - resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + minimatch@10.2.2: + resolution: {integrity: sha512-+G4CpNBxa5MprY+04MbgOw1v7So6n5JY166pFi9KfYwT78fxScCeSNQSNzp6dpPSW2rONOps6Ocam1wFhCgoVw==} + engines: {node: 18 || 20 || >=22} + + minimatch@3.1.3: + resolution: {integrity: sha512-M2GCs7Vk83NxkUyQV1bkABc4yxgz9kILhHImZiBPAZ9ybuvCb0/H7lEl5XvIg3g+9d4eNotkZA5IWwYl0tibaA==} minimatch@9.0.1: resolution: {integrity: sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==} engines: {node: '>=16 || 14 >=14.17'} - minimatch@9.0.5: - resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + minimatch@9.0.6: + resolution: {integrity: sha512-kQAVowdR33euIqeA0+VZTDqU+qo1IeVY+hrKYtZMio3Pg0P0vuh/kwRylLUddJhB6pf3q/botcOvRtx4IN1wqQ==} engines: {node: '>=16 || 14 >=14.17'} - minipass@7.1.2: - resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} + minipass@7.1.3: + resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} engines: {node: '>=16 || 14 >=14.17'} mitt@3.0.1: @@ -2456,6 +2737,9 @@ packages: perfect-debounce@1.0.0: resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==} + perfect-debounce@2.1.0: + resolution: {integrity: sha512-LjgdTytVFXeUgtHZr9WYViYSM/g8MkcTPYDlPa3cDqMirHjKiSZPYd6DoL7pK8AJQr+uWkQvCjHNdiMqsrJs+g==} + picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -2486,8 +2770,8 @@ packages: resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} engines: {node: '>=4'} - pnpm-workspace-yaml@1.4.3: - resolution: {integrity: sha512-Q8B3SWuuISy/Ciag4DFP7MCrJX07wfaekcqD2o/msdIj4x8Ql3bZ/NEKOXV7mTVh7m1YdiFWiMi9xH+0zuEGHw==} + pnpm-workspace-yaml@1.5.0: + resolution: {integrity: sha512-PxdyJuFvq5B0qm3s9PaH/xOtSxrcvpBRr+BblhucpWjs8c79d4b7/cXhyY4AyHOHCnqklCYZTjfl0bT/mFVTRw==} postcss-safe-parser@6.0.0: resolution: {integrity: sha512-FARHN8pwH+WiS2OPCxJI8FuRJpTVnn6ZNFiqAM2aeW2LwTHWWmWgIyKC6cUo0L8aeKiF/14MNvnpls6R2PBeMQ==} @@ -2576,8 +2860,8 @@ packages: prettier-plugin-svelte: optional: true - prettier@3.7.4: - resolution: {integrity: sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==} + prettier@3.8.1: + resolution: {integrity: sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==} engines: {node: '>=14'} hasBin: true @@ -2598,6 +2882,10 @@ packages: queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + readdirp@5.0.0: + resolution: {integrity: sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==} + engines: {node: '>= 20.19.0'} + refa@0.12.1: resolution: {integrity: sha512-J8rn6v4DBb2nnFqkqwy6/NnTYMcgLA+sLr0iIO41qpv0n+ngb7ksag2tMRl0inb1bbO/esUwzW1vbJi7K0sI0g==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} @@ -2636,8 +2924,8 @@ packages: rfdc@1.4.1: resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} - rollup@4.53.3: - resolution: {integrity: sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA==} + rollup@4.59.0: + resolution: {integrity: sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -2658,8 +2946,11 @@ packages: resolution: {integrity: sha512-3A6sD0WYP7+QrjbfNA2FN3FsOaGGFoekCVgTyypy53gPxhbkCIjtO6YWgdrfM+n/8sI8JeXZOIxsHjMTNxQ4nQ==} engines: {node: ^14.0.0 || >=16.0.0} - semver@7.7.3: - resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} + scule@1.3.0: + resolution: {integrity: sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==} + + semver@7.7.4: + resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==} engines: {node: '>=10'} hasBin: true @@ -2678,8 +2969,8 @@ packages: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} - simple-icons@16.2.0: - resolution: {integrity: sha512-SCV4cAX8O2M2WQ3QJm+3k4QdcUIJiBiwKNViQiOwPjWbFWgypzelviW+Bp0A2ij6r/DIEZpTTDcLgD/BE4aexQ==} + simple-icons@16.9.0: + resolution: {integrity: sha512-aKst2C7cLkFyaiQ/Crlwxt9xYOpGPk05XuJZ0ZTJNNCzHCKYrGWz2ebJSi5dG8CmTCxUF/BGs6A8uyJn/EQxqw==} engines: {node: '>=0.12.18'} sisteransi@1.0.5: @@ -2711,8 +3002,8 @@ packages: spdx-expression-parse@4.0.0: resolution: {integrity: sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==} - spdx-license-ids@3.0.22: - resolution: {integrity: sha512-4PRT4nh1EImPbt2jASOKHX7PB7I+e4IWNLvkKFDxNhJlfjbYlleYQh285Z/3mPTHSAK/AvdMmw5BNNuYH8ShgQ==} + spdx-license-ids@3.0.23: + resolution: {integrity: sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw==} speakingurl@14.0.1: resolution: {integrity: sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==} @@ -2756,10 +3047,6 @@ packages: resolution: {integrity: sha512-H+ue8Zo4vJmV2nRjpx86P35lzwDT3nItnIsocgumgr0hHMQ+ZGq5vrERg9kJBo5AWGmxZDhzDo+WVIJqkB0cGA==} engines: {node: '>=16'} - supports-color@7.2.0: - resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} - engines: {node: '>=8'} - svgo@3.3.2: resolution: {integrity: sha512-OoohrmuUlBs8B8o6MB2Aevn+pRIH9zDALSR+6hhqVfa6fRwG/Qw9VUMSMW9VNg2CFc/MTIfabtdOVl9ODIJjpw==} engines: {node: '>=14.0.0'} @@ -2772,12 +3059,12 @@ packages: resolution: {integrity: sha512-2SG1TnJGjMkD4+gblONMGYSrwAzYi+ymOitD+Jb/iMYm57nH20PlkVeMQRah3yDMKEa0QQYUF/QPWpdW7C6zNg==} engines: {node: ^14.18.0 || >=16.0.0} - synckit@0.11.11: - resolution: {integrity: sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==} + synckit@0.11.12: + resolution: {integrity: sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ==} engines: {node: ^14.18.0 || >=16.0.0} - tailwindcss@4.1.18: - resolution: {integrity: sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==} + tailwindcss@4.2.0: + resolution: {integrity: sha512-yYzTZ4++b7fNYxFfpnberEEKu43w44aqDMNM9MHMmcKuCH7lL8jJ4yJ7LGHv7rSwiqM0nkiobF9I6cLlpS2P7Q==} tapable@2.3.0: resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} @@ -2801,11 +3088,11 @@ packages: resolution: {integrity: sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==} engines: {node: '>=14.0.0'} - tldts-core@7.0.19: - resolution: {integrity: sha512-lJX2dEWx0SGH4O6p+7FPwYmJ/bu1JbcGJ8RLaG9b7liIgZ85itUVEPbMtWRVrde/0fnDPEPHW10ZsKW3kVsE9A==} + tldts-core@7.0.23: + resolution: {integrity: sha512-0g9vrtDQLrNIiCj22HSe9d4mLVG3g5ph5DZ8zCKBr4OtrspmNB6ss7hVyzArAeE88ceZocIEGkyW1Ime7fxPtQ==} - tldts@7.0.19: - resolution: {integrity: sha512-8PWx8tvC4jDB39BQw1m4x8y5MH1BcQ5xHeL2n7UVFulMPH/3Q0uiamahFJ3lXA0zO2SUyRXuVVbWSDmstlt9YA==} + tldts@7.0.23: + resolution: {integrity: sha512-ASdhgQIBSay0R/eXggAkQ53G4nTJqTXqC2kbaBbdDwM7SkjyZyO0OaaN1/FH7U/yCeqOHDwFO5j8+Os/IS1dXw==} hasBin: true to-regex-range@5.0.1: @@ -2816,9 +3103,9 @@ packages: resolution: {integrity: sha512-41wJyvKep3yT2tyPqX/4blcfybknGB4D+oETKLs7Q76UiPqRpUJK3hr1nxelyYO0PHKVzJwlu0aCeEAsGI6rpw==} engines: {node: '>=20'} - toml-eslint-parser@0.10.1: - resolution: {integrity: sha512-9mjy3frhioGIVGcwamlVlUyJ9x+WHw/TXiz9R4YOlmsIuBN43r9Dp8HZ35SF9EKjHrn3BUZj04CF+YqZ2oJ+7w==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + toml-eslint-parser@1.0.3: + resolution: {integrity: sha512-A5F0cM6+mDleacLIEUkmfpkBbnHJFV1d2rprHU2MXNk7mlxHq2zGojA+SRvQD1RoMo9gqjZPWEaKG4v1BQ48lw==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} tough-cookie@6.0.0: resolution: {integrity: sha512-kXuRi1mtaKMrsLUxz3sQYvVl37B0Ns6MzfrtV5DvJceE9bPyspOqk9xxv7XbZWcfLWbFmm997vl83qUWVJA64w==} @@ -2828,8 +3115,8 @@ packages: resolution: {integrity: sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==} engines: {node: '>=20'} - ts-api-utils@2.1.0: - resolution: {integrity: sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==} + ts-api-utils@2.4.0: + resolution: {integrity: sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==} engines: {node: '>=18.12'} peerDependencies: typescript: '>=4.8.4' @@ -2865,12 +3152,16 @@ packages: engines: {node: '>=14.17'} hasBin: true - ufo@1.6.1: - resolution: {integrity: sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==} + ufo@1.6.3: + resolution: {integrity: sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==} undici-types@7.16.0: resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} + undici@7.22.0: + resolution: {integrity: sha512-RqslV2Us5BrllB+JeiZnK4peryVTndy9Dnqq62S3yYRRTj0tFQCwEniUy2167skdGOy3vqRzEvl1Dm4sV2ReDg==} + engines: {node: '>=20.18.1'} + unicode-emoji-modifier-base@1.0.0: resolution: {integrity: sha512-yLSH4py7oFH3oG/9K+XWrz1pSi3dfUrWEnInbxMfArOfc1+33BlGPQtLsOYwvdMy11AwUBetYuaRxSPqgkq+8g==} engines: {node: '>=4'} @@ -2884,15 +3175,23 @@ packages: unist-util-visit-parents@6.0.2: resolution: {integrity: sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==} - unist-util-visit@5.0.0: - resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==} + unist-util-visit@5.1.0: + resolution: {integrity: sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==} + + unplugin-utils@0.3.1: + resolution: {integrity: sha512-5lWVjgi6vuHhJ526bI4nlCOmkCIF3nnfXkCMDeMJrtdvxTs6ZFCM8oNufGTsDbKv/tJ/xj8RpvXjRuPBZJuJog==} + engines: {node: '>=20.19.0'} unplugin@2.3.11: resolution: {integrity: sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww==} engines: {node: '>=18.12.0'} - update-browserslist-db@1.2.2: - resolution: {integrity: sha512-E85pfNzMQ9jpKkA7+TJAi4TJN+tBCuWh5rUcS/sv6cFi+1q9LYDwDI5dpUL0u/73EElyQ8d3TEaeW4sPedBqYA==} + unplugin@3.0.0: + resolution: {integrity: sha512-0Mqk3AT2TZCXWKdcoaufeXNukv2mTrEZExeXlHIOZXdqYoHHr4n51pymnwV8x2BOVxwXbK2HLlI7usrqMpycdg==} + engines: {node: ^20.19.0 || >=22.12.0} + + update-browserslist-db@1.2.3: + resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} hasBin: true peerDependencies: browserslist: '>= 4.21.0' @@ -2915,8 +3214,8 @@ packages: peerDependencies: vue: '>=3.2.13' - vite@7.2.7: - resolution: {integrity: sha512-ITcnkFeR3+fI8P1wMgItjGrR10170d8auB4EpMLPqmx6uxElH3a/hHGQabSHKdqd4FXWO1nFIp9rRn7JQ34ACQ==} + vite@7.3.1: + resolution: {integrity: sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: @@ -2955,18 +3254,18 @@ packages: yaml: optional: true - vitest@4.0.15: - resolution: {integrity: sha512-n1RxDp8UJm6N0IbJLQo+yzLZ2sQCDyl1o0LeugbPWf8+8Fttp29GghsQBjYJVmWq3gBFfe9Hs1spR44vovn2wA==} + vitest@4.0.18: + resolution: {integrity: sha512-hOQuK7h0FGKgBAas7v0mSAsnvrIgAvWmRFjmzpJ7SwFHH3g1k2u37JtYwOwmEKhK6ZO3v9ggDBBm0La1LCK4uQ==} engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} hasBin: true peerDependencies: '@edge-runtime/vm': '*' '@opentelemetry/api': ^1.9.0 '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 - '@vitest/browser-playwright': 4.0.15 - '@vitest/browser-preview': 4.0.15 - '@vitest/browser-webdriverio': 4.0.15 - '@vitest/ui': 4.0.15 + '@vitest/browser-playwright': 4.0.18 + '@vitest/browser-preview': 4.0.18 + '@vitest/browser-webdriverio': 4.0.18 + '@vitest/ui': 4.0.18 happy-dom: '*' jsdom: '*' peerDependenciesMeta: @@ -2995,31 +3294,41 @@ packages: vue-component-type-helpers@2.2.12: resolution: {integrity: sha512-YbGqHZ5/eW4SnkPNR44mKVc6ZKQoRs/Rux1sxC6rdwXb4qpbOSYfDr9DsTHolOTGmIKgM9j141mZbBeg05R1pw==} - vue-eslint-parser@10.2.0: - resolution: {integrity: sha512-CydUvFOQKD928UzZhTp4pr2vWz1L+H99t7Pkln2QSPdvmURT0MoC4wUccfCnuEaihNsu9aYYyk+bep8rlfkUXw==} + vue-eslint-parser@10.4.0: + resolution: {integrity: sha512-Vxi9pJdbN3ZnVGLODVtZ7y4Y2kzAAE2Cm0CZ3ZDRvydVYxZ6VrnBhLikBsRS+dpwj4Jv4UCv21PTEwF5rQ9WXg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - eslint: ^8.57.0 || ^9.0.0 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - vue-i18n@11.2.2: - resolution: {integrity: sha512-ULIKZyRluUPRCZmihVgUvpq8hJTtOqnbGZuv4Lz+byEKZq4mU0g92og414l6f/4ju+L5mORsiUuEPYrAuX2NJg==} + vue-i18n@11.2.8: + resolution: {integrity: sha512-vJ123v/PXCZntd6Qj5Jumy7UBmIuE92VrtdX+AXr+1WzdBHojiBxnAxdfctUFL+/JIN+VQH4BhsfTtiGsvVObg==} engines: {node: '>= 16'} peerDependencies: vue: ^3.0.0 - vue-router@4.6.4: - resolution: {integrity: sha512-Hz9q5sa33Yhduglwz6g9skT8OBPii+4bFn88w6J+J4MfEo4KRRpmiNG/hHHkdbRFlLBOqxN8y8gf2Fb0MTUgVg==} + vue-router@5.0.3: + resolution: {integrity: sha512-nG1c7aAFac7NYj8Hluo68WyWfc41xkEjaR0ViLHCa3oDvTQ/nIuLJlXJX1NUPw/DXzx/8+OKMng045HHQKQKWw==} peerDependencies: + '@pinia/colada': '>=0.21.2' + '@vue/compiler-sfc': ^3.5.17 + pinia: ^3.0.4 vue: ^3.5.0 + peerDependenciesMeta: + '@pinia/colada': + optional: true + '@vue/compiler-sfc': + optional: true + pinia: + optional: true - vue-tsc@3.1.8: - resolution: {integrity: sha512-deKgwx6exIHeZwF601P1ktZKNF0bepaSN4jBU3AsbldPx9gylUc1JDxYppl82yxgkAgaz0Y0LCLOi+cXe9HMYA==} + vue-tsc@3.2.5: + resolution: {integrity: sha512-/htfTCMluQ+P2FISGAooul8kO4JMheOTCbCy4M6dYnYYjqLe3BExZudAua6MSIKSFYQtFOYAll7XobYwcpokGA==} hasBin: true peerDependencies: typescript: '>=5.0.0' - vue@3.5.25: - resolution: {integrity: sha512-YLVdgv2K13WJ6n+kD5owehKtEXwdwXuj2TTyJMsO7pSeKw2bfRNZGjhB7YzrpbMYj5b5QsUebHpOqR3R3ziy/g==} + vue@3.5.28: + resolution: {integrity: sha512-BRdrNfeoccSoIZeIhyPBfvWSLFP4q8J3u8Ju8Ug5vu3LdD+yTM13Sg4sKtljxozbnuMu1NB1X5HBHRYUzFocKg==} peerDependencies: typescript: '*' peerDependenciesMeta: @@ -3030,25 +3339,21 @@ packages: resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} engines: {node: '>=18'} - webidl-conversions@8.0.0: - resolution: {integrity: sha512-n4W4YFyz5JzOfQeA8oN7dUYpR+MBP3PIUsn2jLjWXwK5ASUzt0Jc/A5sAUZoCYFJRGF0FBKJ+1JjN43rNdsQzA==} + webidl-conversions@8.0.1: + resolution: {integrity: sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==} engines: {node: '>=20'} webpack-virtual-modules@0.6.2: resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==} - whatwg-encoding@3.1.1: - resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} - engines: {node: '>=18'} - - whatwg-mimetype@4.0.0: - resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} - engines: {node: '>=18'} - - whatwg-url@15.1.0: - resolution: {integrity: sha512-2ytDk0kiEj/yu90JOAp44PVPUkO9+jVhyf+SybKlRHSDlvOOZhdPIrr7xTH64l4WixO2cP+wQIcgujkGBPPz6g==} + whatwg-mimetype@5.0.0: + resolution: {integrity: sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==} engines: {node: '>=20'} + whatwg-url@16.0.1: + resolution: {integrity: sha512-1to4zXBxmXHV3IiSSEInrreIlu02vUOvrhxJJH5vcxYTBDAx51cqZiKdyTxlecdKNSjj8EcxGBxNf6Vg+945gw==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} @@ -3074,18 +3379,6 @@ packages: wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - ws@8.18.3: - resolution: {integrity: sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==} - engines: {node: '>=10.0.0'} - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: '>=5.0.2' - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - xml-name-validator@4.0.0: resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==} engines: {node: '>=12'} @@ -3104,6 +3397,10 @@ packages: resolution: {integrity: sha512-odxVsHAkZYYglR30aPYRY4nUGJnoJ2y1ww2HDvZALo0BDETv9kWbi16J52eHs+PWRNmF4ub6nZqfVOeesOvntg==} engines: {node: ^14.17.0 || >=16.0.0} + yaml-eslint-parser@2.0.0: + resolution: {integrity: sha512-h0uDm97wvT2bokfwwTmY6kJ1hp6YDFL0nRHwNKz8s/VD1FH/vvZjAKoMUE+un0eaYBSG7/c6h+lJTP+31tjgTw==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + yaml@2.8.2: resolution: {integrity: sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==} engines: {node: '>= 14.6'} @@ -3122,47 +3419,47 @@ packages: snapshots: - '@acemir/cssom@0.9.29': {} + '@acemir/cssom@0.9.31': {} - '@antfu/eslint-config@6.7.1(@vue/compiler-sfc@3.5.25)(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)(vitest@4.0.15(@types/node@24.10.4)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(stylus@0.57.0)(yaml@2.8.2))': + '@antfu/eslint-config@7.4.3(@vue/compiler-sfc@3.5.28)(eslint@10.0.1(jiti@2.6.1))(typescript@5.9.3)(vitest@4.0.18(@types/node@24.10.13)(jiti@2.6.1)(jsdom@28.1.0)(lightningcss@1.31.1)(stylus@0.57.0)(yaml@2.8.2))': dependencies: '@antfu/install-pkg': 1.1.0 - '@clack/prompts': 0.11.0 - '@eslint-community/eslint-plugin-eslint-comments': 4.5.0(eslint@9.39.2(jiti@2.6.1)) + '@clack/prompts': 1.0.1 + '@eslint-community/eslint-plugin-eslint-comments': 4.6.0(eslint@10.0.1(jiti@2.6.1)) '@eslint/markdown': 7.5.1 - '@stylistic/eslint-plugin': 5.6.1(eslint@9.39.2(jiti@2.6.1)) - '@typescript-eslint/eslint-plugin': 8.49.0(@typescript-eslint/parser@8.49.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/parser': 8.49.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@vitest/eslint-plugin': 1.5.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)(vitest@4.0.15(@types/node@24.10.4)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(stylus@0.57.0)(yaml@2.8.2)) + '@stylistic/eslint-plugin': 5.9.0(eslint@10.0.1(jiti@2.6.1)) + '@typescript-eslint/eslint-plugin': 8.56.0(@typescript-eslint/parser@8.56.0(eslint@10.0.1(jiti@2.6.1))(typescript@5.9.3))(eslint@10.0.1(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/parser': 8.56.0(eslint@10.0.1(jiti@2.6.1))(typescript@5.9.3) + '@vitest/eslint-plugin': 1.6.9(eslint@10.0.1(jiti@2.6.1))(typescript@5.9.3)(vitest@4.0.18(@types/node@24.10.13)(jiti@2.6.1)(jsdom@28.1.0)(lightningcss@1.31.1)(stylus@0.57.0)(yaml@2.8.2)) ansis: 4.2.0 cac: 6.7.14 - eslint: 9.39.2(jiti@2.6.1) - eslint-config-flat-gitignore: 2.1.0(eslint@9.39.2(jiti@2.6.1)) - eslint-flat-config-utils: 2.1.4 - eslint-merge-processors: 2.0.0(eslint@9.39.2(jiti@2.6.1)) - eslint-plugin-antfu: 3.1.1(eslint@9.39.2(jiti@2.6.1)) - eslint-plugin-command: 3.4.0(eslint@9.39.2(jiti@2.6.1)) - eslint-plugin-import-lite: 0.3.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - eslint-plugin-jsdoc: 61.5.0(eslint@9.39.2(jiti@2.6.1)) - eslint-plugin-jsonc: 2.21.0(eslint@9.39.2(jiti@2.6.1)) - eslint-plugin-n: 17.23.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + eslint: 10.0.1(jiti@2.6.1) + eslint-config-flat-gitignore: 2.2.1(eslint@10.0.1(jiti@2.6.1)) + eslint-flat-config-utils: 3.0.1 + eslint-merge-processors: 2.0.0(eslint@10.0.1(jiti@2.6.1)) + eslint-plugin-antfu: 3.2.2(eslint@10.0.1(jiti@2.6.1)) + eslint-plugin-command: 3.4.0(eslint@10.0.1(jiti@2.6.1)) + eslint-plugin-import-lite: 0.5.2(eslint@10.0.1(jiti@2.6.1)) + eslint-plugin-jsdoc: 62.7.0(eslint@10.0.1(jiti@2.6.1)) + eslint-plugin-jsonc: 2.21.1(eslint@10.0.1(jiti@2.6.1)) + eslint-plugin-n: 17.24.0(eslint@10.0.1(jiti@2.6.1))(typescript@5.9.3) eslint-plugin-no-only-tests: 3.3.0 - eslint-plugin-perfectionist: 4.15.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - eslint-plugin-pnpm: 1.4.3(eslint@9.39.2(jiti@2.6.1)) - eslint-plugin-regexp: 2.10.0(eslint@9.39.2(jiti@2.6.1)) - eslint-plugin-toml: 0.12.0(eslint@9.39.2(jiti@2.6.1)) - eslint-plugin-unicorn: 62.0.0(eslint@9.39.2(jiti@2.6.1)) - eslint-plugin-unused-imports: 4.3.0(@typescript-eslint/eslint-plugin@8.49.0(@typescript-eslint/parser@8.49.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)) - eslint-plugin-vue: 10.6.2(@stylistic/eslint-plugin@5.6.1(eslint@9.39.2(jiti@2.6.1)))(@typescript-eslint/parser@8.49.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(vue-eslint-parser@10.2.0(eslint@9.39.2(jiti@2.6.1))) - eslint-plugin-yml: 1.19.1(eslint@9.39.2(jiti@2.6.1)) - eslint-processor-vue-blocks: 2.0.0(@vue/compiler-sfc@3.5.25)(eslint@9.39.2(jiti@2.6.1)) - globals: 16.5.0 + eslint-plugin-perfectionist: 5.6.0(eslint@10.0.1(jiti@2.6.1))(typescript@5.9.3) + eslint-plugin-pnpm: 1.5.0(eslint@10.0.1(jiti@2.6.1)) + eslint-plugin-regexp: 3.0.0(eslint@10.0.1(jiti@2.6.1)) + eslint-plugin-toml: 1.1.2(eslint@10.0.1(jiti@2.6.1)) + eslint-plugin-unicorn: 63.0.0(eslint@10.0.1(jiti@2.6.1)) + eslint-plugin-unused-imports: 4.4.1(@typescript-eslint/eslint-plugin@8.56.0(@typescript-eslint/parser@8.56.0(eslint@10.0.1(jiti@2.6.1))(typescript@5.9.3))(eslint@10.0.1(jiti@2.6.1))(typescript@5.9.3))(eslint@10.0.1(jiti@2.6.1)) + eslint-plugin-vue: 10.8.0(@stylistic/eslint-plugin@5.9.0(eslint@10.0.1(jiti@2.6.1)))(@typescript-eslint/parser@8.56.0(eslint@10.0.1(jiti@2.6.1))(typescript@5.9.3))(eslint@10.0.1(jiti@2.6.1))(vue-eslint-parser@10.4.0(eslint@10.0.1(jiti@2.6.1))) + eslint-plugin-yml: 3.2.2(eslint@10.0.1(jiti@2.6.1)) + eslint-processor-vue-blocks: 2.0.0(@vue/compiler-sfc@3.5.28)(eslint@10.0.1(jiti@2.6.1)) + globals: 17.3.0 jsonc-eslint-parser: 2.4.2 local-pkg: 1.1.2 parse-gitignore: 2.0.0 - toml-eslint-parser: 0.10.1 - vue-eslint-parser: 10.2.0(eslint@9.39.2(jiti@2.6.1)) - yaml-eslint-parser: 1.3.2 + toml-eslint-parser: 1.0.3 + vue-eslint-parser: 10.4.0(eslint@10.0.1(jiti@2.6.1)) + yaml-eslint-parser: 2.0.0 transitivePeerDependencies: - '@eslint/json' - '@vue/compiler-sfc' @@ -3175,83 +3472,83 @@ snapshots: package-manager-detector: 1.6.0 tinyexec: 1.0.2 - '@asamuzakjp/css-color@4.1.0': + '@asamuzakjp/css-color@5.0.0': dependencies: - '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) - '@csstools/css-color-parser': 3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) - '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) - '@csstools/css-tokenizer': 3.0.4 - lru-cache: 11.2.4 + '@csstools/css-calc': 3.1.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-color-parser': 4.0.2(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + lru-cache: 11.2.6 - '@asamuzakjp/dom-selector@6.7.6': + '@asamuzakjp/dom-selector@6.8.1': dependencies: '@asamuzakjp/nwsapi': 2.3.9 bidi-js: 1.0.3 css-tree: 3.1.0 is-potential-custom-element-name: 1.0.1 - lru-cache: 11.2.4 + lru-cache: 11.2.6 '@asamuzakjp/nwsapi@2.3.9': {} - '@babel/code-frame@7.27.1': + '@babel/code-frame@7.29.0': dependencies: '@babel/helper-validator-identifier': 7.28.5 js-tokens: 4.0.0 picocolors: 1.1.1 - '@babel/compat-data@7.28.5': {} + '@babel/compat-data@7.29.0': {} - '@babel/core@7.28.5': + '@babel/core@7.29.0': dependencies: - '@babel/code-frame': 7.27.1 - '@babel/generator': 7.28.5 - '@babel/helper-compilation-targets': 7.27.2 - '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5) - '@babel/helpers': 7.28.4 - '@babel/parser': 7.28.5 - '@babel/template': 7.27.2 - '@babel/traverse': 7.28.5 - '@babel/types': 7.28.5 + '@babel/code-frame': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) + '@babel/helpers': 7.28.6 + '@babel/parser': 7.29.0 + '@babel/template': 7.28.6 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 '@jridgewell/remapping': 2.3.5 convert-source-map: 2.0.0 debug: 4.4.3 gensync: 1.0.0-beta.2 json5: 2.2.3 - semver: 7.7.3 + semver: 7.7.4 transitivePeerDependencies: - supports-color - '@babel/generator@7.28.5': + '@babel/generator@7.29.1': dependencies: - '@babel/parser': 7.28.5 - '@babel/types': 7.28.5 + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 '@jridgewell/gen-mapping': 0.3.13 '@jridgewell/trace-mapping': 0.3.31 jsesc: 3.1.0 - '@babel/helper-compilation-targets@7.27.2': + '@babel/helper-compilation-targets@7.28.6': dependencies: - '@babel/compat-data': 7.28.5 + '@babel/compat-data': 7.29.0 '@babel/helper-validator-option': 7.27.1 browserslist: 4.28.1 lru-cache: 5.1.1 - semver: 7.7.3 + semver: 7.7.4 '@babel/helper-globals@7.28.0': {} - '@babel/helper-module-imports@7.27.1': + '@babel/helper-module-imports@7.28.6': dependencies: - '@babel/traverse': 7.28.5 - '@babel/types': 7.28.5 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 transitivePeerDependencies: - supports-color - '@babel/helper-module-transforms@7.28.3(@babel/core@7.28.5)': + '@babel/helper-module-transforms@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-module-imports': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-module-imports': 7.28.6 '@babel/helper-validator-identifier': 7.28.5 - '@babel/traverse': 7.28.5 + '@babel/traverse': 7.29.0 transitivePeerDependencies: - supports-color @@ -3261,48 +3558,52 @@ snapshots: '@babel/helper-validator-option@7.27.1': {} - '@babel/helpers@7.28.4': + '@babel/helpers@7.28.6': dependencies: - '@babel/template': 7.27.2 - '@babel/types': 7.28.5 + '@babel/template': 7.28.6 + '@babel/types': 7.29.0 - '@babel/parser@7.28.5': + '@babel/parser@7.29.0': dependencies: - '@babel/types': 7.28.5 + '@babel/types': 7.29.0 - '@babel/runtime@7.28.4': {} + '@babel/runtime@7.28.6': {} - '@babel/template@7.27.2': + '@babel/template@7.28.6': dependencies: - '@babel/code-frame': 7.27.1 - '@babel/parser': 7.28.5 - '@babel/types': 7.28.5 + '@babel/code-frame': 7.29.0 + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 - '@babel/traverse@7.28.5': + '@babel/traverse@7.29.0': dependencies: - '@babel/code-frame': 7.27.1 - '@babel/generator': 7.28.5 + '@babel/code-frame': 7.29.0 + '@babel/generator': 7.29.1 '@babel/helper-globals': 7.28.0 - '@babel/parser': 7.28.5 - '@babel/template': 7.27.2 - '@babel/types': 7.28.5 + '@babel/parser': 7.29.0 + '@babel/template': 7.28.6 + '@babel/types': 7.29.0 debug: 4.4.3 transitivePeerDependencies: - supports-color - '@babel/types@7.28.5': + '@babel/types@7.29.0': dependencies: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.28.5 - '@clack/core@0.5.0': + '@bramus/specificity@2.4.2': + dependencies: + css-tree: 3.1.0 + + '@clack/core@1.0.1': dependencies: picocolors: 1.1.1 sisteransi: 1.0.5 - '@clack/prompts@0.11.0': + '@clack/prompts@1.0.1': dependencies: - '@clack/core': 0.5.0 + '@clack/core': 1.0.1 picocolors: 1.1.1 sisteransi: 1.0.5 @@ -3310,183 +3611,265 @@ snapshots: dependencies: '@jridgewell/trace-mapping': 0.3.9 - '@csstools/color-helpers@5.1.0': {} + '@csstools/color-helpers@6.0.2': {} - '@csstools/css-calc@2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)': + '@csstools/css-calc@3.1.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': dependencies: - '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) - '@csstools/css-tokenizer': 3.0.4 + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 - '@csstools/css-color-parser@3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)': + '@csstools/css-color-parser@4.0.2(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': dependencies: - '@csstools/color-helpers': 5.1.0 - '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) - '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) - '@csstools/css-tokenizer': 3.0.4 + '@csstools/color-helpers': 6.0.2 + '@csstools/css-calc': 3.1.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 - '@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4)': + '@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0)': dependencies: - '@csstools/css-tokenizer': 3.0.4 + '@csstools/css-tokenizer': 4.0.0 - '@csstools/css-syntax-patches-for-csstree@1.0.14(postcss@8.5.6)': - dependencies: - postcss: 8.5.6 + '@csstools/css-syntax-patches-for-csstree@1.0.28': {} - '@csstools/css-tokenizer@3.0.4': {} - - '@es-joy/jsdoccomment@0.76.0': - dependencies: - '@types/estree': 1.0.8 - '@typescript-eslint/types': 8.49.0 - comment-parser: 1.4.1 - esquery: 1.6.0 - jsdoc-type-pratt-parser: 6.10.0 + '@csstools/css-tokenizer@4.0.0': {} '@es-joy/jsdoccomment@0.78.0': dependencies: '@types/estree': 1.0.8 - '@typescript-eslint/types': 8.49.0 + '@typescript-eslint/types': 8.56.0 comment-parser: 1.4.1 - esquery: 1.6.0 + esquery: 1.7.0 jsdoc-type-pratt-parser: 7.0.0 + '@es-joy/jsdoccomment@0.84.0': + dependencies: + '@types/estree': 1.0.8 + '@typescript-eslint/types': 8.56.0 + comment-parser: 1.4.5 + esquery: 1.7.0 + jsdoc-type-pratt-parser: 7.1.1 + '@es-joy/resolve.exports@1.2.0': {} '@esbuild/aix-ppc64@0.25.12': optional: true + '@esbuild/aix-ppc64@0.27.3': + optional: true + '@esbuild/android-arm64@0.25.12': optional: true + '@esbuild/android-arm64@0.27.3': + optional: true + '@esbuild/android-arm@0.25.12': optional: true + '@esbuild/android-arm@0.27.3': + optional: true + '@esbuild/android-x64@0.25.12': optional: true + '@esbuild/android-x64@0.27.3': + optional: true + '@esbuild/darwin-arm64@0.25.12': optional: true + '@esbuild/darwin-arm64@0.27.3': + optional: true + '@esbuild/darwin-x64@0.25.12': optional: true + '@esbuild/darwin-x64@0.27.3': + optional: true + '@esbuild/freebsd-arm64@0.25.12': optional: true + '@esbuild/freebsd-arm64@0.27.3': + optional: true + '@esbuild/freebsd-x64@0.25.12': optional: true + '@esbuild/freebsd-x64@0.27.3': + optional: true + '@esbuild/linux-arm64@0.25.12': optional: true + '@esbuild/linux-arm64@0.27.3': + optional: true + '@esbuild/linux-arm@0.25.12': optional: true + '@esbuild/linux-arm@0.27.3': + optional: true + '@esbuild/linux-ia32@0.25.12': optional: true + '@esbuild/linux-ia32@0.27.3': + optional: true + '@esbuild/linux-loong64@0.25.12': optional: true + '@esbuild/linux-loong64@0.27.3': + optional: true + '@esbuild/linux-mips64el@0.25.12': optional: true + '@esbuild/linux-mips64el@0.27.3': + optional: true + '@esbuild/linux-ppc64@0.25.12': optional: true + '@esbuild/linux-ppc64@0.27.3': + optional: true + '@esbuild/linux-riscv64@0.25.12': optional: true + '@esbuild/linux-riscv64@0.27.3': + optional: true + '@esbuild/linux-s390x@0.25.12': optional: true + '@esbuild/linux-s390x@0.27.3': + optional: true + '@esbuild/linux-x64@0.25.12': optional: true + '@esbuild/linux-x64@0.27.3': + optional: true + '@esbuild/netbsd-arm64@0.25.12': optional: true + '@esbuild/netbsd-arm64@0.27.3': + optional: true + '@esbuild/netbsd-x64@0.25.12': optional: true + '@esbuild/netbsd-x64@0.27.3': + optional: true + '@esbuild/openbsd-arm64@0.25.12': optional: true + '@esbuild/openbsd-arm64@0.27.3': + optional: true + '@esbuild/openbsd-x64@0.25.12': optional: true + '@esbuild/openbsd-x64@0.27.3': + optional: true + '@esbuild/openharmony-arm64@0.25.12': optional: true + '@esbuild/openharmony-arm64@0.27.3': + optional: true + '@esbuild/sunos-x64@0.25.12': optional: true + '@esbuild/sunos-x64@0.27.3': + optional: true + '@esbuild/win32-arm64@0.25.12': optional: true + '@esbuild/win32-arm64@0.27.3': + optional: true + '@esbuild/win32-ia32@0.25.12': optional: true + '@esbuild/win32-ia32@0.27.3': + optional: true + '@esbuild/win32-x64@0.25.12': optional: true - '@eslint-community/eslint-plugin-eslint-comments@4.5.0(eslint@9.39.2(jiti@2.6.1))': + '@esbuild/win32-x64@0.27.3': + optional: true + + '@eslint-community/eslint-plugin-eslint-comments@4.6.0(eslint@10.0.1(jiti@2.6.1))': dependencies: escape-string-regexp: 4.0.0 - eslint: 9.39.2(jiti@2.6.1) - ignore: 5.3.2 + eslint: 10.0.1(jiti@2.6.1) + ignore: 7.0.5 - '@eslint-community/eslint-utils@4.9.0(eslint@9.39.2(jiti@2.6.1))': + '@eslint-community/eslint-utils@4.9.1(eslint@10.0.1(jiti@2.6.1))': dependencies: - eslint: 9.39.2(jiti@2.6.1) + eslint: 10.0.1(jiti@2.6.1) eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.2': {} - '@eslint/compat@1.4.1(eslint@9.39.2(jiti@2.6.1))': + '@eslint/compat@2.0.2(eslint@10.0.1(jiti@2.6.1))': dependencies: - '@eslint/core': 0.17.0 + '@eslint/core': 1.1.0 optionalDependencies: - eslint: 9.39.2(jiti@2.6.1) + eslint: 10.0.1(jiti@2.6.1) - '@eslint/config-array@0.21.1': + '@eslint/config-array@0.23.2': dependencies: - '@eslint/object-schema': 2.1.7 + '@eslint/object-schema': 3.0.2 debug: 4.4.3 - minimatch: 3.1.2 + minimatch: 10.2.2 transitivePeerDependencies: - supports-color - '@eslint/config-helpers@0.4.2': + '@eslint/config-helpers@0.5.2': dependencies: - '@eslint/core': 0.17.0 + '@eslint/core': 1.1.0 '@eslint/core@0.17.0': dependencies: '@types/json-schema': 7.0.15 + '@eslint/core@1.1.0': + dependencies: + '@types/json-schema': 7.0.15 + '@eslint/eslintrc@3.3.3': dependencies: - ajv: 6.12.6 + ajv: 6.14.0 debug: 4.4.3 espree: 10.4.0 globals: 14.0.0 ignore: 5.3.2 import-fresh: 3.3.1 js-yaml: 4.1.1 - minimatch: 3.1.2 + minimatch: 3.1.3 strip-json-comments: 3.1.1 transitivePeerDependencies: - supports-color - '@eslint/js@9.39.2': {} + '@eslint/js@10.0.1(eslint@10.0.1(jiti@2.6.1))': + optionalDependencies: + eslint: 10.0.1(jiti@2.6.1) '@eslint/markdown@7.5.1': dependencies: '@eslint/core': 0.17.0 '@eslint/plugin-kit': 0.4.1 github-slugger: 2.0.0 - mdast-util-from-markdown: 2.0.2 + mdast-util-from-markdown: 2.0.3 mdast-util-frontmatter: 2.0.1 mdast-util-gfm: 3.1.0 micromark-extension-frontmatter: 2.0.0 @@ -3495,13 +3878,20 @@ snapshots: transitivePeerDependencies: - supports-color - '@eslint/object-schema@2.1.7': {} + '@eslint/object-schema@3.0.2': {} '@eslint/plugin-kit@0.4.1': dependencies: '@eslint/core': 0.17.0 levn: 0.4.1 + '@eslint/plugin-kit@0.6.0': + dependencies: + '@eslint/core': 1.1.0 + levn: 0.4.1 + + '@exodus/bytes@1.14.1': {} + '@humanfs/core@0.19.1': {} '@humanfs/node@0.16.7': @@ -3513,24 +3903,24 @@ snapshots: '@humanwhocodes/retry@0.4.3': {} - '@ianvs/prettier-plugin-sort-imports@4.7.0(@vue/compiler-sfc@3.5.25)(prettier@3.7.4)': + '@ianvs/prettier-plugin-sort-imports@4.7.1(@vue/compiler-sfc@3.5.28)(prettier@3.8.1)': dependencies: - '@babel/generator': 7.28.5 - '@babel/parser': 7.28.5 - '@babel/traverse': 7.28.5 - '@babel/types': 7.28.5 - prettier: 3.7.4 - semver: 7.7.3 + '@babel/generator': 7.29.1 + '@babel/parser': 7.29.0 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + prettier: 3.8.1 + semver: 7.7.4 optionalDependencies: - '@vue/compiler-sfc': 3.5.25 + '@vue/compiler-sfc': 3.5.28 transitivePeerDependencies: - supports-color - '@intlify/bundle-utils@11.0.3(vue-i18n@11.2.2(vue@3.5.25(typescript@5.9.3)))': + '@intlify/bundle-utils@11.0.7(vue-i18n@11.2.8(vue@3.5.28(typescript@5.9.3)))': dependencies: - '@intlify/message-compiler': 11.2.2 - '@intlify/shared': 11.2.2 - acorn: 8.15.0 + '@intlify/message-compiler': 11.2.8 + '@intlify/shared': 11.2.8 + acorn: 8.16.0 esbuild: 0.25.12 escodegen: 2.1.0 estree-walker: 2.0.2 @@ -3538,21 +3928,21 @@ snapshots: source-map-js: 1.2.1 yaml-eslint-parser: 1.3.2 optionalDependencies: - vue-i18n: 11.2.2(vue@3.5.25(typescript@5.9.3)) + vue-i18n: 11.2.8(vue@3.5.28(typescript@5.9.3)) - '@intlify/core-base@11.2.2': + '@intlify/core-base@11.2.8': dependencies: - '@intlify/message-compiler': 11.2.2 - '@intlify/shared': 11.2.2 + '@intlify/message-compiler': 11.2.8 + '@intlify/shared': 11.2.8 - '@intlify/eslint-plugin-vue-i18n@4.1.0(eslint@9.39.2(jiti@2.6.1))(jsonc-eslint-parser@2.4.2)(vue-eslint-parser@10.2.0(eslint@9.39.2(jiti@2.6.1)))(yaml-eslint-parser@1.3.2)': + '@intlify/eslint-plugin-vue-i18n@4.1.1(eslint@10.0.1(jiti@2.6.1))(jsonc-eslint-parser@2.4.2)(vue-eslint-parser@10.4.0(eslint@10.0.1(jiti@2.6.1)))(yaml-eslint-parser@2.0.0)': dependencies: '@eslint/eslintrc': 3.3.3 - '@intlify/core-base': 11.2.2 - '@intlify/message-compiler': 11.2.2 + '@intlify/core-base': 11.2.8 + '@intlify/message-compiler': 11.2.8 debug: 4.4.3 - eslint: 9.39.2(jiti@2.6.1) - eslint-compat-utils: 0.6.5(eslint@9.39.2(jiti@2.6.1)) + eslint: 10.0.1(jiti@2.6.1) + eslint-compat-utils: 0.6.5(eslint@10.0.1(jiti@2.6.1)) glob: 10.5.0 globals: 16.5.0 ignore: 7.0.5 @@ -3561,39 +3951,39 @@ snapshots: js-yaml: 4.1.1 json5: 2.2.3 jsonc-eslint-parser: 2.4.2 - lodash: 4.17.21 + lodash: 4.17.23 parse5: 7.3.0 - semver: 7.7.3 + semver: 7.7.4 synckit: 0.10.4 - vue-eslint-parser: 10.2.0(eslint@9.39.2(jiti@2.6.1)) - yaml-eslint-parser: 1.3.2 + vue-eslint-parser: 10.4.0(eslint@10.0.1(jiti@2.6.1)) + yaml-eslint-parser: 2.0.0 transitivePeerDependencies: - supports-color - '@intlify/message-compiler@11.2.2': + '@intlify/message-compiler@11.2.8': dependencies: - '@intlify/shared': 11.2.2 + '@intlify/shared': 11.2.8 source-map-js: 1.2.1 - '@intlify/shared@11.2.2': {} + '@intlify/shared@11.2.8': {} - '@intlify/unplugin-vue-i18n@11.0.3(@vue/compiler-dom@3.5.25)(eslint@9.39.2(jiti@2.6.1))(rollup@4.53.3)(typescript@5.9.3)(vue-i18n@11.2.2(vue@3.5.25(typescript@5.9.3)))(vue@3.5.25(typescript@5.9.3))': + '@intlify/unplugin-vue-i18n@11.0.7(@vue/compiler-dom@3.5.28)(eslint@10.0.1(jiti@2.6.1))(rollup@4.59.0)(typescript@5.9.3)(vue-i18n@11.2.8(vue@3.5.28(typescript@5.9.3)))(vue@3.5.28(typescript@5.9.3))': dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.2(jiti@2.6.1)) - '@intlify/bundle-utils': 11.0.3(vue-i18n@11.2.2(vue@3.5.25(typescript@5.9.3))) - '@intlify/shared': 11.2.2 - '@intlify/vue-i18n-extensions': 8.0.0(@intlify/shared@11.2.2)(@vue/compiler-dom@3.5.25)(vue-i18n@11.2.2(vue@3.5.25(typescript@5.9.3)))(vue@3.5.25(typescript@5.9.3)) - '@rollup/pluginutils': 5.3.0(rollup@4.53.3) - '@typescript-eslint/scope-manager': 8.49.0 - '@typescript-eslint/typescript-estree': 8.49.0(typescript@5.9.3) + '@eslint-community/eslint-utils': 4.9.1(eslint@10.0.1(jiti@2.6.1)) + '@intlify/bundle-utils': 11.0.7(vue-i18n@11.2.8(vue@3.5.28(typescript@5.9.3))) + '@intlify/shared': 11.2.8 + '@intlify/vue-i18n-extensions': 8.0.0(@intlify/shared@11.2.8)(@vue/compiler-dom@3.5.28)(vue-i18n@11.2.8(vue@3.5.28(typescript@5.9.3)))(vue@3.5.28(typescript@5.9.3)) + '@rollup/pluginutils': 5.3.0(rollup@4.59.0) + '@typescript-eslint/scope-manager': 8.56.0 + '@typescript-eslint/typescript-estree': 8.56.0(typescript@5.9.3) debug: 4.4.3 fast-glob: 3.3.3 pathe: 2.0.3 picocolors: 1.1.1 unplugin: 2.3.11 - vue: 3.5.25(typescript@5.9.3) + vue: 3.5.28(typescript@5.9.3) optionalDependencies: - vue-i18n: 11.2.2(vue@3.5.25(typescript@5.9.3)) + vue-i18n: 11.2.8(vue@3.5.28(typescript@5.9.3)) transitivePeerDependencies: - '@vue/compiler-dom' - eslint @@ -3601,14 +3991,14 @@ snapshots: - supports-color - typescript - '@intlify/vue-i18n-extensions@8.0.0(@intlify/shared@11.2.2)(@vue/compiler-dom@3.5.25)(vue-i18n@11.2.2(vue@3.5.25(typescript@5.9.3)))(vue@3.5.25(typescript@5.9.3))': + '@intlify/vue-i18n-extensions@8.0.0(@intlify/shared@11.2.8)(@vue/compiler-dom@3.5.28)(vue-i18n@11.2.8(vue@3.5.28(typescript@5.9.3)))(vue@3.5.28(typescript@5.9.3))': dependencies: - '@babel/parser': 7.28.5 + '@babel/parser': 7.29.0 optionalDependencies: - '@intlify/shared': 11.2.2 - '@vue/compiler-dom': 3.5.25 - vue: 3.5.25(typescript@5.9.3) - vue-i18n: 11.2.2(vue@3.5.25(typescript@5.9.3)) + '@intlify/shared': 11.2.8 + '@vue/compiler-dom': 3.5.28 + vue: 3.5.28(typescript@5.9.3) + vue-i18n: 11.2.8(vue@3.5.28(typescript@5.9.3)) '@isaacs/cliui@8.0.2': dependencies: @@ -3643,9 +4033,9 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 - '@kyvg/vue3-notification@3.4.2(vue@3.5.25(typescript@5.9.3))': + '@kyvg/vue3-notification@3.4.2(vue@3.5.28(typescript@5.9.3))': dependencies: - vue: 3.5.25(typescript@5.9.3) + vue: 3.5.28(typescript@5.9.3) '@mdi/js@7.4.47': {} @@ -3659,179 +4049,190 @@ snapshots: '@nodelib/fs.walk@1.2.8': dependencies: '@nodelib/fs.scandir': 2.1.5 - fastq: 1.19.1 + fastq: 1.20.1 '@one-ini/wasm@0.1.1': {} + '@ota-meshi/ast-token-store@0.3.0': {} + '@pkgjs/parseargs@0.11.0': optional: true '@pkgr/core@0.2.9': {} - '@rolldown/pluginutils@1.0.0-beta.53': {} + '@rolldown/pluginutils@1.0.0-rc.2': {} - '@rollup/pluginutils@5.3.0(rollup@4.53.3)': + '@rollup/pluginutils@5.3.0(rollup@4.59.0)': dependencies: '@types/estree': 1.0.8 estree-walker: 2.0.2 picomatch: 4.0.3 optionalDependencies: - rollup: 4.53.3 + rollup: 4.59.0 - '@rollup/rollup-android-arm-eabi@4.53.3': + '@rollup/rollup-android-arm-eabi@4.59.0': optional: true - '@rollup/rollup-android-arm64@4.53.3': + '@rollup/rollup-android-arm64@4.59.0': optional: true - '@rollup/rollup-darwin-arm64@4.53.3': + '@rollup/rollup-darwin-arm64@4.59.0': optional: true - '@rollup/rollup-darwin-x64@4.53.3': + '@rollup/rollup-darwin-x64@4.59.0': optional: true - '@rollup/rollup-freebsd-arm64@4.53.3': + '@rollup/rollup-freebsd-arm64@4.59.0': optional: true - '@rollup/rollup-freebsd-x64@4.53.3': + '@rollup/rollup-freebsd-x64@4.59.0': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.53.3': + '@rollup/rollup-linux-arm-gnueabihf@4.59.0': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.53.3': + '@rollup/rollup-linux-arm-musleabihf@4.59.0': optional: true - '@rollup/rollup-linux-arm64-gnu@4.53.3': + '@rollup/rollup-linux-arm64-gnu@4.59.0': optional: true - '@rollup/rollup-linux-arm64-musl@4.53.3': + '@rollup/rollup-linux-arm64-musl@4.59.0': optional: true - '@rollup/rollup-linux-loong64-gnu@4.53.3': + '@rollup/rollup-linux-loong64-gnu@4.59.0': optional: true - '@rollup/rollup-linux-ppc64-gnu@4.53.3': + '@rollup/rollup-linux-loong64-musl@4.59.0': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.53.3': + '@rollup/rollup-linux-ppc64-gnu@4.59.0': optional: true - '@rollup/rollup-linux-riscv64-musl@4.53.3': + '@rollup/rollup-linux-ppc64-musl@4.59.0': optional: true - '@rollup/rollup-linux-s390x-gnu@4.53.3': + '@rollup/rollup-linux-riscv64-gnu@4.59.0': optional: true - '@rollup/rollup-linux-x64-gnu@4.53.3': + '@rollup/rollup-linux-riscv64-musl@4.59.0': optional: true - '@rollup/rollup-linux-x64-musl@4.53.3': + '@rollup/rollup-linux-s390x-gnu@4.59.0': optional: true - '@rollup/rollup-openharmony-arm64@4.53.3': + '@rollup/rollup-linux-x64-gnu@4.59.0': optional: true - '@rollup/rollup-win32-arm64-msvc@4.53.3': + '@rollup/rollup-linux-x64-musl@4.59.0': optional: true - '@rollup/rollup-win32-ia32-msvc@4.53.3': + '@rollup/rollup-openbsd-x64@4.59.0': optional: true - '@rollup/rollup-win32-x64-gnu@4.53.3': + '@rollup/rollup-openharmony-arm64@4.59.0': optional: true - '@rollup/rollup-win32-x64-msvc@4.53.3': + '@rollup/rollup-win32-arm64-msvc@4.59.0': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.59.0': + optional: true + + '@rollup/rollup-win32-x64-gnu@4.59.0': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.59.0': optional: true '@sindresorhus/base62@1.0.0': {} '@sindresorhus/is@4.6.0': {} - '@standard-schema/spec@1.0.0': {} + '@standard-schema/spec@1.1.0': {} - '@stylistic/eslint-plugin@5.6.1(eslint@9.39.2(jiti@2.6.1))': + '@stylistic/eslint-plugin@5.9.0(eslint@10.0.1(jiti@2.6.1))': dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.2(jiti@2.6.1)) - '@typescript-eslint/types': 8.49.0 - eslint: 9.39.2(jiti@2.6.1) + '@eslint-community/eslint-utils': 4.9.1(eslint@10.0.1(jiti@2.6.1)) + '@typescript-eslint/types': 8.56.0 + eslint: 10.0.1(jiti@2.6.1) eslint-visitor-keys: 4.2.1 espree: 10.4.0 estraverse: 5.3.0 picomatch: 4.0.3 - '@tailwindcss/node@4.1.18': + '@tailwindcss/node@4.2.0': dependencies: '@jridgewell/remapping': 2.3.5 - enhanced-resolve: 5.18.4 + enhanced-resolve: 5.19.0 jiti: 2.6.1 - lightningcss: 1.30.2 + lightningcss: 1.31.1 magic-string: 0.30.21 source-map-js: 1.2.1 - tailwindcss: 4.1.18 + tailwindcss: 4.2.0 - '@tailwindcss/oxide-android-arm64@4.1.18': + '@tailwindcss/oxide-android-arm64@4.2.0': optional: true - '@tailwindcss/oxide-darwin-arm64@4.1.18': + '@tailwindcss/oxide-darwin-arm64@4.2.0': optional: true - '@tailwindcss/oxide-darwin-x64@4.1.18': + '@tailwindcss/oxide-darwin-x64@4.2.0': optional: true - '@tailwindcss/oxide-freebsd-x64@4.1.18': + '@tailwindcss/oxide-freebsd-x64@4.2.0': optional: true - '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.18': + '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.0': optional: true - '@tailwindcss/oxide-linux-arm64-gnu@4.1.18': + '@tailwindcss/oxide-linux-arm64-gnu@4.2.0': optional: true - '@tailwindcss/oxide-linux-arm64-musl@4.1.18': + '@tailwindcss/oxide-linux-arm64-musl@4.2.0': optional: true - '@tailwindcss/oxide-linux-x64-gnu@4.1.18': + '@tailwindcss/oxide-linux-x64-gnu@4.2.0': optional: true - '@tailwindcss/oxide-linux-x64-musl@4.1.18': + '@tailwindcss/oxide-linux-x64-musl@4.2.0': optional: true - '@tailwindcss/oxide-wasm32-wasi@4.1.18': + '@tailwindcss/oxide-wasm32-wasi@4.2.0': optional: true - '@tailwindcss/oxide-win32-arm64-msvc@4.1.18': + '@tailwindcss/oxide-win32-arm64-msvc@4.2.0': optional: true - '@tailwindcss/oxide-win32-x64-msvc@4.1.18': + '@tailwindcss/oxide-win32-x64-msvc@4.2.0': optional: true - '@tailwindcss/oxide@4.1.18': + '@tailwindcss/oxide@4.2.0': optionalDependencies: - '@tailwindcss/oxide-android-arm64': 4.1.18 - '@tailwindcss/oxide-darwin-arm64': 4.1.18 - '@tailwindcss/oxide-darwin-x64': 4.1.18 - '@tailwindcss/oxide-freebsd-x64': 4.1.18 - '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.18 - '@tailwindcss/oxide-linux-arm64-gnu': 4.1.18 - '@tailwindcss/oxide-linux-arm64-musl': 4.1.18 - '@tailwindcss/oxide-linux-x64-gnu': 4.1.18 - '@tailwindcss/oxide-linux-x64-musl': 4.1.18 - '@tailwindcss/oxide-wasm32-wasi': 4.1.18 - '@tailwindcss/oxide-win32-arm64-msvc': 4.1.18 - '@tailwindcss/oxide-win32-x64-msvc': 4.1.18 + '@tailwindcss/oxide-android-arm64': 4.2.0 + '@tailwindcss/oxide-darwin-arm64': 4.2.0 + '@tailwindcss/oxide-darwin-x64': 4.2.0 + '@tailwindcss/oxide-freebsd-x64': 4.2.0 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.2.0 + '@tailwindcss/oxide-linux-arm64-gnu': 4.2.0 + '@tailwindcss/oxide-linux-arm64-musl': 4.2.0 + '@tailwindcss/oxide-linux-x64-gnu': 4.2.0 + '@tailwindcss/oxide-linux-x64-musl': 4.2.0 + '@tailwindcss/oxide-wasm32-wasi': 4.2.0 + '@tailwindcss/oxide-win32-arm64-msvc': 4.2.0 + '@tailwindcss/oxide-win32-x64-msvc': 4.2.0 - '@tailwindcss/typography@0.5.19(tailwindcss@4.1.18)': + '@tailwindcss/typography@0.5.19(tailwindcss@4.2.0)': dependencies: postcss-selector-parser: 6.0.10 - tailwindcss: 4.1.18 + tailwindcss: 4.2.0 - '@tailwindcss/vite@4.1.18(vite@7.2.7(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(stylus@0.57.0)(yaml@2.8.2))': + '@tailwindcss/vite@4.2.0(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(stylus@0.57.0)(yaml@2.8.2))': dependencies: - '@tailwindcss/node': 4.1.18 - '@tailwindcss/oxide': 4.1.18 - tailwindcss: 4.1.18 - vite: 7.2.7(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(stylus@0.57.0)(yaml@2.8.2) + '@tailwindcss/node': 4.2.0 + '@tailwindcss/oxide': 4.2.0 + tailwindcss: 4.2.0 + vite: 7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(stylus@0.57.0)(yaml@2.8.2) '@trysound/sax@0.2.0': {} @@ -3854,11 +4255,13 @@ snapshots: '@types/deep-eql@4.0.2': {} + '@types/esrecurse@4.3.1': {} + '@types/estree@1.0.8': {} '@types/json-schema@7.0.15': {} - '@types/lodash@4.17.21': {} + '@types/lodash@4.17.23': {} '@types/mdast@4.0.4': dependencies: @@ -3866,11 +4269,11 @@ snapshots: '@types/ms@2.1.0': {} - '@types/node@24.10.4': + '@types/node@24.10.13': dependencies: undici-types: 7.16.0 - '@types/prismjs@1.26.5': {} + '@types/prismjs@1.26.6': {} '@types/semver@7.7.1': {} @@ -3883,194 +4286,204 @@ snapshots: '@types/web-bluetooth@0.0.21': {} - '@typescript-eslint/eslint-plugin@8.49.0(@typescript-eslint/parser@8.49.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/eslint-plugin@8.56.0(@typescript-eslint/parser@8.56.0(eslint@10.0.1(jiti@2.6.1))(typescript@5.9.3))(eslint@10.0.1(jiti@2.6.1))(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.49.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.49.0 - '@typescript-eslint/type-utils': 8.49.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/utils': 8.49.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.49.0 - eslint: 9.39.2(jiti@2.6.1) + '@typescript-eslint/parser': 8.56.0(eslint@10.0.1(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.56.0 + '@typescript-eslint/type-utils': 8.56.0(eslint@10.0.1(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/utils': 8.56.0(eslint@10.0.1(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.56.0 + eslint: 10.0.1(jiti@2.6.1) ignore: 7.0.5 natural-compare: 1.4.0 - ts-api-utils: 2.1.0(typescript@5.9.3) + ts-api-utils: 2.4.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.49.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/parser@8.56.0(eslint@10.0.1(jiti@2.6.1))(typescript@5.9.3)': dependencies: - '@typescript-eslint/scope-manager': 8.49.0 - '@typescript-eslint/types': 8.49.0 - '@typescript-eslint/typescript-estree': 8.49.0(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.49.0 + '@typescript-eslint/scope-manager': 8.56.0 + '@typescript-eslint/types': 8.56.0 + '@typescript-eslint/typescript-estree': 8.56.0(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.56.0 debug: 4.4.3 - eslint: 9.39.2(jiti@2.6.1) + eslint: 10.0.1(jiti@2.6.1) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.49.0(typescript@5.9.3)': + '@typescript-eslint/project-service@8.56.0(typescript@5.9.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.49.0(typescript@5.9.3) - '@typescript-eslint/types': 8.49.0 + '@typescript-eslint/tsconfig-utils': 8.56.0(typescript@5.9.3) + '@typescript-eslint/types': 8.56.0 debug: 4.4.3 typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@8.49.0': + '@typescript-eslint/scope-manager@8.56.0': dependencies: - '@typescript-eslint/types': 8.49.0 - '@typescript-eslint/visitor-keys': 8.49.0 + '@typescript-eslint/types': 8.56.0 + '@typescript-eslint/visitor-keys': 8.56.0 - '@typescript-eslint/tsconfig-utils@8.49.0(typescript@5.9.3)': + '@typescript-eslint/tsconfig-utils@8.56.0(typescript@5.9.3)': dependencies: typescript: 5.9.3 - '@typescript-eslint/type-utils@8.49.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/type-utils@8.56.0(eslint@10.0.1(jiti@2.6.1))(typescript@5.9.3)': dependencies: - '@typescript-eslint/types': 8.49.0 - '@typescript-eslint/typescript-estree': 8.49.0(typescript@5.9.3) - '@typescript-eslint/utils': 8.49.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/types': 8.56.0 + '@typescript-eslint/typescript-estree': 8.56.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.56.0(eslint@10.0.1(jiti@2.6.1))(typescript@5.9.3) debug: 4.4.3 - eslint: 9.39.2(jiti@2.6.1) - ts-api-utils: 2.1.0(typescript@5.9.3) + eslint: 10.0.1(jiti@2.6.1) + ts-api-utils: 2.4.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/types@8.49.0': {} + '@typescript-eslint/types@8.56.0': {} - '@typescript-eslint/typescript-estree@8.49.0(typescript@5.9.3)': + '@typescript-eslint/typescript-estree@8.56.0(typescript@5.9.3)': dependencies: - '@typescript-eslint/project-service': 8.49.0(typescript@5.9.3) - '@typescript-eslint/tsconfig-utils': 8.49.0(typescript@5.9.3) - '@typescript-eslint/types': 8.49.0 - '@typescript-eslint/visitor-keys': 8.49.0 + '@typescript-eslint/project-service': 8.56.0(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.56.0(typescript@5.9.3) + '@typescript-eslint/types': 8.56.0 + '@typescript-eslint/visitor-keys': 8.56.0 debug: 4.4.3 - minimatch: 9.0.5 - semver: 7.7.3 + minimatch: 9.0.6 + semver: 7.7.4 tinyglobby: 0.2.15 - ts-api-utils: 2.1.0(typescript@5.9.3) + ts-api-utils: 2.4.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.49.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/utils@8.56.0(eslint@10.0.1(jiti@2.6.1))(typescript@5.9.3)': dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.2(jiti@2.6.1)) - '@typescript-eslint/scope-manager': 8.49.0 - '@typescript-eslint/types': 8.49.0 - '@typescript-eslint/typescript-estree': 8.49.0(typescript@5.9.3) - eslint: 9.39.2(jiti@2.6.1) + '@eslint-community/eslint-utils': 4.9.1(eslint@10.0.1(jiti@2.6.1)) + '@typescript-eslint/scope-manager': 8.56.0 + '@typescript-eslint/types': 8.56.0 + '@typescript-eslint/typescript-estree': 8.56.0(typescript@5.9.3) + eslint: 10.0.1(jiti@2.6.1) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@8.49.0': + '@typescript-eslint/visitor-keys@8.56.0': dependencies: - '@typescript-eslint/types': 8.49.0 - eslint-visitor-keys: 4.2.1 + '@typescript-eslint/types': 8.56.0 + eslint-visitor-keys: 5.0.1 - '@vitejs/plugin-vue@6.0.3(vite@7.2.7(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(stylus@0.57.0)(yaml@2.8.2))(vue@3.5.25(typescript@5.9.3))': + '@vitejs/plugin-vue@6.0.4(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(stylus@0.57.0)(yaml@2.8.2))(vue@3.5.28(typescript@5.9.3))': dependencies: - '@rolldown/pluginutils': 1.0.0-beta.53 - vite: 7.2.7(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(stylus@0.57.0)(yaml@2.8.2) - vue: 3.5.25(typescript@5.9.3) + '@rolldown/pluginutils': 1.0.0-rc.2 + vite: 7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(stylus@0.57.0)(yaml@2.8.2) + vue: 3.5.28(typescript@5.9.3) - '@vitest/eslint-plugin@1.5.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)(vitest@4.0.15(@types/node@24.10.4)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(stylus@0.57.0)(yaml@2.8.2))': + '@vitest/eslint-plugin@1.6.9(eslint@10.0.1(jiti@2.6.1))(typescript@5.9.3)(vitest@4.0.18(@types/node@24.10.13)(jiti@2.6.1)(jsdom@28.1.0)(lightningcss@1.31.1)(stylus@0.57.0)(yaml@2.8.2))': dependencies: - '@typescript-eslint/scope-manager': 8.49.0 - '@typescript-eslint/utils': 8.49.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - eslint: 9.39.2(jiti@2.6.1) + '@typescript-eslint/scope-manager': 8.56.0 + '@typescript-eslint/utils': 8.56.0(eslint@10.0.1(jiti@2.6.1))(typescript@5.9.3) + eslint: 10.0.1(jiti@2.6.1) optionalDependencies: typescript: 5.9.3 - vitest: 4.0.15(@types/node@24.10.4)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(stylus@0.57.0)(yaml@2.8.2) + vitest: 4.0.18(@types/node@24.10.13)(jiti@2.6.1)(jsdom@28.1.0)(lightningcss@1.31.1)(stylus@0.57.0)(yaml@2.8.2) transitivePeerDependencies: - supports-color - '@vitest/expect@4.0.15': + '@vitest/expect@4.0.18': dependencies: - '@standard-schema/spec': 1.0.0 + '@standard-schema/spec': 1.1.0 '@types/chai': 5.2.3 - '@vitest/spy': 4.0.15 - '@vitest/utils': 4.0.15 - chai: 6.2.1 + '@vitest/spy': 4.0.18 + '@vitest/utils': 4.0.18 + chai: 6.2.2 tinyrainbow: 3.0.3 - '@vitest/mocker@4.0.15(vite@7.2.7(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(stylus@0.57.0)(yaml@2.8.2))': + '@vitest/mocker@4.0.18(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(stylus@0.57.0)(yaml@2.8.2))': dependencies: - '@vitest/spy': 4.0.15 + '@vitest/spy': 4.0.18 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 7.2.7(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(stylus@0.57.0)(yaml@2.8.2) + vite: 7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(stylus@0.57.0)(yaml@2.8.2) - '@vitest/pretty-format@4.0.15': + '@vitest/pretty-format@4.0.18': dependencies: tinyrainbow: 3.0.3 - '@vitest/runner@4.0.15': + '@vitest/runner@4.0.18': dependencies: - '@vitest/utils': 4.0.15 + '@vitest/utils': 4.0.18 pathe: 2.0.3 - '@vitest/snapshot@4.0.15': + '@vitest/snapshot@4.0.18': dependencies: - '@vitest/pretty-format': 4.0.15 + '@vitest/pretty-format': 4.0.18 magic-string: 0.30.21 pathe: 2.0.3 - '@vitest/spy@4.0.15': {} + '@vitest/spy@4.0.18': {} - '@vitest/utils@4.0.15': + '@vitest/utils@4.0.18': dependencies: - '@vitest/pretty-format': 4.0.15 + '@vitest/pretty-format': 4.0.18 tinyrainbow: 3.0.3 - '@volar/language-core@2.4.26': + '@volar/language-core@2.4.28': dependencies: - '@volar/source-map': 2.4.26 + '@volar/source-map': 2.4.28 - '@volar/source-map@2.4.26': {} + '@volar/source-map@2.4.28': {} - '@volar/typescript@2.4.26': + '@volar/typescript@2.4.28': dependencies: - '@volar/language-core': 2.4.26 + '@volar/language-core': 2.4.28 path-browserify: 1.0.1 vscode-uri: 3.1.0 - '@vue/compiler-core@3.5.25': + '@vue-macros/common@3.1.2(vue@3.5.28(typescript@5.9.3))': dependencies: - '@babel/parser': 7.28.5 - '@vue/shared': 3.5.25 - entities: 4.5.0 + '@vue/compiler-sfc': 3.5.28 + ast-kit: 2.2.0 + local-pkg: 1.1.2 + magic-string-ast: 1.0.3 + unplugin-utils: 0.3.1 + optionalDependencies: + vue: 3.5.28(typescript@5.9.3) + + '@vue/compiler-core@3.5.28': + dependencies: + '@babel/parser': 7.29.0 + '@vue/shared': 3.5.28 + entities: 7.0.1 estree-walker: 2.0.2 source-map-js: 1.2.1 - '@vue/compiler-dom@3.5.25': + '@vue/compiler-dom@3.5.28': dependencies: - '@vue/compiler-core': 3.5.25 - '@vue/shared': 3.5.25 + '@vue/compiler-core': 3.5.28 + '@vue/shared': 3.5.28 - '@vue/compiler-sfc@3.5.25': + '@vue/compiler-sfc@3.5.28': dependencies: - '@babel/parser': 7.28.5 - '@vue/compiler-core': 3.5.25 - '@vue/compiler-dom': 3.5.25 - '@vue/compiler-ssr': 3.5.25 - '@vue/shared': 3.5.25 + '@babel/parser': 7.29.0 + '@vue/compiler-core': 3.5.28 + '@vue/compiler-dom': 3.5.28 + '@vue/compiler-ssr': 3.5.28 + '@vue/shared': 3.5.28 estree-walker: 2.0.2 magic-string: 0.30.21 postcss: 8.5.6 source-map-js: 1.2.1 - '@vue/compiler-ssr@3.5.25': + '@vue/compiler-ssr@3.5.28': dependencies: - '@vue/compiler-dom': 3.5.25 - '@vue/shared': 3.5.25 + '@vue/compiler-dom': 3.5.28 + '@vue/shared': 3.5.28 '@vue/devtools-api@6.6.4': {} @@ -4078,6 +4491,10 @@ snapshots: dependencies: '@vue/devtools-kit': 7.7.9 + '@vue/devtools-api@8.0.6': + dependencies: + '@vue/devtools-kit': 8.0.6 + '@vue/devtools-kit@7.7.9': dependencies: '@vue/devtools-shared': 7.7.9 @@ -4088,86 +4505,98 @@ snapshots: speakingurl: 14.0.1 superjson: 2.2.6 + '@vue/devtools-kit@8.0.6': + dependencies: + '@vue/devtools-shared': 8.0.6 + birpc: 2.9.0 + hookable: 5.5.3 + mitt: 3.0.1 + perfect-debounce: 2.1.0 + speakingurl: 14.0.1 + superjson: 2.2.6 + '@vue/devtools-shared@7.7.9': dependencies: rfdc: 1.4.1 - '@vue/language-core@3.1.8(typescript@5.9.3)': + '@vue/devtools-shared@8.0.6': dependencies: - '@volar/language-core': 2.4.26 - '@vue/compiler-dom': 3.5.25 - '@vue/shared': 3.5.25 - alien-signals: 3.1.1 + rfdc: 1.4.1 + + '@vue/language-core@3.2.5': + dependencies: + '@volar/language-core': 2.4.28 + '@vue/compiler-dom': 3.5.28 + '@vue/shared': 3.5.28 + alien-signals: 3.1.2 muggle-string: 0.4.1 path-browserify: 1.0.1 picomatch: 4.0.3 - optionalDependencies: - typescript: 5.9.3 - '@vue/reactivity@3.5.25': + '@vue/reactivity@3.5.28': dependencies: - '@vue/shared': 3.5.25 + '@vue/shared': 3.5.28 - '@vue/runtime-core@3.5.25': + '@vue/runtime-core@3.5.28': dependencies: - '@vue/reactivity': 3.5.25 - '@vue/shared': 3.5.25 + '@vue/reactivity': 3.5.28 + '@vue/shared': 3.5.28 - '@vue/runtime-dom@3.5.25': + '@vue/runtime-dom@3.5.28': dependencies: - '@vue/reactivity': 3.5.25 - '@vue/runtime-core': 3.5.25 - '@vue/shared': 3.5.25 + '@vue/reactivity': 3.5.28 + '@vue/runtime-core': 3.5.28 + '@vue/shared': 3.5.28 csstype: 3.2.3 - '@vue/server-renderer@3.5.25(vue@3.5.25(typescript@5.9.3))': + '@vue/server-renderer@3.5.28(vue@3.5.28(typescript@5.9.3))': dependencies: - '@vue/compiler-ssr': 3.5.25 - '@vue/shared': 3.5.25 - vue: 3.5.25(typescript@5.9.3) + '@vue/compiler-ssr': 3.5.28 + '@vue/shared': 3.5.28 + vue: 3.5.28(typescript@5.9.3) - '@vue/shared@3.5.25': {} + '@vue/shared@3.5.28': {} '@vue/test-utils@2.4.6': dependencies: js-beautify: 1.15.4 vue-component-type-helpers: 2.2.12 - '@vueuse/core@14.1.0(vue@3.5.25(typescript@5.9.3))': + '@vueuse/core@14.2.1(vue@3.5.28(typescript@5.9.3))': dependencies: '@types/web-bluetooth': 0.0.21 - '@vueuse/metadata': 14.1.0 - '@vueuse/shared': 14.1.0(vue@3.5.25(typescript@5.9.3)) - vue: 3.5.25(typescript@5.9.3) + '@vueuse/metadata': 14.2.1 + '@vueuse/shared': 14.2.1(vue@3.5.28(typescript@5.9.3)) + vue: 3.5.28(typescript@5.9.3) - '@vueuse/metadata@14.1.0': {} + '@vueuse/metadata@14.2.1': {} - '@vueuse/shared@14.1.0(vue@3.5.25(typescript@5.9.3))': + '@vueuse/shared@14.2.1(vue@3.5.28(typescript@5.9.3))': dependencies: - vue: 3.5.25(typescript@5.9.3) + vue: 3.5.28(typescript@5.9.3) abbrev@2.0.0: {} - acorn-jsx@5.3.2(acorn@8.15.0): + acorn-jsx@5.3.2(acorn@8.16.0): dependencies: - acorn: 8.15.0 + acorn: 8.16.0 - acorn-walk@8.3.4: + acorn-walk@8.3.5: dependencies: - acorn: 8.15.0 + acorn: 8.16.0 - acorn@8.15.0: {} + acorn@8.16.0: {} agent-base@7.1.4: {} - ajv@6.12.6: + ajv@6.14.0: dependencies: fast-deep-equal: 3.1.3 fast-json-stable-stringify: 2.1.0 json-schema-traverse: 0.4.1 uri-js: 4.4.1 - alien-signals@3.1.1: {} + alien-signals@3.1.2: {} ansi-regex@5.0.1: {} @@ -4191,6 +4620,16 @@ snapshots: assertion-error@2.0.1: {} + ast-kit@2.2.0: + dependencies: + '@babel/parser': 7.29.0 + pathe: 2.0.3 + + ast-walker-scope@0.8.3: + dependencies: + '@babel/parser': 7.29.0 + ast-kit: 2.2.0 + atob@2.1.2: {} babel-plugin-prismjs@2.1.0(prismjs@1.30.0): @@ -4199,7 +4638,9 @@ snapshots: balanced-match@1.0.2: {} - baseline-browser-mapping@2.9.7: {} + balanced-match@4.0.4: {} + + baseline-browser-mapping@2.10.0: {} bidi-js@1.0.3: dependencies: @@ -4218,17 +4659,21 @@ snapshots: dependencies: balanced-match: 1.0.2 + brace-expansion@5.0.3: + dependencies: + balanced-match: 4.0.4 + braces@3.0.3: dependencies: fill-range: 7.1.1 browserslist@4.28.1: dependencies: - baseline-browser-mapping: 2.9.7 - caniuse-lite: 1.0.30001760 - electron-to-chromium: 1.5.267 + baseline-browser-mapping: 2.10.0 + caniuse-lite: 1.0.30001772 + electron-to-chromium: 1.5.302 node-releases: 2.0.27 - update-browserslist-db: 1.2.2(browserslist@4.28.1) + update-browserslist-db: 1.2.3(browserslist@4.28.1) builtin-modules@5.0.0: {} @@ -4236,16 +4681,11 @@ snapshots: callsites@3.1.0: {} - caniuse-lite@1.0.30001760: {} + caniuse-lite@1.0.30001772: {} ccount@2.0.1: {} - chai@6.2.1: {} - - chalk@4.1.2: - dependencies: - ansi-styles: 4.3.0 - supports-color: 7.2.0 + chai@6.2.2: {} change-case@5.4.4: {} @@ -4253,7 +4693,11 @@ snapshots: character-entities@2.0.2: {} - ci-info@4.3.1: {} + chokidar@5.0.0: + dependencies: + readdirp: 5.0.0 + + ci-info@4.4.0: {} clean-regexp@1.0.0: dependencies: @@ -4271,11 +4715,13 @@ snapshots: comment-parser@1.4.1: {} + comment-parser@1.4.5: {} + concat-map@0.0.1: {} confbox@0.1.8: {} - confbox@0.2.2: {} + confbox@0.2.4: {} config-chain@1.1.13: dependencies: @@ -4288,7 +4734,7 @@ snapshots: dependencies: is-what: 5.5.0 - core-js-compat@3.47.0: + core-js-compat@3.48.0: dependencies: browserslist: 4.28.1 @@ -4337,20 +4783,21 @@ snapshots: dependencies: css-tree: 2.2.1 - cssstyle@5.3.4(postcss@8.5.6): + cssstyle@6.1.0: dependencies: - '@asamuzakjp/css-color': 4.1.0 - '@csstools/css-syntax-patches-for-csstree': 1.0.14(postcss@8.5.6) + '@asamuzakjp/css-color': 5.0.0 + '@csstools/css-syntax-patches-for-csstree': 1.0.28 css-tree: 3.1.0 - transitivePeerDependencies: - - postcss + lru-cache: 11.2.6 csstype@3.2.3: {} - data-urls@6.0.0: + data-urls@7.0.0: dependencies: - whatwg-mimetype: 4.0.0 - whatwg-url: 15.1.0 + whatwg-mimetype: 5.0.0 + whatwg-url: 16.0.1 + transitivePeerDependencies: + - '@noble/hashes' debug@4.4.3: dependencies: @@ -4358,7 +4805,7 @@ snapshots: decimal.js@10.6.0: {} - decode-named-character-reference@1.2.0: + decode-named-character-reference@1.3.0: dependencies: character-entities: 2.0.2 @@ -4376,7 +4823,9 @@ snapshots: diff-sequences@27.5.1: {} - diff@4.0.2: {} + diff-sequences@29.6.3: {} + + diff@4.0.4: {} dom-serializer@2.0.0: dependencies: @@ -4400,7 +4849,7 @@ snapshots: domelementtype: 2.3.0 domhandler: 5.0.3 - dotenv@17.2.3: {} + dotenv@17.3.1: {} eastasianwidth@0.2.0: {} @@ -4409,9 +4858,9 @@ snapshots: '@one-ini/wasm': 0.1.1 commander: 10.0.1 minimatch: 9.0.1 - semver: 7.7.3 + semver: 7.7.4 - electron-to-chromium@1.5.267: {} + electron-to-chromium@1.5.302: {} emoji-regex@8.0.0: {} @@ -4421,7 +4870,7 @@ snapshots: empathic@2.0.0: {} - enhanced-resolve@5.18.4: + enhanced-resolve@5.19.0: dependencies: graceful-fs: 4.2.11 tapable: 2.3.0 @@ -4430,6 +4879,8 @@ snapshots: entities@6.0.1: {} + entities@7.0.1: {} + es-module-lexer@1.7.0: {} esbuild@0.25.12: @@ -4461,6 +4912,35 @@ snapshots: '@esbuild/win32-ia32': 0.25.12 '@esbuild/win32-x64': 0.25.12 + esbuild@0.27.3: + optionalDependencies: + '@esbuild/aix-ppc64': 0.27.3 + '@esbuild/android-arm': 0.27.3 + '@esbuild/android-arm64': 0.27.3 + '@esbuild/android-x64': 0.27.3 + '@esbuild/darwin-arm64': 0.27.3 + '@esbuild/darwin-x64': 0.27.3 + '@esbuild/freebsd-arm64': 0.27.3 + '@esbuild/freebsd-x64': 0.27.3 + '@esbuild/linux-arm': 0.27.3 + '@esbuild/linux-arm64': 0.27.3 + '@esbuild/linux-ia32': 0.27.3 + '@esbuild/linux-loong64': 0.27.3 + '@esbuild/linux-mips64el': 0.27.3 + '@esbuild/linux-ppc64': 0.27.3 + '@esbuild/linux-riscv64': 0.27.3 + '@esbuild/linux-s390x': 0.27.3 + '@esbuild/linux-x64': 0.27.3 + '@esbuild/netbsd-arm64': 0.27.3 + '@esbuild/netbsd-x64': 0.27.3 + '@esbuild/openbsd-arm64': 0.27.3 + '@esbuild/openbsd-x64': 0.27.3 + '@esbuild/openharmony-arm64': 0.27.3 + '@esbuild/sunos-x64': 0.27.3 + '@esbuild/win32-arm64': 0.27.3 + '@esbuild/win32-ia32': 0.27.3 + '@esbuild/win32-x64': 0.27.3 + escalade@3.2.0: {} escape-string-regexp@1.0.5: {} @@ -4477,169 +4957,164 @@ snapshots: optionalDependencies: source-map: 0.6.1 - eslint-compat-utils@0.5.1(eslint@9.39.2(jiti@2.6.1)): + eslint-compat-utils@0.5.1(eslint@10.0.1(jiti@2.6.1)): dependencies: - eslint: 9.39.2(jiti@2.6.1) - semver: 7.7.3 + eslint: 10.0.1(jiti@2.6.1) + semver: 7.7.4 - eslint-compat-utils@0.6.5(eslint@9.39.2(jiti@2.6.1)): + eslint-compat-utils@0.6.5(eslint@10.0.1(jiti@2.6.1)): dependencies: - eslint: 9.39.2(jiti@2.6.1) - semver: 7.7.3 + eslint: 10.0.1(jiti@2.6.1) + semver: 7.7.4 - eslint-config-flat-gitignore@2.1.0(eslint@9.39.2(jiti@2.6.1)): + eslint-config-flat-gitignore@2.2.1(eslint@10.0.1(jiti@2.6.1)): dependencies: - '@eslint/compat': 1.4.1(eslint@9.39.2(jiti@2.6.1)) - eslint: 9.39.2(jiti@2.6.1) + '@eslint/compat': 2.0.2(eslint@10.0.1(jiti@2.6.1)) + eslint: 10.0.1(jiti@2.6.1) - eslint-flat-config-utils@2.1.4: + eslint-flat-config-utils@3.0.1: dependencies: + '@eslint/config-helpers': 0.5.2 pathe: 2.0.3 - eslint-json-compat-utils@0.2.1(eslint@9.39.2(jiti@2.6.1))(jsonc-eslint-parser@2.4.2): + eslint-json-compat-utils@0.2.2(eslint@10.0.1(jiti@2.6.1))(jsonc-eslint-parser@2.4.2): dependencies: - eslint: 9.39.2(jiti@2.6.1) - esquery: 1.6.0 + eslint: 10.0.1(jiti@2.6.1) + esquery: 1.7.0 jsonc-eslint-parser: 2.4.2 - eslint-merge-processors@2.0.0(eslint@9.39.2(jiti@2.6.1)): + eslint-merge-processors@2.0.0(eslint@10.0.1(jiti@2.6.1)): dependencies: - eslint: 9.39.2(jiti@2.6.1) + eslint: 10.0.1(jiti@2.6.1) - eslint-plugin-antfu@3.1.1(eslint@9.39.2(jiti@2.6.1)): + eslint-plugin-antfu@3.2.2(eslint@10.0.1(jiti@2.6.1)): dependencies: - eslint: 9.39.2(jiti@2.6.1) + eslint: 10.0.1(jiti@2.6.1) - eslint-plugin-command@3.4.0(eslint@9.39.2(jiti@2.6.1)): + eslint-plugin-command@3.4.0(eslint@10.0.1(jiti@2.6.1)): dependencies: '@es-joy/jsdoccomment': 0.78.0 - eslint: 9.39.2(jiti@2.6.1) + eslint: 10.0.1(jiti@2.6.1) - eslint-plugin-es-x@7.8.0(eslint@9.39.2(jiti@2.6.1)): + eslint-plugin-es-x@7.8.0(eslint@10.0.1(jiti@2.6.1)): dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.2(jiti@2.6.1)) + '@eslint-community/eslint-utils': 4.9.1(eslint@10.0.1(jiti@2.6.1)) '@eslint-community/regexpp': 4.12.2 - eslint: 9.39.2(jiti@2.6.1) - eslint-compat-utils: 0.5.1(eslint@9.39.2(jiti@2.6.1)) + eslint: 10.0.1(jiti@2.6.1) + eslint-compat-utils: 0.5.1(eslint@10.0.1(jiti@2.6.1)) - eslint-plugin-import-lite@0.3.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3): + eslint-plugin-import-lite@0.5.2(eslint@10.0.1(jiti@2.6.1)): dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.2(jiti@2.6.1)) - '@typescript-eslint/types': 8.49.0 - eslint: 9.39.2(jiti@2.6.1) - optionalDependencies: - typescript: 5.9.3 + eslint: 10.0.1(jiti@2.6.1) - eslint-plugin-jsdoc@61.5.0(eslint@9.39.2(jiti@2.6.1)): + eslint-plugin-jsdoc@62.7.0(eslint@10.0.1(jiti@2.6.1)): dependencies: - '@es-joy/jsdoccomment': 0.76.0 + '@es-joy/jsdoccomment': 0.84.0 '@es-joy/resolve.exports': 1.2.0 are-docs-informative: 0.0.2 - comment-parser: 1.4.1 + comment-parser: 1.4.5 debug: 4.4.3 escape-string-regexp: 4.0.0 - eslint: 9.39.2(jiti@2.6.1) - espree: 10.4.0 - esquery: 1.6.0 + eslint: 10.0.1(jiti@2.6.1) + espree: 11.1.1 + esquery: 1.7.0 html-entities: 2.6.0 object-deep-merge: 2.0.0 parse-imports-exports: 0.2.4 - semver: 7.7.3 + semver: 7.7.4 spdx-expression-parse: 4.0.0 to-valid-identifier: 1.0.0 transitivePeerDependencies: - supports-color - eslint-plugin-jsonc@2.21.0(eslint@9.39.2(jiti@2.6.1)): + eslint-plugin-jsonc@2.21.1(eslint@10.0.1(jiti@2.6.1)): dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.2(jiti@2.6.1)) + '@eslint-community/eslint-utils': 4.9.1(eslint@10.0.1(jiti@2.6.1)) diff-sequences: 27.5.1 - eslint: 9.39.2(jiti@2.6.1) - eslint-compat-utils: 0.6.5(eslint@9.39.2(jiti@2.6.1)) - eslint-json-compat-utils: 0.2.1(eslint@9.39.2(jiti@2.6.1))(jsonc-eslint-parser@2.4.2) + eslint: 10.0.1(jiti@2.6.1) + eslint-compat-utils: 0.6.5(eslint@10.0.1(jiti@2.6.1)) + eslint-json-compat-utils: 0.2.2(eslint@10.0.1(jiti@2.6.1))(jsonc-eslint-parser@2.4.2) espree: 10.4.0 graphemer: 1.4.0 jsonc-eslint-parser: 2.4.2 natural-compare: 1.4.0 - synckit: 0.11.11 + synckit: 0.11.12 transitivePeerDependencies: - '@eslint/json' - eslint-plugin-n@17.23.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3): + eslint-plugin-n@17.24.0(eslint@10.0.1(jiti@2.6.1))(typescript@5.9.3): dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.2(jiti@2.6.1)) - enhanced-resolve: 5.18.4 - eslint: 9.39.2(jiti@2.6.1) - eslint-plugin-es-x: 7.8.0(eslint@9.39.2(jiti@2.6.1)) - get-tsconfig: 4.13.0 + '@eslint-community/eslint-utils': 4.9.1(eslint@10.0.1(jiti@2.6.1)) + enhanced-resolve: 5.19.0 + eslint: 10.0.1(jiti@2.6.1) + eslint-plugin-es-x: 7.8.0(eslint@10.0.1(jiti@2.6.1)) + get-tsconfig: 4.13.6 globals: 15.15.0 globrex: 0.1.2 ignore: 5.3.2 - semver: 7.7.3 + semver: 7.7.4 ts-declaration-location: 1.0.7(typescript@5.9.3) transitivePeerDependencies: - typescript eslint-plugin-no-only-tests@3.3.0: {} - eslint-plugin-perfectionist@4.15.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3): + eslint-plugin-perfectionist@5.6.0(eslint@10.0.1(jiti@2.6.1))(typescript@5.9.3): dependencies: - '@typescript-eslint/types': 8.49.0 - '@typescript-eslint/utils': 8.49.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - eslint: 9.39.2(jiti@2.6.1) + '@typescript-eslint/utils': 8.56.0(eslint@10.0.1(jiti@2.6.1))(typescript@5.9.3) + eslint: 10.0.1(jiti@2.6.1) natural-orderby: 5.0.0 transitivePeerDependencies: - supports-color - typescript - eslint-plugin-pnpm@1.4.3(eslint@9.39.2(jiti@2.6.1)): + eslint-plugin-pnpm@1.5.0(eslint@10.0.1(jiti@2.6.1)): dependencies: empathic: 2.0.0 - eslint: 9.39.2(jiti@2.6.1) + eslint: 10.0.1(jiti@2.6.1) jsonc-eslint-parser: 2.4.2 pathe: 2.0.3 - pnpm-workspace-yaml: 1.4.3 + pnpm-workspace-yaml: 1.5.0 tinyglobby: 0.2.15 yaml: 2.8.2 - yaml-eslint-parser: 1.3.2 + yaml-eslint-parser: 2.0.0 - eslint-plugin-promise@7.2.1(eslint@9.39.2(jiti@2.6.1)): + eslint-plugin-promise@7.2.1(eslint@10.0.1(jiti@2.6.1)): dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.2(jiti@2.6.1)) - eslint: 9.39.2(jiti@2.6.1) + '@eslint-community/eslint-utils': 4.9.1(eslint@10.0.1(jiti@2.6.1)) + eslint: 10.0.1(jiti@2.6.1) - eslint-plugin-regexp@2.10.0(eslint@9.39.2(jiti@2.6.1)): + eslint-plugin-regexp@3.0.0(eslint@10.0.1(jiti@2.6.1)): dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.2(jiti@2.6.1)) + '@eslint-community/eslint-utils': 4.9.1(eslint@10.0.1(jiti@2.6.1)) '@eslint-community/regexpp': 4.12.2 - comment-parser: 1.4.1 - eslint: 9.39.2(jiti@2.6.1) - jsdoc-type-pratt-parser: 4.8.0 + comment-parser: 1.4.5 + eslint: 10.0.1(jiti@2.6.1) + jsdoc-type-pratt-parser: 7.1.1 refa: 0.12.1 regexp-ast-analysis: 0.7.1 scslre: 0.3.0 - eslint-plugin-toml@0.12.0(eslint@9.39.2(jiti@2.6.1)): + eslint-plugin-toml@1.1.2(eslint@10.0.1(jiti@2.6.1)): dependencies: + '@eslint/core': 1.1.0 + '@eslint/plugin-kit': 0.6.0 + '@ota-meshi/ast-token-store': 0.3.0 debug: 4.4.3 - eslint: 9.39.2(jiti@2.6.1) - eslint-compat-utils: 0.6.5(eslint@9.39.2(jiti@2.6.1)) - lodash: 4.17.21 - toml-eslint-parser: 0.10.1 + eslint: 10.0.1(jiti@2.6.1) + toml-eslint-parser: 1.0.3 transitivePeerDependencies: - supports-color - eslint-plugin-unicorn@62.0.0(eslint@9.39.2(jiti@2.6.1)): + eslint-plugin-unicorn@63.0.0(eslint@10.0.1(jiti@2.6.1)): dependencies: '@babel/helper-validator-identifier': 7.28.5 - '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.2(jiti@2.6.1)) - '@eslint/plugin-kit': 0.4.1 + '@eslint-community/eslint-utils': 4.9.1(eslint@10.0.1(jiti@2.6.1)) change-case: 5.4.4 - ci-info: 4.3.1 + ci-info: 4.4.0 clean-regexp: 1.0.0 - core-js-compat: 3.47.0 - eslint: 9.39.2(jiti@2.6.1) - esquery: 1.6.0 + core-js-compat: 3.48.0 + eslint: 10.0.1(jiti@2.6.1) find-up-simple: 1.0.1 globals: 16.5.0 indent-string: 5.0.0 @@ -4648,63 +5123,67 @@ snapshots: pluralize: 8.0.0 regexp-tree: 0.1.27 regjsparser: 0.13.0 - semver: 7.7.3 + semver: 7.7.4 strip-indent: 4.1.1 - eslint-plugin-unused-imports@4.3.0(@typescript-eslint/eslint-plugin@8.49.0(@typescript-eslint/parser@8.49.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)): + eslint-plugin-unused-imports@4.4.1(@typescript-eslint/eslint-plugin@8.56.0(@typescript-eslint/parser@8.56.0(eslint@10.0.1(jiti@2.6.1))(typescript@5.9.3))(eslint@10.0.1(jiti@2.6.1))(typescript@5.9.3))(eslint@10.0.1(jiti@2.6.1)): dependencies: - eslint: 9.39.2(jiti@2.6.1) + eslint: 10.0.1(jiti@2.6.1) optionalDependencies: - '@typescript-eslint/eslint-plugin': 8.49.0(@typescript-eslint/parser@8.49.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/eslint-plugin': 8.56.0(@typescript-eslint/parser@8.56.0(eslint@10.0.1(jiti@2.6.1))(typescript@5.9.3))(eslint@10.0.1(jiti@2.6.1))(typescript@5.9.3) - eslint-plugin-vue-scoped-css@2.12.0(eslint@9.39.2(jiti@2.6.1))(vue-eslint-parser@10.2.0(eslint@9.39.2(jiti@2.6.1))): + eslint-plugin-vue-scoped-css@2.12.0(eslint@10.0.1(jiti@2.6.1))(vue-eslint-parser@10.4.0(eslint@10.0.1(jiti@2.6.1))): dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.2(jiti@2.6.1)) - eslint: 9.39.2(jiti@2.6.1) - eslint-compat-utils: 0.6.5(eslint@9.39.2(jiti@2.6.1)) - lodash: 4.17.21 + '@eslint-community/eslint-utils': 4.9.1(eslint@10.0.1(jiti@2.6.1)) + eslint: 10.0.1(jiti@2.6.1) + eslint-compat-utils: 0.6.5(eslint@10.0.1(jiti@2.6.1)) + lodash: 4.17.23 postcss: 8.5.6 postcss-safe-parser: 6.0.0(postcss@8.5.6) postcss-scss: 4.0.9(postcss@8.5.6) postcss-selector-parser: 7.1.1 postcss-styl: 0.12.3 - vue-eslint-parser: 10.2.0(eslint@9.39.2(jiti@2.6.1)) + vue-eslint-parser: 10.4.0(eslint@10.0.1(jiti@2.6.1)) transitivePeerDependencies: - supports-color - eslint-plugin-vue@10.6.2(@stylistic/eslint-plugin@5.6.1(eslint@9.39.2(jiti@2.6.1)))(@typescript-eslint/parser@8.49.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(vue-eslint-parser@10.2.0(eslint@9.39.2(jiti@2.6.1))): + eslint-plugin-vue@10.8.0(@stylistic/eslint-plugin@5.9.0(eslint@10.0.1(jiti@2.6.1)))(@typescript-eslint/parser@8.56.0(eslint@10.0.1(jiti@2.6.1))(typescript@5.9.3))(eslint@10.0.1(jiti@2.6.1))(vue-eslint-parser@10.4.0(eslint@10.0.1(jiti@2.6.1))): dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.2(jiti@2.6.1)) - eslint: 9.39.2(jiti@2.6.1) + '@eslint-community/eslint-utils': 4.9.1(eslint@10.0.1(jiti@2.6.1)) + eslint: 10.0.1(jiti@2.6.1) natural-compare: 1.4.0 nth-check: 2.1.1 postcss-selector-parser: 7.1.1 - semver: 7.7.3 - vue-eslint-parser: 10.2.0(eslint@9.39.2(jiti@2.6.1)) + semver: 7.7.4 + vue-eslint-parser: 10.4.0(eslint@10.0.1(jiti@2.6.1)) xml-name-validator: 4.0.0 optionalDependencies: - '@stylistic/eslint-plugin': 5.6.1(eslint@9.39.2(jiti@2.6.1)) - '@typescript-eslint/parser': 8.49.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@stylistic/eslint-plugin': 5.9.0(eslint@10.0.1(jiti@2.6.1)) + '@typescript-eslint/parser': 8.56.0(eslint@10.0.1(jiti@2.6.1))(typescript@5.9.3) - eslint-plugin-yml@1.19.1(eslint@9.39.2(jiti@2.6.1)): + eslint-plugin-yml@3.2.2(eslint@10.0.1(jiti@2.6.1)): dependencies: + '@eslint/core': 1.1.0 + '@eslint/plugin-kit': 0.6.0 + '@ota-meshi/ast-token-store': 0.3.0 debug: 4.4.3 - diff-sequences: 27.5.1 - escape-string-regexp: 4.0.0 - eslint: 9.39.2(jiti@2.6.1) - eslint-compat-utils: 0.6.5(eslint@9.39.2(jiti@2.6.1)) + diff-sequences: 29.6.3 + escape-string-regexp: 5.0.0 + eslint: 10.0.1(jiti@2.6.1) natural-compare: 1.4.0 - yaml-eslint-parser: 1.3.2 + yaml-eslint-parser: 2.0.0 transitivePeerDependencies: - supports-color - eslint-processor-vue-blocks@2.0.0(@vue/compiler-sfc@3.5.25)(eslint@9.39.2(jiti@2.6.1)): + eslint-processor-vue-blocks@2.0.0(@vue/compiler-sfc@3.5.28)(eslint@10.0.1(jiti@2.6.1)): dependencies: - '@vue/compiler-sfc': 3.5.25 - eslint: 9.39.2(jiti@2.6.1) + '@vue/compiler-sfc': 3.5.28 + eslint: 10.0.1(jiti@2.6.1) - eslint-scope@8.4.0: + eslint-scope@9.1.1: dependencies: + '@types/esrecurse': 4.3.1 + '@types/estree': 1.0.8 esrecurse: 4.3.0 estraverse: 5.3.0 @@ -4712,29 +5191,28 @@ snapshots: eslint-visitor-keys@4.2.1: {} - eslint@9.39.2(jiti@2.6.1): + eslint-visitor-keys@5.0.1: {} + + eslint@10.0.1(jiti@2.6.1): dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.2(jiti@2.6.1)) + '@eslint-community/eslint-utils': 4.9.1(eslint@10.0.1(jiti@2.6.1)) '@eslint-community/regexpp': 4.12.2 - '@eslint/config-array': 0.21.1 - '@eslint/config-helpers': 0.4.2 - '@eslint/core': 0.17.0 - '@eslint/eslintrc': 3.3.3 - '@eslint/js': 9.39.2 - '@eslint/plugin-kit': 0.4.1 + '@eslint/config-array': 0.23.2 + '@eslint/config-helpers': 0.5.2 + '@eslint/core': 1.1.0 + '@eslint/plugin-kit': 0.6.0 '@humanfs/node': 0.16.7 '@humanwhocodes/module-importer': 1.0.1 '@humanwhocodes/retry': 0.4.3 '@types/estree': 1.0.8 - ajv: 6.12.6 - chalk: 4.1.2 + ajv: 6.14.0 cross-spawn: 7.0.6 debug: 4.4.3 escape-string-regexp: 4.0.0 - eslint-scope: 8.4.0 - eslint-visitor-keys: 4.2.1 - espree: 10.4.0 - esquery: 1.6.0 + eslint-scope: 9.1.1 + eslint-visitor-keys: 5.0.1 + espree: 11.1.1 + esquery: 1.7.0 esutils: 2.0.3 fast-deep-equal: 3.1.3 file-entry-cache: 8.0.0 @@ -4744,8 +5222,7 @@ snapshots: imurmurhash: 0.1.4 is-glob: 4.0.3 json-stable-stringify-without-jsonify: 1.0.1 - lodash.merge: 4.6.2 - minimatch: 3.1.2 + minimatch: 10.2.2 natural-compare: 1.4.0 optionator: 0.9.4 optionalDependencies: @@ -4755,19 +5232,25 @@ snapshots: espree@10.4.0: dependencies: - acorn: 8.15.0 - acorn-jsx: 5.3.2(acorn@8.15.0) + acorn: 8.16.0 + acorn-jsx: 5.3.2(acorn@8.16.0) eslint-visitor-keys: 4.2.1 + espree@11.1.1: + dependencies: + acorn: 8.16.0 + acorn-jsx: 5.3.2(acorn@8.16.0) + eslint-visitor-keys: 5.0.1 + espree@9.6.1: dependencies: - acorn: 8.15.0 - acorn-jsx: 5.3.2(acorn@8.15.0) + acorn: 8.16.0 + acorn-jsx: 5.3.2(acorn@8.16.0) eslint-visitor-keys: 3.4.3 esprima@4.0.1: {} - esquery@1.6.0: + esquery@1.7.0: dependencies: estraverse: 5.3.0 @@ -4805,7 +5288,7 @@ snapshots: fast-levenshtein@2.0.6: {} - fastq@1.19.1: + fastq@1.20.1: dependencies: reusify: 1.1.0 @@ -4855,7 +5338,7 @@ snapshots: gensync@1.0.0-beta.2: {} - get-tsconfig@4.13.0: + get-tsconfig@4.13.6: dependencies: resolve-pkg-maps: 1.0.0 @@ -4873,8 +5356,8 @@ snapshots: dependencies: foreground-child: 3.3.1 jackspeak: 3.4.3 - minimatch: 9.0.5 - minipass: 7.1.2 + minimatch: 9.0.6 + minipass: 7.1.3 package-json-from-dist: 1.0.1 path-scurry: 1.11.1 @@ -4883,7 +5366,7 @@ snapshots: fs.realpath: 1.0.0 inflight: 1.0.6 inherits: 2.0.4 - minimatch: 3.1.2 + minimatch: 3.1.3 once: 1.4.0 path-is-absolute: 1.0.1 @@ -4893,19 +5376,21 @@ snapshots: globals@16.5.0: {} + globals@17.3.0: {} + globrex@0.1.2: {} graceful-fs@4.2.11: {} graphemer@1.4.0: {} - has-flag@4.0.0: {} - hookable@5.5.3: {} - html-encoding-sniffer@4.0.0: + html-encoding-sniffer@6.0.0: dependencies: - whatwg-encoding: 3.1.1 + '@exodus/bytes': 1.14.1 + transitivePeerDependencies: + - '@noble/hashes' html-entities@2.6.0: {} @@ -4923,10 +5408,6 @@ snapshots: transitivePeerDependencies: - supports-color - iconv-lite@0.6.3: - dependencies: - safer-buffer: 2.1.2 - ignore@5.3.2: {} ignore@7.0.5: {} @@ -4963,7 +5444,7 @@ snapshots: is-language-code@3.1.0: dependencies: - '@babel/runtime': 7.28.4 + '@babel/runtime': 7.28.6 is-number@7.0.0: {} @@ -4999,20 +5480,20 @@ snapshots: dependencies: argparse: 2.0.1 - jsdoc-type-pratt-parser@4.8.0: {} - - jsdoc-type-pratt-parser@6.10.0: {} - jsdoc-type-pratt-parser@7.0.0: {} - jsdom@27.3.0(postcss@8.5.6): + jsdoc-type-pratt-parser@7.1.1: {} + + jsdom@28.1.0: dependencies: - '@acemir/cssom': 0.9.29 - '@asamuzakjp/dom-selector': 6.7.6 - cssstyle: 5.3.4(postcss@8.5.6) - data-urls: 6.0.0 + '@acemir/cssom': 0.9.31 + '@asamuzakjp/dom-selector': 6.8.1 + '@bramus/specificity': 2.4.2 + '@exodus/bytes': 1.14.1 + cssstyle: 6.1.0 + data-urls: 7.0.0 decimal.js: 10.6.0 - html-encoding-sniffer: 4.0.0 + html-encoding-sniffer: 6.0.0 http-proxy-agent: 7.0.2 https-proxy-agent: 7.0.6 is-potential-custom-element-name: 1.0.1 @@ -5020,18 +5501,15 @@ snapshots: saxes: 6.0.0 symbol-tree: 3.2.4 tough-cookie: 6.0.0 + undici: 7.22.0 w3c-xmlserializer: 5.0.0 - webidl-conversions: 8.0.0 - whatwg-encoding: 3.1.1 - whatwg-mimetype: 4.0.0 - whatwg-url: 15.1.0 - ws: 8.18.3 + webidl-conversions: 8.0.1 + whatwg-mimetype: 5.0.0 + whatwg-url: 16.0.1 xml-name-validator: 5.0.0 transitivePeerDependencies: - - bufferutil - - postcss + - '@noble/hashes' - supports-color - - utf-8-validate jsesc@3.1.0: {} @@ -5045,10 +5523,10 @@ snapshots: jsonc-eslint-parser@2.4.2: dependencies: - acorn: 8.15.0 + acorn: 8.16.0 eslint-visitor-keys: 3.4.3 espree: 9.6.1 - semver: 7.7.3 + semver: 7.7.4 keyv@4.5.4: dependencies: @@ -5059,54 +5537,54 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 - lightningcss-android-arm64@1.30.2: + lightningcss-android-arm64@1.31.1: optional: true - lightningcss-darwin-arm64@1.30.2: + lightningcss-darwin-arm64@1.31.1: optional: true - lightningcss-darwin-x64@1.30.2: + lightningcss-darwin-x64@1.31.1: optional: true - lightningcss-freebsd-x64@1.30.2: + lightningcss-freebsd-x64@1.31.1: optional: true - lightningcss-linux-arm-gnueabihf@1.30.2: + lightningcss-linux-arm-gnueabihf@1.31.1: optional: true - lightningcss-linux-arm64-gnu@1.30.2: + lightningcss-linux-arm64-gnu@1.31.1: optional: true - lightningcss-linux-arm64-musl@1.30.2: + lightningcss-linux-arm64-musl@1.31.1: optional: true - lightningcss-linux-x64-gnu@1.30.2: + lightningcss-linux-x64-gnu@1.31.1: optional: true - lightningcss-linux-x64-musl@1.30.2: + lightningcss-linux-x64-musl@1.31.1: optional: true - lightningcss-win32-arm64-msvc@1.30.2: + lightningcss-win32-arm64-msvc@1.31.1: optional: true - lightningcss-win32-x64-msvc@1.30.2: + lightningcss-win32-x64-msvc@1.31.1: optional: true - lightningcss@1.30.2: + lightningcss@1.31.1: dependencies: detect-libc: 2.1.2 optionalDependencies: - lightningcss-android-arm64: 1.30.2 - lightningcss-darwin-arm64: 1.30.2 - lightningcss-darwin-x64: 1.30.2 - lightningcss-freebsd-x64: 1.30.2 - lightningcss-linux-arm-gnueabihf: 1.30.2 - lightningcss-linux-arm64-gnu: 1.30.2 - lightningcss-linux-arm64-musl: 1.30.2 - lightningcss-linux-x64-gnu: 1.30.2 - lightningcss-linux-x64-musl: 1.30.2 - lightningcss-win32-arm64-msvc: 1.30.2 - lightningcss-win32-x64-msvc: 1.30.2 + lightningcss-android-arm64: 1.31.1 + lightningcss-darwin-arm64: 1.31.1 + lightningcss-darwin-x64: 1.31.1 + lightningcss-freebsd-x64: 1.31.1 + lightningcss-linux-arm-gnueabihf: 1.31.1 + lightningcss-linux-arm64-gnu: 1.31.1 + lightningcss-linux-arm64-musl: 1.31.1 + lightningcss-linux-x64-gnu: 1.31.1 + lightningcss-linux-x64-musl: 1.31.1 + lightningcss-win32-arm64-msvc: 1.31.1 + lightningcss-win32-x64-msvc: 1.31.1 local-pkg@1.1.2: dependencies: @@ -5118,22 +5596,24 @@ snapshots: dependencies: p-locate: 5.0.0 - lodash.merge@4.6.2: {} - lodash.sortedlastindex@4.1.0: {} - lodash@4.17.21: {} + lodash@4.17.23: {} longest-streak@3.1.0: {} lru-cache@10.4.3: {} - lru-cache@11.2.4: {} + lru-cache@11.2.6: {} lru-cache@5.1.1: dependencies: yallist: 3.1.1 + magic-string-ast@1.0.3: + dependencies: + magic-string: 0.30.21 + magic-string@0.30.21: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -5142,7 +5622,7 @@ snapshots: markdown-table@3.0.4: {} - marked@17.0.1: {} + marked@17.0.3: {} mdast-util-find-and-replace@3.0.2: dependencies: @@ -5151,11 +5631,11 @@ snapshots: unist-util-is: 6.0.1 unist-util-visit-parents: 6.0.2 - mdast-util-from-markdown@2.0.2: + mdast-util-from-markdown@2.0.3: dependencies: '@types/mdast': 4.0.4 '@types/unist': 3.0.3 - decode-named-character-reference: 1.2.0 + decode-named-character-reference: 1.3.0 devlop: 1.1.0 mdast-util-to-string: 4.0.0 micromark: 4.0.2 @@ -5173,7 +5653,7 @@ snapshots: '@types/mdast': 4.0.4 devlop: 1.1.0 escape-string-regexp: 5.0.0 - mdast-util-from-markdown: 2.0.2 + mdast-util-from-markdown: 2.0.3 mdast-util-to-markdown: 2.1.2 micromark-extension-frontmatter: 2.0.0 transitivePeerDependencies: @@ -5191,7 +5671,7 @@ snapshots: dependencies: '@types/mdast': 4.0.4 devlop: 1.1.0 - mdast-util-from-markdown: 2.0.2 + mdast-util-from-markdown: 2.0.3 mdast-util-to-markdown: 2.1.2 micromark-util-normalize-identifier: 2.0.1 transitivePeerDependencies: @@ -5200,7 +5680,7 @@ snapshots: mdast-util-gfm-strikethrough@2.0.0: dependencies: '@types/mdast': 4.0.4 - mdast-util-from-markdown: 2.0.2 + mdast-util-from-markdown: 2.0.3 mdast-util-to-markdown: 2.1.2 transitivePeerDependencies: - supports-color @@ -5210,7 +5690,7 @@ snapshots: '@types/mdast': 4.0.4 devlop: 1.1.0 markdown-table: 3.0.4 - mdast-util-from-markdown: 2.0.2 + mdast-util-from-markdown: 2.0.3 mdast-util-to-markdown: 2.1.2 transitivePeerDependencies: - supports-color @@ -5219,14 +5699,14 @@ snapshots: dependencies: '@types/mdast': 4.0.4 devlop: 1.1.0 - mdast-util-from-markdown: 2.0.2 + mdast-util-from-markdown: 2.0.3 mdast-util-to-markdown: 2.1.2 transitivePeerDependencies: - supports-color mdast-util-gfm@3.1.0: dependencies: - mdast-util-from-markdown: 2.0.2 + mdast-util-from-markdown: 2.0.3 mdast-util-gfm-autolink-literal: 2.0.1 mdast-util-gfm-footnote: 2.1.0 mdast-util-gfm-strikethrough: 2.0.0 @@ -5250,7 +5730,7 @@ snapshots: mdast-util-to-string: 4.0.0 micromark-util-classify-character: 2.0.1 micromark-util-decode-string: 2.0.1 - unist-util-visit: 5.0.0 + unist-util-visit: 5.1.0 zwitch: 2.0.4 mdast-util-to-string@4.0.0: @@ -5267,7 +5747,7 @@ snapshots: micromark-core-commonmark@2.0.3: dependencies: - decode-named-character-reference: 1.2.0 + decode-named-character-reference: 1.3.0 devlop: 1.1.0 micromark-factory-destination: 2.0.1 micromark-factory-label: 2.0.1 @@ -5407,7 +5887,7 @@ snapshots: micromark-util-decode-string@2.0.1: dependencies: - decode-named-character-reference: 1.2.0 + decode-named-character-reference: 1.3.0 micromark-util-character: 2.1.1 micromark-util-decode-numeric-character-reference: 2.0.2 micromark-util-symbol: 2.0.1 @@ -5445,7 +5925,7 @@ snapshots: dependencies: '@types/debug': 4.1.12 debug: 4.4.3 - decode-named-character-reference: 1.2.0 + decode-named-character-reference: 1.3.0 devlop: 1.1.0 micromark-core-commonmark: 2.0.3 micromark-factory-space: 2.0.1 @@ -5468,7 +5948,11 @@ snapshots: braces: 3.0.3 picomatch: 2.3.1 - minimatch@3.1.2: + minimatch@10.2.2: + dependencies: + brace-expansion: 5.0.3 + + minimatch@3.1.3: dependencies: brace-expansion: 1.1.12 @@ -5476,20 +5960,20 @@ snapshots: dependencies: brace-expansion: 2.0.2 - minimatch@9.0.5: + minimatch@9.0.6: dependencies: - brace-expansion: 2.0.2 + brace-expansion: 5.0.3 - minipass@7.1.2: {} + minipass@7.1.3: {} mitt@3.0.1: {} mlly@1.8.0: dependencies: - acorn: 8.15.0 + acorn: 8.16.0 pathe: 2.0.3 pkg-types: 1.3.1 - ufo: 1.6.1 + ufo: 1.6.3 ms@2.1.3: {} @@ -5578,22 +6062,24 @@ snapshots: path-scurry@1.11.1: dependencies: lru-cache: 10.4.3 - minipass: 7.1.2 + minipass: 7.1.3 pathe@2.0.3: {} perfect-debounce@1.0.0: {} + perfect-debounce@2.1.0: {} + picocolors@1.1.1: {} picomatch@2.3.1: {} picomatch@4.0.3: {} - pinia@3.0.4(typescript@5.9.3)(vue@3.5.25(typescript@5.9.3)): + pinia@3.0.4(typescript@5.9.3)(vue@3.5.28(typescript@5.9.3)): dependencies: '@vue/devtools-api': 7.7.9 - vue: 3.5.25(typescript@5.9.3) + vue: 3.5.28(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 @@ -5605,13 +6091,13 @@ snapshots: pkg-types@2.3.0: dependencies: - confbox: 0.2.2 + confbox: 0.2.4 exsolve: 1.0.8 pathe: 2.0.3 pluralize@8.0.0: {} - pnpm-workspace-yaml@1.4.3: + pnpm-workspace-yaml@1.5.0: dependencies: yaml: 2.8.2 @@ -5651,13 +6137,13 @@ snapshots: prelude-ls@1.2.1: {} - prettier-plugin-tailwindcss@0.7.2(@ianvs/prettier-plugin-sort-imports@4.7.0(@vue/compiler-sfc@3.5.25)(prettier@3.7.4))(prettier@3.7.4): + prettier-plugin-tailwindcss@0.7.2(@ianvs/prettier-plugin-sort-imports@4.7.1(@vue/compiler-sfc@3.5.28)(prettier@3.8.1))(prettier@3.8.1): dependencies: - prettier: 3.7.4 + prettier: 3.8.1 optionalDependencies: - '@ianvs/prettier-plugin-sort-imports': 4.7.0(@vue/compiler-sfc@3.5.25)(prettier@3.7.4) + '@ianvs/prettier-plugin-sort-imports': 4.7.1(@vue/compiler-sfc@3.5.28)(prettier@3.8.1) - prettier@3.7.4: {} + prettier@3.8.1: {} prismjs@1.30.0: {} @@ -5669,6 +6155,8 @@ snapshots: queue-microtask@1.2.3: {} + readdirp@5.0.0: {} + refa@0.12.1: dependencies: '@eslint-community/regexpp': 4.12.2 @@ -5696,32 +6184,35 @@ snapshots: rfdc@1.4.1: {} - rollup@4.53.3: + rollup@4.59.0: dependencies: '@types/estree': 1.0.8 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.53.3 - '@rollup/rollup-android-arm64': 4.53.3 - '@rollup/rollup-darwin-arm64': 4.53.3 - '@rollup/rollup-darwin-x64': 4.53.3 - '@rollup/rollup-freebsd-arm64': 4.53.3 - '@rollup/rollup-freebsd-x64': 4.53.3 - '@rollup/rollup-linux-arm-gnueabihf': 4.53.3 - '@rollup/rollup-linux-arm-musleabihf': 4.53.3 - '@rollup/rollup-linux-arm64-gnu': 4.53.3 - '@rollup/rollup-linux-arm64-musl': 4.53.3 - '@rollup/rollup-linux-loong64-gnu': 4.53.3 - '@rollup/rollup-linux-ppc64-gnu': 4.53.3 - '@rollup/rollup-linux-riscv64-gnu': 4.53.3 - '@rollup/rollup-linux-riscv64-musl': 4.53.3 - '@rollup/rollup-linux-s390x-gnu': 4.53.3 - '@rollup/rollup-linux-x64-gnu': 4.53.3 - '@rollup/rollup-linux-x64-musl': 4.53.3 - '@rollup/rollup-openharmony-arm64': 4.53.3 - '@rollup/rollup-win32-arm64-msvc': 4.53.3 - '@rollup/rollup-win32-ia32-msvc': 4.53.3 - '@rollup/rollup-win32-x64-gnu': 4.53.3 - '@rollup/rollup-win32-x64-msvc': 4.53.3 + '@rollup/rollup-android-arm-eabi': 4.59.0 + '@rollup/rollup-android-arm64': 4.59.0 + '@rollup/rollup-darwin-arm64': 4.59.0 + '@rollup/rollup-darwin-x64': 4.59.0 + '@rollup/rollup-freebsd-arm64': 4.59.0 + '@rollup/rollup-freebsd-x64': 4.59.0 + '@rollup/rollup-linux-arm-gnueabihf': 4.59.0 + '@rollup/rollup-linux-arm-musleabihf': 4.59.0 + '@rollup/rollup-linux-arm64-gnu': 4.59.0 + '@rollup/rollup-linux-arm64-musl': 4.59.0 + '@rollup/rollup-linux-loong64-gnu': 4.59.0 + '@rollup/rollup-linux-loong64-musl': 4.59.0 + '@rollup/rollup-linux-ppc64-gnu': 4.59.0 + '@rollup/rollup-linux-ppc64-musl': 4.59.0 + '@rollup/rollup-linux-riscv64-gnu': 4.59.0 + '@rollup/rollup-linux-riscv64-musl': 4.59.0 + '@rollup/rollup-linux-s390x-gnu': 4.59.0 + '@rollup/rollup-linux-x64-gnu': 4.59.0 + '@rollup/rollup-linux-x64-musl': 4.59.0 + '@rollup/rollup-openbsd-x64': 4.59.0 + '@rollup/rollup-openharmony-arm64': 4.59.0 + '@rollup/rollup-win32-arm64-msvc': 4.59.0 + '@rollup/rollup-win32-ia32-msvc': 4.59.0 + '@rollup/rollup-win32-x64-gnu': 4.59.0 + '@rollup/rollup-win32-x64-msvc': 4.59.0 fsevents: 2.3.3 run-parallel@1.2.0: @@ -5742,7 +6233,9 @@ snapshots: refa: 0.12.1 regexp-ast-analysis: 0.7.1 - semver@7.7.3: {} + scule@1.3.0: {} + + semver@7.7.4: {} shebang-command@2.0.0: dependencies: @@ -5754,7 +6247,7 @@ snapshots: signal-exit@4.1.0: {} - simple-icons@16.2.0: {} + simple-icons@16.9.0: {} sisteransi@1.0.5: {} @@ -5778,9 +6271,9 @@ snapshots: spdx-expression-parse@4.0.0: dependencies: spdx-exceptions: 2.5.0 - spdx-license-ids: 3.0.22 + spdx-license-ids: 3.0.23 - spdx-license-ids@3.0.22: {} + spdx-license-ids@3.0.23: {} speakingurl@14.0.1: {} @@ -5827,10 +6320,6 @@ snapshots: dependencies: copy-anything: 4.0.5 - supports-color@7.2.0: - dependencies: - has-flag: 4.0.0 - svgo@3.3.2: dependencies: '@trysound/sax': 0.2.0 @@ -5848,11 +6337,11 @@ snapshots: '@pkgr/core': 0.2.9 tslib: 2.8.1 - synckit@0.11.11: + synckit@0.11.12: dependencies: '@pkgr/core': 0.2.9 - tailwindcss@4.1.18: {} + tailwindcss@4.2.0: {} tapable@2.3.0: {} @@ -5869,11 +6358,11 @@ snapshots: tinyrainbow@3.0.3: {} - tldts-core@7.0.19: {} + tldts-core@7.0.23: {} - tldts@7.0.19: + tldts@7.0.23: dependencies: - tldts-core: 7.0.19 + tldts-core: 7.0.23 to-regex-range@5.0.1: dependencies: @@ -5884,19 +6373,19 @@ snapshots: '@sindresorhus/base62': 1.0.0 reserved-identifiers: 1.2.0 - toml-eslint-parser@0.10.1: + toml-eslint-parser@1.0.3: dependencies: - eslint-visitor-keys: 3.4.3 + eslint-visitor-keys: 5.0.1 tough-cookie@6.0.0: dependencies: - tldts: 7.0.19 + tldts: 7.0.23 tr46@6.0.0: dependencies: punycode: 2.3.1 - ts-api-utils@2.1.0(typescript@5.9.3): + ts-api-utils@2.4.0(typescript@5.9.3): dependencies: typescript: 5.9.3 @@ -5905,19 +6394,19 @@ snapshots: picomatch: 4.0.3 typescript: 5.9.3 - ts-node@10.9.2(@types/node@24.10.4)(typescript@5.9.3): + ts-node@10.9.2(@types/node@24.10.13)(typescript@5.9.3): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.12 '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 - '@types/node': 24.10.4 - acorn: 8.15.0 - acorn-walk: 8.3.4 + '@types/node': 24.10.13 + acorn: 8.16.0 + acorn-walk: 8.3.5 arg: 4.1.3 create-require: 1.1.1 - diff: 4.0.2 + diff: 4.0.4 make-error: 1.3.6 typescript: 5.9.3 v8-compile-cache-lib: 3.0.1 @@ -5931,10 +6420,12 @@ snapshots: typescript@5.9.3: {} - ufo@1.6.1: {} + ufo@1.6.3: {} undici-types@7.16.0: {} + undici@7.22.0: {} + unicode-emoji-modifier-base@1.0.0: {} unist-util-is@6.0.1: @@ -5950,20 +6441,31 @@ snapshots: '@types/unist': 3.0.3 unist-util-is: 6.0.1 - unist-util-visit@5.0.0: + unist-util-visit@5.1.0: dependencies: '@types/unist': 3.0.3 unist-util-is: 6.0.1 unist-util-visit-parents: 6.0.2 + unplugin-utils@0.3.1: + dependencies: + pathe: 2.0.3 + picomatch: 4.0.3 + unplugin@2.3.11: dependencies: '@jridgewell/remapping': 2.3.5 - acorn: 8.15.0 + acorn: 8.16.0 picomatch: 4.0.3 webpack-virtual-modules: 0.6.2 - update-browserslist-db@1.2.2(browserslist@4.28.1): + unplugin@3.0.0: + dependencies: + '@jridgewell/remapping': 2.3.5 + picomatch: 4.0.3 + webpack-virtual-modules: 0.6.2 + + update-browserslist-db@1.2.3(browserslist@4.28.1): dependencies: browserslist: 4.28.1 escalade: 3.2.0 @@ -5979,42 +6481,42 @@ snapshots: vite-plugin-prismjs@0.0.11(prismjs@1.30.0): dependencies: - '@babel/core': 7.28.5 + '@babel/core': 7.29.0 babel-plugin-prismjs: 2.1.0(prismjs@1.30.0) transitivePeerDependencies: - prismjs - supports-color - vite-svg-loader@5.1.0(vue@3.5.25(typescript@5.9.3)): + vite-svg-loader@5.1.0(vue@3.5.28(typescript@5.9.3)): dependencies: svgo: 3.3.2 - vue: 3.5.25(typescript@5.9.3) + vue: 3.5.28(typescript@5.9.3) - vite@7.2.7(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(stylus@0.57.0)(yaml@2.8.2): + vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(stylus@0.57.0)(yaml@2.8.2): dependencies: - esbuild: 0.25.12 + esbuild: 0.27.3 fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 postcss: 8.5.6 - rollup: 4.53.3 + rollup: 4.59.0 tinyglobby: 0.2.15 optionalDependencies: - '@types/node': 24.10.4 + '@types/node': 24.10.13 fsevents: 2.3.3 jiti: 2.6.1 - lightningcss: 1.30.2 + lightningcss: 1.31.1 stylus: 0.57.0 yaml: 2.8.2 - vitest@4.0.15(@types/node@24.10.4)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2)(stylus@0.57.0)(yaml@2.8.2): + vitest@4.0.18(@types/node@24.10.13)(jiti@2.6.1)(jsdom@28.1.0)(lightningcss@1.31.1)(stylus@0.57.0)(yaml@2.8.2): dependencies: - '@vitest/expect': 4.0.15 - '@vitest/mocker': 4.0.15(vite@7.2.7(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(stylus@0.57.0)(yaml@2.8.2)) - '@vitest/pretty-format': 4.0.15 - '@vitest/runner': 4.0.15 - '@vitest/snapshot': 4.0.15 - '@vitest/spy': 4.0.15 - '@vitest/utils': 4.0.15 + '@vitest/expect': 4.0.18 + '@vitest/mocker': 4.0.18(vite@7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(stylus@0.57.0)(yaml@2.8.2)) + '@vitest/pretty-format': 4.0.18 + '@vitest/runner': 4.0.18 + '@vitest/snapshot': 4.0.18 + '@vitest/spy': 4.0.18 + '@vitest/utils': 4.0.18 es-module-lexer: 1.7.0 expect-type: 1.3.0 magic-string: 0.30.21 @@ -6026,11 +6528,11 @@ snapshots: tinyexec: 1.0.2 tinyglobby: 0.2.15 tinyrainbow: 3.0.3 - vite: 7.2.7(@types/node@24.10.4)(jiti@2.6.1)(lightningcss@1.30.2)(stylus@0.57.0)(yaml@2.8.2) + vite: 7.3.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(stylus@0.57.0)(yaml@2.8.2) why-is-node-running: 2.3.0 optionalDependencies: - '@types/node': 24.10.4 - jsdom: 27.3.0(postcss@8.5.6) + '@types/node': 24.10.13 + jsdom: 28.1.0 transitivePeerDependencies: - jiti - less @@ -6048,43 +6550,62 @@ snapshots: vue-component-type-helpers@2.2.12: {} - vue-eslint-parser@10.2.0(eslint@9.39.2(jiti@2.6.1)): + vue-eslint-parser@10.4.0(eslint@10.0.1(jiti@2.6.1)): dependencies: debug: 4.4.3 - eslint: 9.39.2(jiti@2.6.1) - eslint-scope: 8.4.0 - eslint-visitor-keys: 4.2.1 - espree: 10.4.0 - esquery: 1.6.0 - semver: 7.7.3 + eslint: 10.0.1(jiti@2.6.1) + eslint-scope: 9.1.1 + eslint-visitor-keys: 5.0.1 + espree: 11.1.1 + esquery: 1.7.0 + semver: 7.7.4 transitivePeerDependencies: - supports-color - vue-i18n@11.2.2(vue@3.5.25(typescript@5.9.3)): + vue-i18n@11.2.8(vue@3.5.28(typescript@5.9.3)): dependencies: - '@intlify/core-base': 11.2.2 - '@intlify/shared': 11.2.2 + '@intlify/core-base': 11.2.8 + '@intlify/shared': 11.2.8 '@vue/devtools-api': 6.6.4 - vue: 3.5.25(typescript@5.9.3) + vue: 3.5.28(typescript@5.9.3) - vue-router@4.6.4(vue@3.5.25(typescript@5.9.3)): + vue-router@5.0.3(@vue/compiler-sfc@3.5.28)(pinia@3.0.4(typescript@5.9.3)(vue@3.5.28(typescript@5.9.3)))(vue@3.5.28(typescript@5.9.3)): dependencies: - '@vue/devtools-api': 6.6.4 - vue: 3.5.25(typescript@5.9.3) + '@babel/generator': 7.29.1 + '@vue-macros/common': 3.1.2(vue@3.5.28(typescript@5.9.3)) + '@vue/devtools-api': 8.0.6 + ast-walker-scope: 0.8.3 + chokidar: 5.0.0 + json5: 2.2.3 + local-pkg: 1.1.2 + magic-string: 0.30.21 + mlly: 1.8.0 + muggle-string: 0.4.1 + pathe: 2.0.3 + picomatch: 4.0.3 + scule: 1.3.0 + tinyglobby: 0.2.15 + unplugin: 3.0.0 + unplugin-utils: 0.3.1 + vue: 3.5.28(typescript@5.9.3) + yaml: 2.8.2 + optionalDependencies: + '@vue/compiler-sfc': 3.5.28 + pinia: 3.0.4(typescript@5.9.3)(vue@3.5.28(typescript@5.9.3)) - vue-tsc@3.1.8(typescript@5.9.3): + vue-tsc@3.2.5(typescript@5.9.3): dependencies: - '@volar/typescript': 2.4.26 - '@vue/language-core': 3.1.8(typescript@5.9.3) + '@volar/typescript': 2.4.28 + '@vue/language-core': 3.2.5 typescript: 5.9.3 - vue@3.5.25(typescript@5.9.3): + vue@3.5.28(typescript@5.9.3): dependencies: - '@vue/compiler-dom': 3.5.25 - '@vue/compiler-sfc': 3.5.25 - '@vue/runtime-dom': 3.5.25 - '@vue/server-renderer': 3.5.25(vue@3.5.25(typescript@5.9.3)) - '@vue/shared': 3.5.25 + '@vue/compiler-dom': 3.5.28 + '@vue/compiler-sfc': 3.5.28 + '@vue/runtime-dom': 3.5.28 + '@vue/server-renderer': 3.5.28(vue@3.5.28(typescript@5.9.3)) + '@vue/shared': 3.5.28 optionalDependencies: typescript: 5.9.3 @@ -6092,20 +6613,19 @@ snapshots: dependencies: xml-name-validator: 5.0.0 - webidl-conversions@8.0.0: {} + webidl-conversions@8.0.1: {} webpack-virtual-modules@0.6.2: {} - whatwg-encoding@3.1.1: - dependencies: - iconv-lite: 0.6.3 + whatwg-mimetype@5.0.0: {} - whatwg-mimetype@4.0.0: {} - - whatwg-url@15.1.0: + whatwg-url@16.0.1: dependencies: + '@exodus/bytes': 1.14.1 tr46: 6.0.0 - webidl-conversions: 8.0.0 + webidl-conversions: 8.0.1 + transitivePeerDependencies: + - '@noble/hashes' which@2.0.2: dependencies: @@ -6132,8 +6652,6 @@ snapshots: wrappy@1.0.2: {} - ws@8.18.3: {} - xml-name-validator@4.0.0: {} xml-name-validator@5.0.0: {} @@ -6147,6 +6665,11 @@ snapshots: eslint-visitor-keys: 3.4.3 yaml: 2.8.2 + yaml-eslint-parser@2.0.0: + dependencies: + eslint-visitor-keys: 5.0.1 + yaml: 2.8.2 + yaml@2.8.2: {} yn@3.1.1: {} diff --git a/web/src/App.vue b/web/src/App.vue index f73778030..a948bc7e1 100644 --- a/web/src/App.vue +++ b/web/src/App.vue @@ -1,6 +1,6 @@