From 2802f96e9773d194f8a88dd4050b43ae4dd2fd78 Mon Sep 17 00:00:00 2001 From: koalajoe23 Date: Tue, 9 Sep 2025 22:13:41 +0200 Subject: [PATCH 01/30] check user and repo for redirects when using git via SSH transport (#35416) fixes #30565 When using git with a gitea hosted repository, the HTTP-Transport did honor the user and repository redirects, which are created when renaming a user or repo and also when transferring ownership of a repo to a different organization. This is extremely helpful, as repo URLs remain stable and do not have to be migrated on each client's worktree and other places, e.g. CI at once. The SSH transport - which I favor - did not know of these redirections and I implemented a lookup during the `serv` command. --- cmd/serv.go | 10 +++--- models/fixtures/user_redirect.yml | 4 +++ routers/private/serv.go | 25 +++++++++++++ tests/integration/git_ssh_redirect_test.go | 42 ++++++++++++++++++++++ 4 files changed, 76 insertions(+), 5 deletions(-) create mode 100644 tests/integration/git_ssh_redirect_test.go diff --git a/cmd/serv.go b/cmd/serv.go index 089d0e3bb7c..60f7fb92ff0 100644 --- a/cmd/serv.go +++ b/cmd/serv.go @@ -229,11 +229,6 @@ func runServ(ctx context.Context, c *cli.Command) error { username := repoPathFields[0] reponame := strings.TrimSuffix(repoPathFields[1], ".git") // “the-repo-name" or "the-repo-name.wiki" - // LowerCase and trim the repoPath as that's how they are stored. - // This should be done after splitting the repoPath into username and reponame - // so that username and reponame are not affected. - repoPath = strings.ToLower(strings.TrimSpace(repoPath)) - if !repo.IsValidSSHAccessRepoName(reponame) { return fail(ctx, "Invalid repo name", "Invalid repo name: %s", reponame) } @@ -280,6 +275,11 @@ func runServ(ctx context.Context, c *cli.Command) error { return fail(ctx, extra.UserMsg, "ServCommand failed: %s", extra.Error) } + // LowerCase and trim the repoPath as that's how they are stored. + // This should be done after splitting the repoPath into username and reponame + // so that username and reponame are not affected. + repoPath = strings.ToLower(results.OwnerName + "/" + results.RepoName + ".git") + // LFS SSH protocol if verb == git.CmdVerbLfsTransfer { token, err := getLFSAuthToken(ctx, lfsVerb, results) diff --git a/models/fixtures/user_redirect.yml b/models/fixtures/user_redirect.yml index 8ff79933983..c668cb6c3b7 100644 --- a/models/fixtures/user_redirect.yml +++ b/models/fixtures/user_redirect.yml @@ -2,3 +2,7 @@ id: 1 lower_name: olduser1 redirect_user_id: 1 +- + id: 2 + lower_name: olduser2 + redirect_user_id: 2 diff --git a/routers/private/serv.go b/routers/private/serv.go index b879be0dc20..3dfe4d21da7 100644 --- a/routers/private/serv.go +++ b/routers/private/serv.go @@ -108,6 +108,18 @@ func ServCommand(ctx *context.PrivateContext) { results.RepoName = repoName[:len(repoName)-5] } + // Check if there is a user redirect for the requested owner + redirectedUserID, err := user_model.LookupUserRedirect(ctx, results.OwnerName) + if err == nil { + owner, err := user_model.GetUserByID(ctx, redirectedUserID) + if err == nil { + log.Info("User %s has been redirected to %s", results.OwnerName, owner.Name) + results.OwnerName = owner.Name + } else { + log.Warn("User %s has a redirect to user with ID %d, but no user with this ID could be found. Trying without redirect...", results.OwnerName, redirectedUserID) + } + } + owner, err := user_model.GetUserByName(ctx, results.OwnerName) if err != nil { if user_model.IsErrUserNotExist(err) { @@ -131,6 +143,19 @@ func ServCommand(ctx *context.PrivateContext) { return } + redirectedRepoID, err := repo_model.LookupRedirect(ctx, owner.ID, results.RepoName) + if err == nil { + redirectedRepo, err := repo_model.GetRepositoryByID(ctx, redirectedRepoID) + if err == nil { + log.Info("Repository %s/%s has been redirected to %s/%s", results.OwnerName, results.RepoName, redirectedRepo.OwnerName, redirectedRepo.Name) + results.RepoName = redirectedRepo.Name + results.OwnerName = redirectedRepo.OwnerName + owner.ID = redirectedRepo.OwnerID + } else { + log.Warn("Repo %s/%s has a redirect to repo with ID %d, but no repo with this ID could be found. Trying without redirect...", results.OwnerName, results.RepoName, redirectedRepoID) + } + } + // Now get the Repository and set the results section repoExist := true repo, err := repo_model.GetRepositoryByName(ctx, owner.ID, results.RepoName) diff --git a/tests/integration/git_ssh_redirect_test.go b/tests/integration/git_ssh_redirect_test.go new file mode 100644 index 00000000000..5e35ed2a744 --- /dev/null +++ b/tests/integration/git_ssh_redirect_test.go @@ -0,0 +1,42 @@ +// Copyright 2025 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package integration + +import ( + "fmt" + "net/url" + "testing" + + auth_model "code.gitea.io/gitea/models/auth" +) + +func TestGitSSHRedirect(t *testing.T) { + onGiteaRun(t, testGitSSHRedirect) +} + +func testGitSSHRedirect(t *testing.T, u *url.URL) { + apiTestContext := NewAPITestContext(t, "user2", "repo1", auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser) + + withKeyFile(t, "my-testing-key", func(keyFile string) { + t.Run("CreateUserKey", doAPICreateUserKey(apiTestContext, "test-key", keyFile)) + + testCases := []struct { + testName string + userName string + repoName string + }{ + {"Test untouched", "user2", "repo1"}, + {"Test renamed user", "olduser2", "repo1"}, + {"Test renamed repo", "user2", "oldrepo1"}, + {"Test renamed user and repo", "olduser2", "oldrepo1"}, + } + + for _, tc := range testCases { + t.Run(tc.testName, func(t *testing.T) { + cloneURL := createSSHUrl(fmt.Sprintf("%s/%s.git", tc.userName, tc.repoName), u) + t.Run("Clone", doGitClone(t.TempDir(), cloneURL)) + }) + } + }) +} From 47df15cabcacc0017937cdafedb61364407ec52c Mon Sep 17 00:00:00 2001 From: silverwind Date: Wed, 10 Sep 2025 02:30:20 +0200 Subject: [PATCH 02/30] Update JS and PY dependencies (#35444) Tested all affected dependencies. --- options/fileicon/material-icon-rules.json | 94 ++++- options/fileicon/material-icon-svgs.json | 23 +- package.json | 18 +- pnpm-lock.yaml | 349 +++++++++--------- .../assets/img/svg/octicon-checkbox-fill.svg | 1 + uv.lock | 160 ++++---- 6 files changed, 379 insertions(+), 266 deletions(-) create mode 100644 public/assets/img/svg/octicon-checkbox-fill.svg diff --git a/options/fileicon/material-icon-rules.json b/options/fileicon/material-icon-rules.json index 15bbf613db7..622564fe2b7 100644 --- a/options/fileicon/material-icon-rules.json +++ b/options/fileicon/material-icon-rules.json @@ -3367,6 +3367,22 @@ "..claude": "folder-claude", "_.claude": "folder-claude", "__.claude__": "folder-claude", + ".cursor": "folder-cursor", + "..cursor": "folder-cursor", + "_.cursor": "folder-cursor", + "__.cursor__": "folder-cursor", + "metro": "folder-metro", + ".metro": "folder-metro", + "_metro": "folder-metro", + "__metro__": "folder-metro", + "filter": "folder-filter", + ".filter": "folder-filter", + "_filter": "folder-filter", + "__filter__": "folder-filter", + "filters": "folder-filter", + ".filters": "folder-filter", + "_filters": "folder-filter", + "__filters__": "folder-filter", "meta-inf": "folder-config", ".meta-inf": "folder-config", "_meta-inf": "folder-config", @@ -6763,7 +6779,23 @@ ".claude": "folder-claude-open", "..claude": "folder-claude-open", "_.claude": "folder-claude-open", - "__.claude__": "folder-claude-open" + "__.claude__": "folder-claude-open", + ".cursor": "folder-cursor-open", + "..cursor": "folder-cursor-open", + "_.cursor": "folder-cursor-open", + "__.cursor__": "folder-cursor-open", + "metro": "folder-metro-open", + ".metro": "folder-metro-open", + "_metro": "folder-metro-open", + "__metro__": "folder-metro-open", + "filter": "folder-filter-open", + ".filter": "folder-filter-open", + "_filter": "folder-filter-open", + "__filter__": "folder-filter-open", + "filters": "folder-filter-open", + ".filters": "folder-filter-open", + "_filters": "folder-filter-open", + "__filters__": "folder-filter-open" }, "rootFolderNames": {}, "rootFolderNamesExpanded": {}, @@ -6800,6 +6832,7 @@ "sublime-project": "sublime", "sublime-workspace": "sublime", "slx": "simulink", + "qmd": "quarto", "tw": "twine", "twee": "twine", "yml.dist": "yaml", @@ -7366,6 +7399,7 @@ "mli": "ocaml", "cmx": "ocaml", "odin": "odin", + "onnx": "onnx", "js.map": "javascript-map", "mjs.map": "javascript-map", "cjs.map": "javascript-map", @@ -7468,6 +7502,7 @@ "tfvars": "terraform", "tfstate": "terraform", "tfbackend": "terraform", + "tofu": "opentofu", "blade.php": "laravel", "inky.php": "laravel", "applescript": "applescript", @@ -7761,12 +7796,24 @@ "geom": "shader", "frag": "shader", "comp": "shader", + "rgen": "shader", + "rint": "shader", + "rahit": "shader", + "rchit": "shader", + "rmiss": "shader", + "rcall": "shader", "vert.glsl": "shader", "tesc.glsl": "shader", "tese.glsl": "shader", "geom.glsl": "shader", "frag.glsl": "shader", "comp.glsl": "shader", + "rgen.glsl": "shader", + "rint.glsl": "shader", + "rahit.glsl": "shader", + "rchit.glsl": "shader", + "rmiss.glsl": "shader", + "rcall.glsl": "shader", "vertex.glsl": "shader", "geometry.glsl": "shader", "fragment.glsl": "shader", @@ -7790,6 +7837,8 @@ "comp.hlsl": "shader", "tess.hlsl": "shader", "wgsl": "shader", + "spv": "shader", + "slang": "shader", "sy": "siyuan", "ndst.yml": "ndst", "ndst.yaml": "ndst", @@ -7852,6 +7901,7 @@ "hurl": "hurl", "cds": "cds", "slint": "slint", + "verse": "verse", "sw": "sway", "zeabur": "zeabur", "bench.ts": "bench-ts", @@ -9004,6 +9054,7 @@ ".eslintrc.base.json": "eslint", ".eslintignore": "eslint", ".eslintcache": "eslint", + "eslint-options.js": "eslint", "code_of_conduct.md": "conduct", "code_of_conduct.txt": "conduct", "code_of_conduct": "conduct", @@ -9025,6 +9076,7 @@ ".mocharc.json": "mocha", ".mocharc.jsonc": "mocha", "jenkinsfile": "jenkins", + "firebase.config.js": "firebase", "firebase.json": "firebase", ".firebaserc": "firebase", "firestore.rules": "firebase", @@ -10032,6 +10084,18 @@ ".oxlintrc.json": "oxlint", "CLAUDE.md": "claude", "CLAUDE.local.md": "claude", + ".cursorignore": "cursor", + ".cursorindexingignore": "cursor", + ".cursorrules": "cursor", + ".cursor": "cursor", + ".cursor.json": "cursor", + ".cursorrc": "cursor", + "metro.config.js": "metro", + "metro.config.json": "metro", + "src/bashly.yaml": "bashly", + "src/bashly.yml": "bashly", + "bashly-settings.yaml": "bashly-settings", + "bashly-settings.yml": "bashly-settings", "xamlstyler.json": "xaml", ".rhistory": "r", "cmakepresets.json": "cmake", @@ -10113,6 +10177,7 @@ "haml": "haml", "yang": "yang", "terraform": "terraform", + "opentofu": "opentofu", "applescript": "applescript", "cake": "cake", "cucumber": "cucumber", @@ -10243,7 +10308,8 @@ "beancount": "beancount", "ahk2": "ahk2", "gnuplot": "gnuplot", - "helm": "helm" + "helm": "helm", + "nginx": "nginx" }, "light": { "fileExtensions": { @@ -10253,6 +10319,7 @@ "j2": "jinja_light", "jinja-html": "jinja_light", "toml": "toml_light", + "tofu": "opentofu_light", "huff": "huff_light", "cr": "crystal_light", "ecr": "crystal_light", @@ -10275,6 +10342,7 @@ "openapi.yml": "openapi_light", "openapi.yaml": "openapi_light", "tldr": "tldraw_light", + "verse": "verse_light", "zeabur": "zeabur_light" }, "fileNames": { @@ -10437,7 +10505,15 @@ "zeabur.yml": "zeabur_light", "zeabur.toml": "zeabur_light", "copilot-instructions.md": "copilot_light", - "hosts": "hosts_light" + "hosts": "hosts_light", + ".cursorignore": "cursor_light", + ".cursorindexingignore": "cursor_light", + ".cursorrules": "cursor_light", + ".cursor": "cursor_light", + ".cursor.json": "cursor_light", + ".cursorrc": "cursor_light", + "bashly-settings.yaml": "bashly-settings_light", + "bashly-settings.yml": "bashly-settings_light" }, "languageIds": { "toml": "toml_light", @@ -10460,7 +10536,11 @@ "idea": "folder-intellij_light", ".idea": "folder-intellij_light", "_idea": "folder-intellij_light", - "__idea__": "folder-intellij_light" + "__idea__": "folder-intellij_light", + ".cursor": "folder-cursor_light", + "..cursor": "folder-cursor_light", + "_.cursor": "folder-cursor_light", + "__.cursor__": "folder-cursor_light" }, "folderNamesExpanded": { "jinja": "folder-jinja-open_light", @@ -10478,7 +10558,11 @@ "idea": "folder-intellij-open_light", ".idea": "folder-intellij-open_light", "_idea": "folder-intellij-open_light", - "__idea__": "folder-intellij-open_light" + "__idea__": "folder-intellij-open_light", + ".cursor": "folder-cursor-open_light", + "..cursor": "folder-cursor-open_light", + "_.cursor": "folder-cursor-open_light", + "__.cursor__": "folder-cursor-open_light" }, "rootFolderNames": {}, "rootFolderNamesExpanded": {} diff --git a/options/fileicon/material-icon-svgs.json b/options/fileicon/material-icon-svgs.json index 9d1e0ee075f..9aa78359dae 100644 --- a/options/fileicon/material-icon-svgs.json +++ b/options/fileicon/material-icon-svgs.json @@ -49,6 +49,10 @@ "azure": "", "babel": "", "ballerina": "", + "bashly-hook": "", + "bashly-settings.clone": "", + "bashly-settings_light.clone": "", + "bashly": "", "bazel": "", "bbx": "", "beancount": "", @@ -116,7 +120,7 @@ "commitlint": "", "concourse": "", "conduct": "", - "console": "", + "console": "", "container.clone": "", "contentlayer": "", "context": "", @@ -134,6 +138,8 @@ "css": "", "cucumber": "", "cuda": "", + "cursor": "", + "cursor_light": "", "cypress": "", "d": "", "dart": "", @@ -287,6 +293,10 @@ "folder-coverage": "", "folder-css-open": "", "folder-css": "", + "folder-cursor-open": "", + "folder-cursor-open_light": "", + "folder-cursor": "", + "folder-cursor_light": "", "folder-custom-open": "", "folder-custom": "", "folder-cypress-open": "", @@ -339,6 +349,8 @@ "folder-fastlane": "", "folder-favicon-open": "", "folder-favicon": "", + "folder-filter-open": "", + "folder-filter": "", "folder-firebase-open": "", "folder-firebase": "", "folder-firestore-open": "", @@ -463,6 +475,8 @@ "folder-messages": "", "folder-meta-open": "", "folder-meta": "", + "folder-metro-open": "", + "folder-metro": "", "folder-middleware-open": "", "folder-middleware": "", "folder-mjml-open": "", @@ -830,6 +844,7 @@ "merlin": "", "mermaid": "", "meson": "", + "metro": "", "minecraft-fabric": "", "minecraft": "", "mint": "", @@ -881,10 +896,13 @@ "objective-cpp": "", "ocaml": "", "odin": "", + "onnx": "", "opa": "", "opam": "", "openapi": "", "openapi_light": "", + "opentofu": "", + "opentofu_light": "", "otne": "", "oxlint": "", "packship": "", @@ -935,6 +953,7 @@ "python": "", "pytorch": "", "qsharp": "", + "quarto": "", "quasar": "", "quokka": "", "qwik": "", @@ -1100,6 +1119,8 @@ "verdaccio": "", "verified": "", "verilog": "", + "verse": "", + "verse_light": "", "vfl": "", "video": "", "vim": "", diff --git a/package.json b/package.json index 79aaa880a55..5fe8e70c3f3 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "@github/relative-time-element": "4.4.8", "@github/text-expander-element": "2.9.2", "@mcaptcha/vanilla-glue": "0.1.0-alpha-3", - "@primer/octicons": "19.17.0", + "@primer/octicons": "19.18.0", "@resvg/resvg-wasm": "2.6.2", "@silverwind/vue3-calendar-heatmap": "2.0.6", "@techknowlogick/license-checker-webpack-plugin": "0.3.0", @@ -31,14 +31,14 @@ "dropzone": "6.0.0-beta.2", "easymde": "2.20.0", "esbuild-loader": "4.3.0", - "htmx.org": "2.0.6", + "htmx.org": "2.0.7", "idiomorph": "0.7.3", "jquery": "3.7.1", "katex": "0.16.22", "mermaid": "11.11.0", "mini-css-extract-plugin": "2.9.4", "minimatch": "10.0.3", - "monaco-editor": "0.52.2", + "monaco-editor": "0.53.0", "monaco-editor-webpack-plugin": "7.1.0", "online-3d-viewer": "0.16.0", "pdfobject": "2.3.1", @@ -47,7 +47,7 @@ "postcss-loader": "8.2.0", "postcss-nesting": "13.0.2", "sortablejs": "1.15.6", - "swagger-ui-dist": "5.28.1", + "swagger-ui-dist": "5.29.0", "tailwindcss": "3.4.17", "throttle-debounce": "5.0.2", "tinycolor2": "1.6.0", @@ -63,7 +63,7 @@ "vue-loader": "17.4.2", "webpack": "5.101.3", "webpack-cli": "6.0.1", - "wrap-ansi": "9.0.0" + "wrap-ansi": "9.0.2" }, "devDependencies": { "@eslint-community/eslint-plugin-eslint-comments": "4.5.0", @@ -82,8 +82,8 @@ "@types/throttle-debounce": "5.0.2", "@types/tinycolor2": "1.4.6", "@types/toastify-js": "1.12.4", - "@typescript-eslint/eslint-plugin": "8.42.0", - "@typescript-eslint/parser": "8.42.0", + "@typescript-eslint/eslint-plugin": "8.43.0", + "@typescript-eslint/parser": "8.43.0", "@vitejs/plugin-vue": "6.0.1", "@vitest/eslint-plugin": "1.3.9", "eslint": "8.57.0", @@ -102,7 +102,7 @@ "eslint-plugin-wc": "3.0.1", "happy-dom": "18.0.1", "markdownlint-cli": "0.45.0", - "material-icon-theme": "5.26.0", + "material-icon-theme": "5.27.0", "nolyfill": "1.0.44", "postcss-html": "1.8.0", "stylelint": "16.24.0", @@ -112,7 +112,7 @@ "stylelint-value-no-unknown-custom-properties": "6.0.1", "svgo": "4.0.0", "type-fest": "4.41.0", - "updates": "16.6.4", + "updates": "16.7.0", "vite-string-plugin": "1.4.6", "vitest": "3.2.4", "vue-tsc": "3.0.6" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 149d8f179c1..83a31ce8ad6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -51,8 +51,8 @@ importers: specifier: 0.1.0-alpha-3 version: 0.1.0-alpha-3 '@primer/octicons': - specifier: 19.17.0 - version: 19.17.0 + specifier: 19.18.0 + version: 19.18.0 '@resvg/resvg-wasm': specifier: 2.6.2 version: 2.6.2 @@ -102,8 +102,8 @@ importers: specifier: 4.3.0 version: 4.3.0(webpack@5.101.3) htmx.org: - specifier: 2.0.6 - version: 2.0.6 + specifier: 2.0.7 + version: 2.0.7 idiomorph: specifier: 0.7.3 version: 0.7.3 @@ -123,11 +123,11 @@ importers: specifier: 10.0.3 version: 10.0.3 monaco-editor: - specifier: 0.52.2 - version: 0.52.2 + specifier: 0.53.0 + version: 0.53.0 monaco-editor-webpack-plugin: specifier: 7.1.0 - version: 7.1.0(monaco-editor@0.52.2)(webpack@5.101.3) + version: 7.1.0(monaco-editor@0.53.0)(webpack@5.101.3) online-3d-viewer: specifier: 0.16.0 version: 0.16.0 @@ -150,8 +150,8 @@ importers: specifier: 1.15.6 version: 1.15.6 swagger-ui-dist: - specifier: 5.28.1 - version: 5.28.1 + specifier: 5.29.0 + version: 5.29.0 tailwindcss: specifier: 3.4.17 version: 3.4.17 @@ -198,8 +198,8 @@ importers: specifier: 6.0.1 version: 6.0.1(webpack@5.101.3) wrap-ansi: - specifier: 9.0.0 - version: 9.0.0 + specifier: 9.0.2 + version: 9.0.2 devDependencies: '@eslint-community/eslint-plugin-eslint-comments': specifier: 4.5.0 @@ -250,14 +250,14 @@ importers: specifier: 1.12.4 version: 1.12.4 '@typescript-eslint/eslint-plugin': - specifier: 8.42.0 - version: 8.42.0(@typescript-eslint/parser@8.42.0(eslint@8.57.0)(typescript@5.9.2))(eslint@8.57.0)(typescript@5.9.2) + specifier: 8.43.0 + version: 8.43.0(@typescript-eslint/parser@8.43.0(eslint@8.57.0)(typescript@5.9.2))(eslint@8.57.0)(typescript@5.9.2) '@typescript-eslint/parser': - specifier: 8.42.0 - version: 8.42.0(eslint@8.57.0)(typescript@5.9.2) + specifier: 8.43.0 + version: 8.43.0(eslint@8.57.0)(typescript@5.9.2) '@vitejs/plugin-vue': specifier: 6.0.1 - version: 6.0.1(vite@7.1.4(@types/node@24.3.1)(jiti@2.5.1)(stylus@0.57.0)(terser@5.44.0)(yaml@2.8.1))(vue@3.5.21(typescript@5.9.2)) + version: 6.0.1(vite@7.1.5(@types/node@24.3.1)(jiti@2.5.1)(stylus@0.57.0)(terser@5.44.0)(yaml@2.8.1))(vue@3.5.21(typescript@5.9.2)) '@vitest/eslint-plugin': specifier: 1.3.9 version: 1.3.9(eslint@8.57.0)(typescript@5.9.2)(vitest@3.2.4(@types/debug@4.1.12)(@types/node@24.3.1)(happy-dom@18.0.1)(jiti@2.5.1)(stylus@0.57.0)(terser@5.44.0)(yaml@2.8.1)) @@ -266,7 +266,7 @@ importers: version: 8.57.0 eslint-import-resolver-typescript: specifier: 4.4.4 - version: 4.4.4(eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.42.0(eslint@8.57.0)(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@8.57.0))(eslint-plugin-import@2.32.0)(eslint@8.57.0) + version: 4.4.4(eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.43.0(eslint@8.57.0)(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@8.57.0))(eslint-plugin-import@2.32.0)(eslint@8.57.0) eslint-plugin-array-func: specifier: 4.0.0 version: 4.0.0(eslint@8.57.0) @@ -275,7 +275,7 @@ importers: version: 5.0.2(@types/eslint@9.6.1)(eslint-import-resolver-typescript@4.4.4)(eslint@8.57.0)(typescript@5.9.2) eslint-plugin-import-x: specifier: 4.16.1 - version: 4.16.1(@typescript-eslint/utils@8.42.0(eslint@8.57.0)(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@8.57.0) + version: 4.16.1(@typescript-eslint/utils@8.43.0(eslint@8.57.0)(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@8.57.0) eslint-plugin-no-jquery: specifier: 3.1.1 version: 3.1.1(eslint@8.57.0) @@ -296,7 +296,7 @@ importers: version: 56.0.1(eslint@8.57.0) eslint-plugin-vue: specifier: 10.4.0 - version: 10.4.0(@typescript-eslint/parser@8.42.0(eslint@8.57.0)(typescript@5.9.2))(eslint@8.57.0)(vue-eslint-parser@10.2.0(eslint@8.57.0)) + version: 10.4.0(@typescript-eslint/parser@8.43.0(eslint@8.57.0)(typescript@5.9.2))(eslint@8.57.0)(vue-eslint-parser@10.2.0(eslint@8.57.0)) eslint-plugin-vue-scoped-css: specifier: 2.12.0 version: 2.12.0(eslint@8.57.0)(vue-eslint-parser@10.2.0(eslint@8.57.0)) @@ -310,8 +310,8 @@ importers: specifier: 0.45.0 version: 0.45.0 material-icon-theme: - specifier: 5.26.0 - version: 5.26.0 + specifier: 5.27.0 + version: 5.27.0 nolyfill: specifier: 1.0.44 version: 1.0.44 @@ -340,8 +340,8 @@ importers: specifier: 4.41.0 version: 4.41.0 updates: - specifier: 16.6.4 - version: 16.6.4 + specifier: 16.7.0 + version: 16.7.0 vite-string-plugin: specifier: 1.4.6 version: 1.4.6 @@ -665,8 +665,8 @@ packages: peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 - '@eslint-community/eslint-utils@4.8.0': - resolution: {integrity: sha512-MJQFqrZgcW0UNYLGOuQpey/oTN59vyWwplvCGZztn1cKz9agZPPYpJB7h2OMmuu7VLqkvEjN8feFZJmxNF9D+Q==} + '@eslint-community/eslint-utils@4.9.0': + resolution: {integrity: sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 @@ -876,8 +876,8 @@ packages: '@popperjs/core@2.11.8': resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==} - '@primer/octicons@19.17.0': - resolution: {integrity: sha512-uM3ET0WC2aZMetxv7CRfIw3FexIo2fYtw2EgxqLFzLjn/rh+dIQWu781chLHh9d2mSNlxedauHLQmbYi0Dd/Mg==} + '@primer/octicons@19.18.0': + resolution: {integrity: sha512-4P8FS7slUp0vHE7zLtlfOQcgF99r0tdxpriT3ahp6iwwnf1hF3OlDWXEp5n6b6G5eIY1cNr1bCrjRL+DkRjFVw==} '@resvg/resvg-wasm@2.6.2': resolution: {integrity: sha512-FqALmHI8D4o6lk/LRWDnhw95z5eO+eAa6ORjVg09YRR7BkcM6oPHU9uyC0gtQG5vpFLvgpeU4+zEAz2H8APHNw==} @@ -1334,6 +1334,9 @@ packages: '@types/toastify-js@1.12.4': resolution: {integrity: sha512-zfZHU4tKffPCnZRe7pjv/eFKzTVHozKewFCKaCjZ4gFinKgJRz/t0bkZiMCXJxPhv/ZoeDGNOeRD09R0kQZ/nw==} + '@types/trusted-types@1.0.6': + resolution: {integrity: sha512-230RC8sFeHoT6sSUlRO6a8cAnclO06eeiq1QDfiv2FGCLWFvvERWgwIQD4FWqD9A69BN7Lzee4OXwoMVnnsWDw==} + '@types/trusted-types@2.0.7': resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} @@ -1355,63 +1358,63 @@ packages: '@types/whatwg-mimetype@3.0.2': resolution: {integrity: sha512-c2AKvDT8ToxLIOUlN51gTiHXflsfIFisS4pO7pDPoKouJCESkhZnEy623gwP9laCy5lnLDAw1vAzu2vM2YLOrA==} - '@typescript-eslint/eslint-plugin@8.42.0': - resolution: {integrity: sha512-Aq2dPqsQkxHOLfb2OPv43RnIvfj05nw8v/6n3B2NABIPpHnjQnaLo9QGMTvml+tv4korl/Cjfrb/BYhoL8UUTQ==} + '@typescript-eslint/eslint-plugin@8.43.0': + resolution: {integrity: sha512-8tg+gt7ENL7KewsKMKDHXR1vm8tt9eMxjJBYINf6swonlWgkYn5NwyIgXpbbDxTNU5DgpDFfj95prcTq2clIQQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.42.0 + '@typescript-eslint/parser': ^8.43.0 eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/parser@8.42.0': - resolution: {integrity: sha512-r1XG74QgShUgXph1BYseJ+KZd17bKQib/yF3SR+demvytiRXrwd12Blnz5eYGm8tXaeRdd4x88MlfwldHoudGg==} + '@typescript-eslint/parser@8.43.0': + resolution: {integrity: sha512-B7RIQiTsCBBmY+yW4+ILd6mF5h1FUwJsVvpqkrgpszYifetQ2Ke+Z4u6aZh0CblkUGIdR59iYVyXqqZGkZ3aBw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/project-service@8.42.0': - resolution: {integrity: sha512-vfVpLHAhbPjilrabtOSNcUDmBboQNrJUiNAGoImkZKnMjs2TIcWG33s4Ds0wY3/50aZmTMqJa6PiwkwezaAklg==} + '@typescript-eslint/project-service@8.43.0': + resolution: {integrity: sha512-htB/+D/BIGoNTQYffZw4uM4NzzuolCoaA/BusuSIcC8YjmBYQioew5VUZAYdAETPjeed0hqCaW7EHg+Robq8uw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/scope-manager@8.42.0': - resolution: {integrity: sha512-51+x9o78NBAVgQzOPd17DkNTnIzJ8T/O2dmMBLoK9qbY0Gm52XJcdJcCl18ExBMiHo6jPMErUQWUv5RLE51zJw==} + '@typescript-eslint/scope-manager@8.43.0': + resolution: {integrity: sha512-daSWlQ87ZhsjrbMLvpuuMAt3y4ba57AuvadcR7f3nl8eS3BjRc8L9VLxFLk92RL5xdXOg6IQ+qKjjqNEimGuAg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/tsconfig-utils@8.42.0': - resolution: {integrity: sha512-kHeFUOdwAJfUmYKjR3CLgZSglGHjbNTi1H8sTYRYV2xX6eNz4RyJ2LIgsDLKf8Yi0/GL1WZAC/DgZBeBft8QAQ==} + '@typescript-eslint/tsconfig-utils@8.43.0': + resolution: {integrity: sha512-ALC2prjZcj2YqqL5X/bwWQmHA2em6/94GcbB/KKu5SX3EBDOsqztmmX1kMkvAJHzxk7TazKzJfFiEIagNV3qEA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/type-utils@8.42.0': - resolution: {integrity: sha512-9KChw92sbPTYVFw3JLRH1ockhyR3zqqn9lQXol3/YbI6jVxzWoGcT3AsAW0mu1MY0gYtsXnUGV/AKpkAj5tVlQ==} + '@typescript-eslint/type-utils@8.43.0': + resolution: {integrity: sha512-qaH1uLBpBuBBuRf8c1mLJ6swOfzCXryhKND04Igr4pckzSEW9JX5Aw9AgW00kwfjWJF0kk0ps9ExKTfvXfw4Qg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/types@8.42.0': - resolution: {integrity: sha512-LdtAWMiFmbRLNP7JNeY0SqEtJvGMYSzfiWBSmx+VSZ1CH+1zyl8Mmw1TT39OrtsRvIYShjJWzTDMPWZJCpwBlw==} + '@typescript-eslint/types@8.43.0': + resolution: {integrity: sha512-vQ2FZaxJpydjSZJKiSW/LJsabFFvV7KgLC5DiLhkBcykhQj8iK9BOaDmQt74nnKdLvceM5xmhaTF+pLekrxEkw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@8.42.0': - resolution: {integrity: sha512-ku/uYtT4QXY8sl9EDJETD27o3Ewdi72hcXg1ah/kkUgBvAYHLwj2ofswFFNXS+FL5G+AGkxBtvGt8pFBHKlHsQ==} + '@typescript-eslint/typescript-estree@8.43.0': + resolution: {integrity: sha512-7Vv6zlAhPb+cvEpP06WXXy/ZByph9iL6BQRBDj4kmBsW98AqEeQHlj/13X+sZOrKSo9/rNKH4Ul4f6EICREFdw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/utils@8.42.0': - resolution: {integrity: sha512-JnIzu7H3RH5BrKC4NoZqRfmjqCIS1u3hGZltDYJgkVdqAezl4L9d1ZLw+36huCujtSBSAirGINF/S4UxOcR+/g==} + '@typescript-eslint/utils@8.43.0': + resolution: {integrity: sha512-S1/tEmkUeeswxd0GGcnwuVQPFWo8NzZTOMxCvw8BX7OMxnNae+i8Tm7REQen/SwUIPoPqfKn7EaZ+YLpiB3k9g==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/visitor-keys@8.42.0': - resolution: {integrity: sha512-3WbiuzoEowaEn8RSnhJBrxSwX8ULYE9CXaPepS2C2W3NSA5NNIvBaslpBSBElPq0UGr0xVJlXFWOAKIkyylydQ==} + '@typescript-eslint/visitor-keys@8.43.0': + resolution: {integrity: sha512-T+S1KqRD4sg/bHfLwrpF/K3gQLBM1n7Rp7OjjikjTEssI2YJzQpi5WXoynOaQ93ERIuq3O8RBTOUYDKszUCEHw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@ungap/structured-clone@1.3.0': @@ -1750,16 +1753,16 @@ packages: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} - ansi-regex@6.2.0: - resolution: {integrity: sha512-TKY5pyBkHyADOPYlRT9Lx6F544mPl0vS5Ew7BJ45hA08Q+t3GjbueLliBWN3sMICk6+y7HdyxSzC4bWS8baBdg==} + ansi-regex@6.2.2: + resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} engines: {node: '>=12'} ansi-styles@4.3.0: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} - ansi-styles@6.2.1: - resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} + ansi-styles@6.2.3: + resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} engines: {node: '>=12'} ansi_up@6.0.6: @@ -2381,8 +2384,8 @@ packages: easymde@2.20.0: resolution: {integrity: sha512-V1Z5f92TfR42Na852OWnIZMbM7zotWQYTddNaLYZFVKj7APBbyZ3FYJ27gBw2grMW3R6Qdv9J8n5Ij7XRSIgXQ==} - electron-to-chromium@1.5.214: - resolution: {integrity: sha512-TpvUNdha+X3ybfU78NoQatKvQEm1oq3lf2QbnmCEdw+Bd9RuIAY+hJTvq1avzHM0f7EJfnH3vbCnbzKzisc/9Q==} + electron-to-chromium@1.5.215: + resolution: {integrity: sha512-TIvGp57UpeNetj/wV/xpFNpWGb0b/ROw372lHPx5Aafx02gjTBtWnEEcaSX3W2dLM3OSdGGyHX/cHl01JQsLaQ==} emoji-regex@10.5.0: resolution: {integrity: sha512-lb49vf1Xzfx080OKA0o6l8DQQpV+6Vg95zyCJX9VB/BqKYlhG7N4wgROUUHRA+ZPUefLnteQOad7z1kT2bV7bg==} @@ -2829,8 +2832,8 @@ packages: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} - get-east-asian-width@1.3.1: - resolution: {integrity: sha512-R1QfovbPsKmosqTnPoRFiJ7CF9MLRgb53ChvMZm+r4p76/+8yKDy17qLL2PKInORy2RkZZekuK0efYgmzTkXyQ==} + get-east-asian-width@1.4.0: + resolution: {integrity: sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==} engines: {node: '>=18'} get-set-props@0.1.0: @@ -2935,8 +2938,8 @@ packages: htmlparser2@8.0.2: resolution: {integrity: sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==} - htmx.org@2.0.6: - resolution: {integrity: sha512-7ythjYneGSk3yCHgtCnQeaoF+D+o7U2LF37WU3O0JYv3gTZSicdEFiI/Ai/NJyC5ZpYJWMpUb11OC5Lr6AfAqA==} + htmx.org@2.0.7: + resolution: {integrity: sha512-YiJqF3U5KyO28VC5mPfehKJPF+n1Gni+cupK+D69TF0nm7wY6AXn3a4mPWIikfAXtl1u1F1+ZhSCS7KT8pVmqA==} iconv-lite@0.6.3: resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} @@ -3330,8 +3333,8 @@ packages: magic-string@0.25.9: resolution: {integrity: sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==} - magic-string@0.30.18: - resolution: {integrity: sha512-yi8swmWbO17qHhwIBNeeZxTceJMeBvWJaId6dyvTSOwTipqeHhMhOrz6513r1sOKnpvQ7zkhlG8tPrpilwTxHQ==} + magic-string@0.30.19: + resolution: {integrity: sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==} markdown-escape@2.0.0: resolution: {integrity: sha512-Trz4v0+XWlwy68LJIyw3bLbsJiC8XAbRCKF9DbEtZjyndKOGVx6n+wNB0VfoRmY2LKboQLeniap3xrb6LGSJ8A==} @@ -3359,8 +3362,8 @@ packages: engines: {node: '>= 12'} hasBin: true - material-icon-theme@5.26.0: - resolution: {integrity: sha512-Etrm3gMsgCRfpyqE11dDRqb3epoqxq94Pa1QEk20D7uIImneRhtsTFvhOcbKEQfMzup8IBUI1+oYrkfwIb6Xuw==} + material-icon-theme@5.27.0: + resolution: {integrity: sha512-zB3LtPY2n6z4Kp5fSc7OT8KwAZIJRvcOq6PZR4jmAkvmW1Ot+y6lNJmNqERK9rYAT42tZD1YmkhHaMcA2KEObA==} engines: {vscode: ^1.55.0} mathml-tag-names@2.1.3: @@ -3513,8 +3516,8 @@ packages: monaco-editor: '>= 0.31.0' webpack: ^4.5.0 || 5.x - monaco-editor@0.52.2: - resolution: {integrity: sha512-GEQWEZmfkOGLdd3XK8ryrfWz3AIP8YymVXiPHEdewrUq7mh0qrKrfHLNCXcbB6sTnMLnOZ3ztSiKcciFUkIJwQ==} + monaco-editor@0.53.0: + resolution: {integrity: sha512-0WNThgC6CMWNXXBxTbaYYcunj08iB5rnx4/G56UOPeL9UVIUGGHA1GR0EWIh9Ebabj7NpCRawQ5b0hfN1jQmYQ==} moo@0.5.2: resolution: {integrity: sha512-iSAJLHYKnX41mKcJKjqvnAN9sf0LMDTXDEvFv+ffuRR9a1MIuXLjMNL6EsnDHSkKLTWNqQQ5uo61P4EbU4NU+Q==} @@ -4172,8 +4175,8 @@ packages: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} - strip-ansi@7.1.0: - resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} + strip-ansi@7.1.2: + resolution: {integrity: sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==} engines: {node: '>=12'} strip-bom@3.0.0: @@ -4268,8 +4271,8 @@ packages: svgson@5.3.1: resolution: {integrity: sha512-qdPgvUNWb40gWktBJnbJRelWcPzkLed/ShhnRsjbayXz8OtdPOzbil9jtiZdrYvSDumAz/VNQr6JaNfPx/gvPA==} - swagger-ui-dist@5.28.1: - resolution: {integrity: sha512-IvPrtNi8MvjiuDgoSmPYgg27Lvu38fnLD1OSd8Y103xXsPAqezVNnNeHnVCZ/d+CMXJblflGaIyHxAYIF3O71w==} + swagger-ui-dist@5.29.0: + resolution: {integrity: sha512-gqs7Md3AxP4mbpXAq31o5QW+wGUZsUzVatg70yXpUR245dfIis5jAzufBd+UQM/w2xSfrhvA1eqsrgnl2PbezQ==} sync-fetch@0.4.5: resolution: {integrity: sha512-esiWJ7ixSKGpd9DJPBTC4ckChqdOjIwJfYhVHkcQ2Gnm41323p1TRmEI+esTQ9ppD+b5opps2OTEGTCGX5kF+g==} @@ -4452,8 +4455,8 @@ packages: peerDependencies: browserslist: '>= 4.21.0' - updates@16.6.4: - resolution: {integrity: sha512-HHJH9SBWJr/1+iSLuS1txaq4bz2q/ENK4KHRhcTgOgJEUeBnmLeF5/0nQya9vGnRGLnrXacuAk+pTAzKuOs9ng==} + updates@16.7.0: + resolution: {integrity: sha512-GOqKdZREAlOR90YBBY8FpkmJOPjjxntYcuAKZRWXK5Pvt2CAcPREk+KeqClG3yqqk+NGWkqAsIxa1ORzQB1iQA==} engines: {node: '>=20'} hasBin: true @@ -4491,8 +4494,8 @@ packages: vite-string-plugin@1.4.6: resolution: {integrity: sha512-Csjtny8/uVIynzlaRRj4RpHrPAakNwlH9jw6kgQ8tQhc2f0zzA6bCbAgWD0y84EgB8aLNrz7pZFUqSt3LOtk+w==} - vite@7.1.4: - resolution: {integrity: sha512-X5QFK4SGynAeeIt+A7ZWnApdUyHYm+pzv/8/A57LqSGcI88U6R6ipOs3uCesdc6yl7nl+zNO0t8LmqAdXcQihw==} + vite@7.1.5: + resolution: {integrity: sha512-4cKBO9wR75r0BeIWWWId9XK9Lj6La5X846Zw9dFfzMRw38IlTk2iCcUt6hsyiDRcPidc55ZParFYDXi0nXOeLQ==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: @@ -4705,8 +4708,8 @@ packages: resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} engines: {node: '>=12'} - wrap-ansi@9.0.0: - resolution: {integrity: sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==} + wrap-ansi@9.0.2: + resolution: {integrity: sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==} engines: {node: '>=18'} wrappy@1.0.2: @@ -4983,7 +4986,7 @@ snapshots: eslint: 8.57.0 ignore: 5.3.2 - '@eslint-community/eslint-utils@4.8.0(eslint@8.57.0)': + '@eslint-community/eslint-utils@4.9.0(eslint@8.57.0)': dependencies: eslint: 8.57.0 eslint-visitor-keys: 3.4.3 @@ -5056,7 +5059,7 @@ snapshots: dependencies: string-width: 5.1.2 string-width-cjs: string-width@4.2.3 - strip-ansi: 7.1.0 + strip-ansi: 7.1.2 strip-ansi-cjs: strip-ansi@6.0.1 wrap-ansi: 8.1.0 wrap-ansi-cjs: wrap-ansi@7.0.0 @@ -5192,7 +5195,7 @@ snapshots: '@popperjs/core@2.11.8': {} - '@primer/octicons@19.17.0': + '@primer/octicons@19.18.0': dependencies: object-assign: 4.1.1 @@ -5797,6 +5800,8 @@ snapshots: '@types/toastify-js@1.12.4': {} + '@types/trusted-types@1.0.6': {} + '@types/trusted-types@2.0.7': optional: true @@ -5825,14 +5830,14 @@ snapshots: '@types/whatwg-mimetype@3.0.2': {} - '@typescript-eslint/eslint-plugin@8.42.0(@typescript-eslint/parser@8.42.0(eslint@8.57.0)(typescript@5.9.2))(eslint@8.57.0)(typescript@5.9.2)': + '@typescript-eslint/eslint-plugin@8.43.0(@typescript-eslint/parser@8.43.0(eslint@8.57.0)(typescript@5.9.2))(eslint@8.57.0)(typescript@5.9.2)': dependencies: '@eslint-community/regexpp': 4.12.1 - '@typescript-eslint/parser': 8.42.0(eslint@8.57.0)(typescript@5.9.2) - '@typescript-eslint/scope-manager': 8.42.0 - '@typescript-eslint/type-utils': 8.42.0(eslint@8.57.0)(typescript@5.9.2) - '@typescript-eslint/utils': 8.42.0(eslint@8.57.0)(typescript@5.9.2) - '@typescript-eslint/visitor-keys': 8.42.0 + '@typescript-eslint/parser': 8.43.0(eslint@8.57.0)(typescript@5.9.2) + '@typescript-eslint/scope-manager': 8.43.0 + '@typescript-eslint/type-utils': 8.43.0(eslint@8.57.0)(typescript@5.9.2) + '@typescript-eslint/utils': 8.43.0(eslint@8.57.0)(typescript@5.9.2) + '@typescript-eslint/visitor-keys': 8.43.0 eslint: 8.57.0 graphemer: 1.4.0 ignore: 7.0.5 @@ -5842,41 +5847,41 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.42.0(eslint@8.57.0)(typescript@5.9.2)': + '@typescript-eslint/parser@8.43.0(eslint@8.57.0)(typescript@5.9.2)': dependencies: - '@typescript-eslint/scope-manager': 8.42.0 - '@typescript-eslint/types': 8.42.0 - '@typescript-eslint/typescript-estree': 8.42.0(typescript@5.9.2) - '@typescript-eslint/visitor-keys': 8.42.0 + '@typescript-eslint/scope-manager': 8.43.0 + '@typescript-eslint/types': 8.43.0 + '@typescript-eslint/typescript-estree': 8.43.0(typescript@5.9.2) + '@typescript-eslint/visitor-keys': 8.43.0 debug: 4.4.1 eslint: 8.57.0 typescript: 5.9.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.42.0(typescript@5.9.2)': + '@typescript-eslint/project-service@8.43.0(typescript@5.9.2)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.42.0(typescript@5.9.2) - '@typescript-eslint/types': 8.42.0 + '@typescript-eslint/tsconfig-utils': 8.43.0(typescript@5.9.2) + '@typescript-eslint/types': 8.43.0 debug: 4.4.1 typescript: 5.9.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@8.42.0': + '@typescript-eslint/scope-manager@8.43.0': dependencies: - '@typescript-eslint/types': 8.42.0 - '@typescript-eslint/visitor-keys': 8.42.0 + '@typescript-eslint/types': 8.43.0 + '@typescript-eslint/visitor-keys': 8.43.0 - '@typescript-eslint/tsconfig-utils@8.42.0(typescript@5.9.2)': + '@typescript-eslint/tsconfig-utils@8.43.0(typescript@5.9.2)': dependencies: typescript: 5.9.2 - '@typescript-eslint/type-utils@8.42.0(eslint@8.57.0)(typescript@5.9.2)': + '@typescript-eslint/type-utils@8.43.0(eslint@8.57.0)(typescript@5.9.2)': dependencies: - '@typescript-eslint/types': 8.42.0 - '@typescript-eslint/typescript-estree': 8.42.0(typescript@5.9.2) - '@typescript-eslint/utils': 8.42.0(eslint@8.57.0)(typescript@5.9.2) + '@typescript-eslint/types': 8.43.0 + '@typescript-eslint/typescript-estree': 8.43.0(typescript@5.9.2) + '@typescript-eslint/utils': 8.43.0(eslint@8.57.0)(typescript@5.9.2) debug: 4.4.1 eslint: 8.57.0 ts-api-utils: 2.1.0(typescript@5.9.2) @@ -5884,14 +5889,14 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/types@8.42.0': {} + '@typescript-eslint/types@8.43.0': {} - '@typescript-eslint/typescript-estree@8.42.0(typescript@5.9.2)': + '@typescript-eslint/typescript-estree@8.43.0(typescript@5.9.2)': dependencies: - '@typescript-eslint/project-service': 8.42.0(typescript@5.9.2) - '@typescript-eslint/tsconfig-utils': 8.42.0(typescript@5.9.2) - '@typescript-eslint/types': 8.42.0 - '@typescript-eslint/visitor-keys': 8.42.0 + '@typescript-eslint/project-service': 8.43.0(typescript@5.9.2) + '@typescript-eslint/tsconfig-utils': 8.43.0(typescript@5.9.2) + '@typescript-eslint/types': 8.43.0 + '@typescript-eslint/visitor-keys': 8.43.0 debug: 4.4.1 fast-glob: 3.3.3 is-glob: 4.0.3 @@ -5902,20 +5907,20 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.42.0(eslint@8.57.0)(typescript@5.9.2)': + '@typescript-eslint/utils@8.43.0(eslint@8.57.0)(typescript@5.9.2)': dependencies: - '@eslint-community/eslint-utils': 4.8.0(eslint@8.57.0) - '@typescript-eslint/scope-manager': 8.42.0 - '@typescript-eslint/types': 8.42.0 - '@typescript-eslint/typescript-estree': 8.42.0(typescript@5.9.2) + '@eslint-community/eslint-utils': 4.9.0(eslint@8.57.0) + '@typescript-eslint/scope-manager': 8.43.0 + '@typescript-eslint/types': 8.43.0 + '@typescript-eslint/typescript-estree': 8.43.0(typescript@5.9.2) eslint: 8.57.0 typescript: 5.9.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@8.42.0': + '@typescript-eslint/visitor-keys@8.43.0': dependencies: - '@typescript-eslint/types': 8.42.0 + '@typescript-eslint/types': 8.43.0 eslint-visitor-keys: 4.2.1 '@ungap/structured-clone@1.3.0': {} @@ -5979,16 +5984,16 @@ snapshots: '@unrs/resolver-binding-win32-x64-msvc@1.11.1': optional: true - '@vitejs/plugin-vue@6.0.1(vite@7.1.4(@types/node@24.3.1)(jiti@2.5.1)(stylus@0.57.0)(terser@5.44.0)(yaml@2.8.1))(vue@3.5.21(typescript@5.9.2))': + '@vitejs/plugin-vue@6.0.1(vite@7.1.5(@types/node@24.3.1)(jiti@2.5.1)(stylus@0.57.0)(terser@5.44.0)(yaml@2.8.1))(vue@3.5.21(typescript@5.9.2))': dependencies: '@rolldown/pluginutils': 1.0.0-beta.29 - vite: 7.1.4(@types/node@24.3.1)(jiti@2.5.1)(stylus@0.57.0)(terser@5.44.0)(yaml@2.8.1) + vite: 7.1.5(@types/node@24.3.1)(jiti@2.5.1)(stylus@0.57.0)(terser@5.44.0)(yaml@2.8.1) vue: 3.5.21(typescript@5.9.2) '@vitest/eslint-plugin@1.3.9(eslint@8.57.0)(typescript@5.9.2)(vitest@3.2.4(@types/debug@4.1.12)(@types/node@24.3.1)(happy-dom@18.0.1)(jiti@2.5.1)(stylus@0.57.0)(terser@5.44.0)(yaml@2.8.1))': dependencies: - '@typescript-eslint/scope-manager': 8.42.0 - '@typescript-eslint/utils': 8.42.0(eslint@8.57.0)(typescript@5.9.2) + '@typescript-eslint/scope-manager': 8.43.0 + '@typescript-eslint/utils': 8.43.0(eslint@8.57.0)(typescript@5.9.2) eslint: 8.57.0 optionalDependencies: typescript: 5.9.2 @@ -6004,13 +6009,13 @@ snapshots: chai: 5.3.3 tinyrainbow: 2.0.0 - '@vitest/mocker@3.2.4(vite@7.1.4(@types/node@24.3.1)(jiti@2.5.1)(stylus@0.57.0)(terser@5.44.0)(yaml@2.8.1))': + '@vitest/mocker@3.2.4(vite@7.1.5(@types/node@24.3.1)(jiti@2.5.1)(stylus@0.57.0)(terser@5.44.0)(yaml@2.8.1))': dependencies: '@vitest/spy': 3.2.4 estree-walker: 3.0.3 - magic-string: 0.30.18 + magic-string: 0.30.19 optionalDependencies: - vite: 7.1.4(@types/node@24.3.1)(jiti@2.5.1)(stylus@0.57.0)(terser@5.44.0)(yaml@2.8.1) + vite: 7.1.5(@types/node@24.3.1)(jiti@2.5.1)(stylus@0.57.0)(terser@5.44.0)(yaml@2.8.1) '@vitest/pretty-format@3.2.4': dependencies: @@ -6025,7 +6030,7 @@ snapshots: '@vitest/snapshot@3.2.4': dependencies: '@vitest/pretty-format': 3.2.4 - magic-string: 0.30.18 + magic-string: 0.30.19 pathe: 2.0.3 '@vitest/spy@3.2.4': @@ -6071,7 +6076,7 @@ snapshots: '@vue/compiler-ssr': 3.5.21 '@vue/shared': 3.5.21 estree-walker: 2.0.2 - magic-string: 0.30.18 + magic-string: 0.30.19 postcss: 8.5.6 source-map-js: 1.2.1 @@ -6270,13 +6275,13 @@ snapshots: ansi-regex@5.0.1: {} - ansi-regex@6.2.0: {} + ansi-regex@6.2.2: {} ansi-styles@4.3.0: dependencies: color-convert: 2.0.1 - ansi-styles@6.2.1: {} + ansi-styles@6.2.3: {} ansi_up@6.0.6: {} @@ -6352,7 +6357,7 @@ snapshots: browserslist@4.25.4: dependencies: caniuse-lite: 1.0.30001741 - electron-to-chromium: 1.5.214 + electron-to-chromium: 1.5.215 node-releases: 2.0.20 update-browserslist-db: 1.1.3(browserslist@4.25.4) @@ -6880,7 +6885,7 @@ snapshots: codemirror-spell-checker: 1.1.2 marked: 4.3.0 - electron-to-chromium@1.5.214: {} + electron-to-chromium@1.5.215: {} emoji-regex@10.5.0: {} @@ -6974,7 +6979,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@4.4.4(eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.42.0(eslint@8.57.0)(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@8.57.0))(eslint-plugin-import@2.32.0)(eslint@8.57.0): + eslint-import-resolver-typescript@4.4.4(eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.43.0(eslint@8.57.0)(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@8.57.0))(eslint-plugin-import@2.32.0)(eslint@8.57.0): dependencies: debug: 4.4.1 eslint: 8.57.0 @@ -6985,19 +6990,19 @@ snapshots: tinyglobby: 0.2.15 unrs-resolver: 1.11.1 optionalDependencies: - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.42.0(eslint@8.57.0)(typescript@5.9.2))(eslint-import-resolver-typescript@4.4.4)(eslint@8.57.0) - eslint-plugin-import-x: 4.16.1(@typescript-eslint/utils@8.42.0(eslint@8.57.0)(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@8.57.0) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.43.0(eslint@8.57.0)(typescript@5.9.2))(eslint-import-resolver-typescript@4.4.4)(eslint@8.57.0) + eslint-plugin-import-x: 4.16.1(@typescript-eslint/utils@8.43.0(eslint@8.57.0)(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@8.57.0) transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.1(@typescript-eslint/parser@8.42.0(eslint@8.57.0)(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@4.4.4)(eslint@8.57.0): + eslint-module-utils@2.12.1(@typescript-eslint/parser@8.43.0(eslint@8.57.0)(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@4.4.4)(eslint@8.57.0): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 8.42.0(eslint@8.57.0)(typescript@5.9.2) + '@typescript-eslint/parser': 8.43.0(eslint@8.57.0)(typescript@5.9.2) eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 4.4.4(eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.42.0(eslint@8.57.0)(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@8.57.0))(eslint-plugin-import@2.32.0)(eslint@8.57.0) + eslint-import-resolver-typescript: 4.4.4(eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.43.0(eslint@8.57.0)(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@8.57.0))(eslint-plugin-import@2.32.0)(eslint@8.57.0) transitivePeerDependencies: - supports-color @@ -7027,8 +7032,8 @@ snapshots: eslint-plugin-github@5.0.2(@types/eslint@9.6.1)(eslint-import-resolver-typescript@4.4.4)(eslint@8.57.0)(typescript@5.9.2): dependencies: '@github/browserslist-config': 1.0.0 - '@typescript-eslint/eslint-plugin': 8.42.0(@typescript-eslint/parser@8.42.0(eslint@8.57.0)(typescript@5.9.2))(eslint@8.57.0)(typescript@5.9.2) - '@typescript-eslint/parser': 8.42.0(eslint@8.57.0)(typescript@5.9.2) + '@typescript-eslint/eslint-plugin': 8.43.0(@typescript-eslint/parser@8.43.0(eslint@8.57.0)(typescript@5.9.2))(eslint@8.57.0)(typescript@5.9.2) + '@typescript-eslint/parser': 8.43.0(eslint@8.57.0)(typescript@5.9.2) aria-query: 5.3.2 eslint: 8.57.0 eslint-config-prettier: 10.1.8(eslint@8.57.0) @@ -7036,7 +7041,7 @@ snapshots: eslint-plugin-eslint-comments: 3.2.0(eslint@8.57.0) eslint-plugin-filenames: 1.3.2(eslint@8.57.0) eslint-plugin-i18n-text: 1.0.1(eslint@8.57.0) - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.42.0(eslint@8.57.0)(typescript@5.9.2))(eslint-import-resolver-typescript@4.4.4)(eslint@8.57.0) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.43.0(eslint@8.57.0)(typescript@5.9.2))(eslint-import-resolver-typescript@4.4.4)(eslint@8.57.0) eslint-plugin-jsx-a11y: 6.10.2(eslint@8.57.0) eslint-plugin-no-only-tests: 3.3.0 eslint-plugin-prettier: 5.5.4(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@8.57.0))(eslint@8.57.0)(prettier@3.6.2) @@ -7055,9 +7060,9 @@ snapshots: dependencies: eslint: 8.57.0 - eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.42.0(eslint@8.57.0)(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@8.57.0): + eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.43.0(eslint@8.57.0)(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@8.57.0): dependencies: - '@typescript-eslint/types': 8.42.0 + '@typescript-eslint/types': 8.43.0 comment-parser: 1.4.1 debug: 4.4.1 eslint: 8.57.0 @@ -7068,12 +7073,12 @@ snapshots: stable-hash-x: 0.2.0 unrs-resolver: 1.11.1 optionalDependencies: - '@typescript-eslint/utils': 8.42.0(eslint@8.57.0)(typescript@5.9.2) + '@typescript-eslint/utils': 8.43.0(eslint@8.57.0)(typescript@5.9.2) eslint-import-resolver-node: 0.3.9 transitivePeerDependencies: - supports-color - eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.42.0(eslint@8.57.0)(typescript@5.9.2))(eslint-import-resolver-typescript@4.4.4)(eslint@8.57.0): + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.43.0(eslint@8.57.0)(typescript@5.9.2))(eslint-import-resolver-typescript@4.4.4)(eslint@8.57.0): dependencies: '@rtsao/scc': 1.1.0 array-includes: '@nolyfill/array-includes@1.0.44' @@ -7084,7 +7089,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.42.0(eslint@8.57.0)(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@4.4.4)(eslint@8.57.0) + eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.43.0(eslint@8.57.0)(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@4.4.4)(eslint@8.57.0) hasown: '@nolyfill/hasown@1.0.44' is-core-module: '@nolyfill/is-core-module@1.0.39' is-glob: 4.0.3 @@ -7096,7 +7101,7 @@ snapshots: string.prototype.trimend: '@nolyfill/string.prototype.trimend@1.0.44' tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 8.42.0(eslint@8.57.0)(typescript@5.9.2) + '@typescript-eslint/parser': 8.43.0(eslint@8.57.0)(typescript@5.9.2) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack @@ -7151,7 +7156,7 @@ snapshots: eslint-plugin-regexp@2.10.0(eslint@8.57.0): dependencies: - '@eslint-community/eslint-utils': 4.8.0(eslint@8.57.0) + '@eslint-community/eslint-utils': 4.9.0(eslint@8.57.0) '@eslint-community/regexpp': 4.12.1 comment-parser: 1.4.1 eslint: 8.57.0 @@ -7177,7 +7182,7 @@ snapshots: eslint-plugin-unicorn@56.0.1(eslint@8.57.0): dependencies: '@babel/helper-validator-identifier': 7.27.1 - '@eslint-community/eslint-utils': 4.8.0(eslint@8.57.0) + '@eslint-community/eslint-utils': 4.9.0(eslint@8.57.0) ci-info: 4.3.0 clean-regexp: 1.0.0 core-js-compat: 3.45.1 @@ -7196,7 +7201,7 @@ snapshots: eslint-plugin-vue-scoped-css@2.12.0(eslint@8.57.0)(vue-eslint-parser@10.2.0(eslint@8.57.0)): dependencies: - '@eslint-community/eslint-utils': 4.8.0(eslint@8.57.0) + '@eslint-community/eslint-utils': 4.9.0(eslint@8.57.0) eslint: 8.57.0 eslint-compat-utils: 0.6.5(eslint@8.57.0) lodash: 4.17.21 @@ -7209,9 +7214,9 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-plugin-vue@10.4.0(@typescript-eslint/parser@8.42.0(eslint@8.57.0)(typescript@5.9.2))(eslint@8.57.0)(vue-eslint-parser@10.2.0(eslint@8.57.0)): + eslint-plugin-vue@10.4.0(@typescript-eslint/parser@8.43.0(eslint@8.57.0)(typescript@5.9.2))(eslint@8.57.0)(vue-eslint-parser@10.2.0(eslint@8.57.0)): dependencies: - '@eslint-community/eslint-utils': 4.8.0(eslint@8.57.0) + '@eslint-community/eslint-utils': 4.9.0(eslint@8.57.0) eslint: 8.57.0 natural-compare: 1.4.0 nth-check: 2.1.1 @@ -7220,7 +7225,7 @@ snapshots: vue-eslint-parser: 10.2.0(eslint@8.57.0) xml-name-validator: 4.0.0 optionalDependencies: - '@typescript-eslint/parser': 8.42.0(eslint@8.57.0)(typescript@5.9.2) + '@typescript-eslint/parser': 8.43.0(eslint@8.57.0)(typescript@5.9.2) eslint-plugin-wc@3.0.1(eslint@8.57.0): dependencies: @@ -7251,7 +7256,7 @@ snapshots: eslint@8.57.0: dependencies: - '@eslint-community/eslint-utils': 4.8.0(eslint@8.57.0) + '@eslint-community/eslint-utils': 4.9.0(eslint@8.57.0) '@eslint-community/regexpp': 4.12.1 '@eslint/eslintrc': 2.1.4 '@eslint/js': 8.57.0 @@ -7443,7 +7448,7 @@ snapshots: get-caller-file@2.0.5: {} - get-east-asian-width@1.3.1: {} + get-east-asian-width@1.4.0: {} get-set-props@0.1.0: {} @@ -7555,7 +7560,7 @@ snapshots: domutils: 3.2.2 entities: 4.5.0 - htmx.org@2.0.6: {} + htmx.org@2.0.7: {} iconv-lite@0.6.3: dependencies: @@ -7882,7 +7887,7 @@ snapshots: dependencies: sourcemap-codec: 1.4.8 - magic-string@0.30.18: + magic-string@0.30.19: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -7930,7 +7935,7 @@ snapshots: marked@4.3.0: {} - material-icon-theme@5.26.0: + material-icon-theme@5.27.0: dependencies: chroma-js: 3.1.2 events: 3.3.0 @@ -8190,13 +8195,15 @@ snapshots: pkg-types: 1.3.1 ufo: 1.6.1 - monaco-editor-webpack-plugin@7.1.0(monaco-editor@0.52.2)(webpack@5.101.3): + monaco-editor-webpack-plugin@7.1.0(monaco-editor@0.53.0)(webpack@5.101.3): dependencies: loader-utils: 2.0.4 - monaco-editor: 0.52.2 + monaco-editor: 0.53.0 webpack: 5.101.3(webpack-cli@6.0.1) - monaco-editor@0.52.2: {} + monaco-editor@0.53.0: + dependencies: + '@types/trusted-types': 1.0.6 moo@0.5.2: {} @@ -8808,21 +8815,21 @@ snapshots: dependencies: eastasianwidth: 0.2.0 emoji-regex: 9.2.2 - strip-ansi: 7.1.0 + strip-ansi: 7.1.2 string-width@7.2.0: dependencies: emoji-regex: 10.5.0 - get-east-asian-width: 1.3.1 - strip-ansi: 7.1.0 + get-east-asian-width: 1.4.0 + strip-ansi: 7.1.2 strip-ansi@6.0.1: dependencies: ansi-regex: 5.0.1 - strip-ansi@7.1.0: + strip-ansi@7.1.2: dependencies: - ansi-regex: 6.2.0 + ansi-regex: 6.2.2 strip-bom@3.0.0: {} @@ -8959,7 +8966,7 @@ snapshots: deep-rename-keys: 0.2.1 xml-reader: 2.4.3 - swagger-ui-dist@5.28.1: + swagger-ui-dist@5.29.0: dependencies: '@scarf/scarf': 1.4.0 @@ -9151,7 +9158,7 @@ snapshots: escalade: 3.2.0 picocolors: 1.1.1 - updates@16.6.4: {} + updates@16.7.0: {} uri-js@4.4.1: dependencies: @@ -9182,7 +9189,7 @@ snapshots: debug: 4.4.1 es-module-lexer: 1.7.0 pathe: 2.0.3 - vite: 7.1.4(@types/node@24.3.1)(jiti@2.5.1)(stylus@0.57.0)(terser@5.44.0)(yaml@2.8.1) + vite: 7.1.5(@types/node@24.3.1)(jiti@2.5.1)(stylus@0.57.0)(terser@5.44.0)(yaml@2.8.1) transitivePeerDependencies: - '@types/node' - jiti @@ -9199,7 +9206,7 @@ snapshots: vite-string-plugin@1.4.6: {} - vite@7.1.4(@types/node@24.3.1)(jiti@2.5.1)(stylus@0.57.0)(terser@5.44.0)(yaml@2.8.1): + vite@7.1.5(@types/node@24.3.1)(jiti@2.5.1)(stylus@0.57.0)(terser@5.44.0)(yaml@2.8.1): dependencies: esbuild: 0.25.9 fdir: 6.5.0(picomatch@4.0.3) @@ -9219,7 +9226,7 @@ snapshots: dependencies: '@types/chai': 5.2.2 '@vitest/expect': 3.2.4 - '@vitest/mocker': 3.2.4(vite@7.1.4(@types/node@24.3.1)(jiti@2.5.1)(stylus@0.57.0)(terser@5.44.0)(yaml@2.8.1)) + '@vitest/mocker': 3.2.4(vite@7.1.5(@types/node@24.3.1)(jiti@2.5.1)(stylus@0.57.0)(terser@5.44.0)(yaml@2.8.1)) '@vitest/pretty-format': 3.2.4 '@vitest/runner': 3.2.4 '@vitest/snapshot': 3.2.4 @@ -9228,7 +9235,7 @@ snapshots: chai: 5.3.3 debug: 4.4.1 expect-type: 1.2.2 - magic-string: 0.30.18 + magic-string: 0.30.19 pathe: 2.0.3 picomatch: 4.0.3 std-env: 3.9.0 @@ -9237,7 +9244,7 @@ snapshots: tinyglobby: 0.2.15 tinypool: 1.1.1 tinyrainbow: 2.0.0 - vite: 7.1.4(@types/node@24.3.1)(jiti@2.5.1)(stylus@0.57.0)(terser@5.44.0)(yaml@2.8.1) + vite: 7.1.5(@types/node@24.3.1)(jiti@2.5.1)(stylus@0.57.0)(terser@5.44.0)(yaml@2.8.1) vite-node: 3.2.4(@types/node@24.3.1)(jiti@2.5.1)(stylus@0.57.0)(terser@5.44.0)(yaml@2.8.1) why-is-node-running: 2.3.0 optionalDependencies: @@ -9434,15 +9441,15 @@ snapshots: wrap-ansi@8.1.0: dependencies: - ansi-styles: 6.2.1 + ansi-styles: 6.2.3 string-width: 5.1.2 - strip-ansi: 7.1.0 + strip-ansi: 7.1.2 - wrap-ansi@9.0.0: + wrap-ansi@9.0.2: dependencies: - ansi-styles: 6.2.1 + ansi-styles: 6.2.3 string-width: 7.2.0 - strip-ansi: 7.1.0 + strip-ansi: 7.1.2 wrappy@1.0.2: {} diff --git a/public/assets/img/svg/octicon-checkbox-fill.svg b/public/assets/img/svg/octicon-checkbox-fill.svg new file mode 100644 index 00000000000..6e9085f61c6 --- /dev/null +++ b/public/assets/img/svg/octicon-checkbox-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/uv.lock b/uv.lock index 6a6374d3fa9..db2fa1212de 100644 --- a/uv.lock +++ b/uv.lock @@ -1,5 +1,5 @@ version = 1 -revision = 2 +revision = 3 requires-python = ">=3.10" [[package]] @@ -118,11 +118,11 @@ wheels = [ [[package]] name = "json5" -version = "0.12.0" +version = "0.12.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/12/be/c6c745ec4c4539b25a278b70e29793f10382947df0d9efba2fa09120895d/json5-0.12.0.tar.gz", hash = "sha256:0b4b6ff56801a1c7dc817b0241bca4ce474a0e6a163bfef3fc594d3fd263ff3a", size = 51907, upload-time = "2025-04-03T16:33:13.201Z" } +sdist = { url = "https://files.pythonhosted.org/packages/12/ae/929aee9619e9eba9015207a9d2c1c54db18311da7eb4dcf6d41ad6f0eb67/json5-0.12.1.tar.gz", hash = "sha256:b2743e77b3242f8d03c143dd975a6ec7c52e2f2afe76ed934e53503dd4ad4990", size = 52191, upload-time = "2025-08-12T19:47:42.583Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/41/9f/3500910d5a98549e3098807493851eeef2b89cdd3032227558a104dfe926/json5-0.12.0-py3-none-any.whl", hash = "sha256:6d37aa6c08b0609f16e1ec5ff94697e2cbbfbad5ac112afa05794da9ab7810db", size = 36079, upload-time = "2025-04-03T16:33:11.927Z" }, + { url = "https://files.pythonhosted.org/packages/85/e2/05328bd2621be49a6fed9e3030b1e51a2d04537d3f816d211b9cc53c5262/json5-0.12.1-py3-none-any.whl", hash = "sha256:d9c9b3bc34a5f54d43c35e11ef7cb87d8bdd098c6ace87117a7b7e83e705c1d5", size = 36119, upload-time = "2025-08-12T19:47:41.131Z" }, ] [[package]] @@ -180,81 +180,81 @@ wheels = [ [[package]] name = "regex" -version = "2025.7.34" +version = "2025.9.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0b/de/e13fa6dc61d78b30ba47481f99933a3b49a57779d625c392d8036770a60d/regex-2025.7.34.tar.gz", hash = "sha256:9ead9765217afd04a86822dfcd4ed2747dfe426e887da413b15ff0ac2457e21a", size = 400714, upload-time = "2025-07-31T00:21:16.262Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b2/5a/4c63457fbcaf19d138d72b2e9b39405954f98c0349b31c601bfcb151582c/regex-2025.9.1.tar.gz", hash = "sha256:88ac07b38d20b54d79e704e38aa3bd2c0f8027432164226bdee201a1c0c9c9ff", size = 400852, upload-time = "2025-09-01T22:10:10.479Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/50/d2/0a44a9d92370e5e105f16669acf801b215107efea9dea4317fe96e9aad67/regex-2025.7.34-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d856164d25e2b3b07b779bfed813eb4b6b6ce73c2fd818d46f47c1eb5cd79bd6", size = 484591, upload-time = "2025-07-31T00:18:46.675Z" }, - { url = "https://files.pythonhosted.org/packages/2e/b1/00c4f83aa902f1048495de9f2f33638ce970ce1cf9447b477d272a0e22bb/regex-2025.7.34-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2d15a9da5fad793e35fb7be74eec450d968e05d2e294f3e0e77ab03fa7234a83", size = 289293, upload-time = "2025-07-31T00:18:53.069Z" }, - { url = "https://files.pythonhosted.org/packages/f3/b0/5bc5c8ddc418e8be5530b43ae1f7c9303f43aeff5f40185c4287cf6732f2/regex-2025.7.34-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:95b4639c77d414efa93c8de14ce3f7965a94d007e068a94f9d4997bb9bd9c81f", size = 285932, upload-time = "2025-07-31T00:18:54.673Z" }, - { url = "https://files.pythonhosted.org/packages/46/c7/a1a28d050b23665a5e1eeb4d7f13b83ea86f0bc018da7b8f89f86ff7f094/regex-2025.7.34-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5d7de1ceed5a5f84f342ba4a9f4ae589524adf9744b2ee61b5da884b5b659834", size = 780361, upload-time = "2025-07-31T00:18:56.13Z" }, - { url = "https://files.pythonhosted.org/packages/cb/0d/82e7afe7b2c9fe3d488a6ab6145d1d97e55f822dfb9b4569aba2497e3d09/regex-2025.7.34-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:02e5860a250cd350c4933cf376c3bc9cb28948e2c96a8bc042aee7b985cfa26f", size = 849176, upload-time = "2025-07-31T00:18:57.483Z" }, - { url = "https://files.pythonhosted.org/packages/bf/16/3036e16903d8194f1490af457a7e33b06d9e9edd9576b1fe6c7ac660e9ed/regex-2025.7.34-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0a5966220b9a1a88691282b7e4350e9599cf65780ca60d914a798cb791aa1177", size = 897222, upload-time = "2025-07-31T00:18:58.721Z" }, - { url = "https://files.pythonhosted.org/packages/5a/c2/010e089ae00d31418e7d2c6601760eea1957cde12be719730c7133b8c165/regex-2025.7.34-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:48fb045bbd4aab2418dc1ba2088a5e32de4bfe64e1457b948bb328a8dc2f1c2e", size = 789831, upload-time = "2025-07-31T00:19:00.436Z" }, - { url = "https://files.pythonhosted.org/packages/dd/86/b312b7bf5c46d21dbd9a3fdc4a80fde56ea93c9c0b89cf401879635e094d/regex-2025.7.34-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:20ff8433fa45e131f7316594efe24d4679c5449c0ca69d91c2f9d21846fdf064", size = 780665, upload-time = "2025-07-31T00:19:01.828Z" }, - { url = "https://files.pythonhosted.org/packages/40/e5/674b82bfff112c820b09e3c86a423d4a568143ede7f8440fdcbce259e895/regex-2025.7.34-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:c436fd1e95c04c19039668cfb548450a37c13f051e8659f40aed426e36b3765f", size = 773511, upload-time = "2025-07-31T00:19:03.654Z" }, - { url = "https://files.pythonhosted.org/packages/2d/18/39e7c578eb6cf1454db2b64e4733d7e4f179714867a75d84492ec44fa9b2/regex-2025.7.34-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:0b85241d3cfb9f8a13cefdfbd58a2843f208f2ed2c88181bf84e22e0c7fc066d", size = 843990, upload-time = "2025-07-31T00:19:05.61Z" }, - { url = "https://files.pythonhosted.org/packages/b6/d9/522a6715aefe2f463dc60c68924abeeb8ab6893f01adf5720359d94ede8c/regex-2025.7.34-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:075641c94126b064c65ab86e7e71fc3d63e7ff1bea1fb794f0773c97cdad3a03", size = 834676, upload-time = "2025-07-31T00:19:07.023Z" }, - { url = "https://files.pythonhosted.org/packages/59/53/c4d5284cb40543566542e24f1badc9f72af68d01db21e89e36e02292eee0/regex-2025.7.34-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:70645cad3407d103d1dbcb4841839d2946f7d36cf38acbd40120fee1682151e5", size = 778420, upload-time = "2025-07-31T00:19:08.511Z" }, - { url = "https://files.pythonhosted.org/packages/ea/4a/b779a7707d4a44a7e6ee9d0d98e40b2a4de74d622966080e9c95e25e2d24/regex-2025.7.34-cp310-cp310-win32.whl", hash = "sha256:3b836eb4a95526b263c2a3359308600bd95ce7848ebd3c29af0c37c4f9627cd3", size = 263999, upload-time = "2025-07-31T00:19:10.072Z" }, - { url = "https://files.pythonhosted.org/packages/ef/6e/33c7583f5427aa039c28bff7f4103c2de5b6aa5b9edc330c61ec576b1960/regex-2025.7.34-cp310-cp310-win_amd64.whl", hash = "sha256:cbfaa401d77334613cf434f723c7e8ba585df162be76474bccc53ae4e5520b3a", size = 276023, upload-time = "2025-07-31T00:19:11.34Z" }, - { url = "https://files.pythonhosted.org/packages/9f/fc/00b32e0ac14213d76d806d952826402b49fd06d42bfabacdf5d5d016bc47/regex-2025.7.34-cp310-cp310-win_arm64.whl", hash = "sha256:bca11d3c38a47c621769433c47f364b44e8043e0de8e482c5968b20ab90a3986", size = 268357, upload-time = "2025-07-31T00:19:12.729Z" }, - { url = "https://files.pythonhosted.org/packages/0d/85/f497b91577169472f7c1dc262a5ecc65e39e146fc3a52c571e5daaae4b7d/regex-2025.7.34-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:da304313761b8500b8e175eb2040c4394a875837d5635f6256d6fa0377ad32c8", size = 484594, upload-time = "2025-07-31T00:19:13.927Z" }, - { url = "https://files.pythonhosted.org/packages/1c/c5/ad2a5c11ce9e6257fcbfd6cd965d07502f6054aaa19d50a3d7fd991ec5d1/regex-2025.7.34-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:35e43ebf5b18cd751ea81455b19acfdec402e82fe0dc6143edfae4c5c4b3909a", size = 289294, upload-time = "2025-07-31T00:19:15.395Z" }, - { url = "https://files.pythonhosted.org/packages/8e/01/83ffd9641fcf5e018f9b51aa922c3e538ac9439424fda3df540b643ecf4f/regex-2025.7.34-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:96bbae4c616726f4661fe7bcad5952e10d25d3c51ddc388189d8864fbc1b3c68", size = 285933, upload-time = "2025-07-31T00:19:16.704Z" }, - { url = "https://files.pythonhosted.org/packages/77/20/5edab2e5766f0259bc1da7381b07ce6eb4401b17b2254d02f492cd8a81a8/regex-2025.7.34-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9feab78a1ffa4f2b1e27b1bcdaad36f48c2fed4870264ce32f52a393db093c78", size = 792335, upload-time = "2025-07-31T00:19:18.561Z" }, - { url = "https://files.pythonhosted.org/packages/30/bd/744d3ed8777dce8487b2606b94925e207e7c5931d5870f47f5b643a4580a/regex-2025.7.34-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f14b36e6d4d07f1a5060f28ef3b3561c5d95eb0651741474ce4c0a4c56ba8719", size = 858605, upload-time = "2025-07-31T00:19:20.204Z" }, - { url = "https://files.pythonhosted.org/packages/99/3d/93754176289718d7578c31d151047e7b8acc7a8c20e7706716f23c49e45e/regex-2025.7.34-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:85c3a958ef8b3d5079c763477e1f09e89d13ad22198a37e9d7b26b4b17438b33", size = 905780, upload-time = "2025-07-31T00:19:21.876Z" }, - { url = "https://files.pythonhosted.org/packages/ee/2e/c689f274a92deffa03999a430505ff2aeace408fd681a90eafa92fdd6930/regex-2025.7.34-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:37555e4ae0b93358fa7c2d240a4291d4a4227cc7c607d8f85596cdb08ec0a083", size = 798868, upload-time = "2025-07-31T00:19:23.222Z" }, - { url = "https://files.pythonhosted.org/packages/0d/9e/39673688805d139b33b4a24851a71b9978d61915c4d72b5ffda324d0668a/regex-2025.7.34-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ee38926f31f1aa61b0232a3a11b83461f7807661c062df9eb88769d86e6195c3", size = 781784, upload-time = "2025-07-31T00:19:24.59Z" }, - { url = "https://files.pythonhosted.org/packages/18/bd/4c1cab12cfabe14beaa076523056b8ab0c882a8feaf0a6f48b0a75dab9ed/regex-2025.7.34-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:a664291c31cae9c4a30589bd8bc2ebb56ef880c9c6264cb7643633831e606a4d", size = 852837, upload-time = "2025-07-31T00:19:25.911Z" }, - { url = "https://files.pythonhosted.org/packages/cb/21/663d983cbb3bba537fc213a579abbd0f263fb28271c514123f3c547ab917/regex-2025.7.34-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:f3e5c1e0925e77ec46ddc736b756a6da50d4df4ee3f69536ffb2373460e2dafd", size = 844240, upload-time = "2025-07-31T00:19:27.688Z" }, - { url = "https://files.pythonhosted.org/packages/8e/2d/9beeeb913bc5d32faa913cf8c47e968da936af61ec20af5d269d0f84a100/regex-2025.7.34-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d428fc7731dcbb4e2ffe43aeb8f90775ad155e7db4347a639768bc6cd2df881a", size = 787139, upload-time = "2025-07-31T00:19:29.475Z" }, - { url = "https://files.pythonhosted.org/packages/eb/f5/9b9384415fdc533551be2ba805dd8c4621873e5df69c958f403bfd3b2b6e/regex-2025.7.34-cp311-cp311-win32.whl", hash = "sha256:e154a7ee7fa18333ad90b20e16ef84daaeac61877c8ef942ec8dfa50dc38b7a1", size = 264019, upload-time = "2025-07-31T00:19:31.129Z" }, - { url = "https://files.pythonhosted.org/packages/18/9d/e069ed94debcf4cc9626d652a48040b079ce34c7e4fb174f16874958d485/regex-2025.7.34-cp311-cp311-win_amd64.whl", hash = "sha256:24257953d5c1d6d3c129ab03414c07fc1a47833c9165d49b954190b2b7f21a1a", size = 276047, upload-time = "2025-07-31T00:19:32.497Z" }, - { url = "https://files.pythonhosted.org/packages/fd/cf/3bafbe9d1fd1db77355e7fbbbf0d0cfb34501a8b8e334deca14f94c7b315/regex-2025.7.34-cp311-cp311-win_arm64.whl", hash = "sha256:3157aa512b9e606586900888cd469a444f9b898ecb7f8931996cb715f77477f0", size = 268362, upload-time = "2025-07-31T00:19:34.094Z" }, - { url = "https://files.pythonhosted.org/packages/ff/f0/31d62596c75a33f979317658e8d261574785c6cd8672c06741ce2e2e2070/regex-2025.7.34-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:7f7211a746aced993bef487de69307a38c5ddd79257d7be83f7b202cb59ddb50", size = 485492, upload-time = "2025-07-31T00:19:35.57Z" }, - { url = "https://files.pythonhosted.org/packages/d8/16/b818d223f1c9758c3434be89aa1a01aae798e0e0df36c1f143d1963dd1ee/regex-2025.7.34-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fb31080f2bd0681484b275461b202b5ad182f52c9ec606052020fe13eb13a72f", size = 290000, upload-time = "2025-07-31T00:19:37.175Z" }, - { url = "https://files.pythonhosted.org/packages/cd/70/69506d53397b4bd6954061bae75677ad34deb7f6ca3ba199660d6f728ff5/regex-2025.7.34-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0200a5150c4cf61e407038f4b4d5cdad13e86345dac29ff9dab3d75d905cf130", size = 286072, upload-time = "2025-07-31T00:19:38.612Z" }, - { url = "https://files.pythonhosted.org/packages/b0/73/536a216d5f66084fb577bb0543b5cb7de3272eb70a157f0c3a542f1c2551/regex-2025.7.34-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:739a74970e736df0773788377969c9fea3876c2fc13d0563f98e5503e5185f46", size = 797341, upload-time = "2025-07-31T00:19:40.119Z" }, - { url = "https://files.pythonhosted.org/packages/26/af/733f8168449e56e8f404bb807ea7189f59507cbea1b67a7bbcd92f8bf844/regex-2025.7.34-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4fef81b2f7ea6a2029161ed6dea9ae13834c28eb5a95b8771828194a026621e4", size = 862556, upload-time = "2025-07-31T00:19:41.556Z" }, - { url = "https://files.pythonhosted.org/packages/19/dd/59c464d58c06c4f7d87de4ab1f590e430821345a40c5d345d449a636d15f/regex-2025.7.34-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ea74cf81fe61a7e9d77989050d0089a927ab758c29dac4e8e1b6c06fccf3ebf0", size = 910762, upload-time = "2025-07-31T00:19:43Z" }, - { url = "https://files.pythonhosted.org/packages/37/a8/b05ccf33ceca0815a1e253693b2c86544932ebcc0049c16b0fbdf18b688b/regex-2025.7.34-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e4636a7f3b65a5f340ed9ddf53585c42e3ff37101d383ed321bfe5660481744b", size = 801892, upload-time = "2025-07-31T00:19:44.645Z" }, - { url = "https://files.pythonhosted.org/packages/5f/9a/b993cb2e634cc22810afd1652dba0cae156c40d4864285ff486c73cd1996/regex-2025.7.34-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6cef962d7834437fe8d3da6f9bfc6f93f20f218266dcefec0560ed7765f5fe01", size = 786551, upload-time = "2025-07-31T00:19:46.127Z" }, - { url = "https://files.pythonhosted.org/packages/2d/79/7849d67910a0de4e26834b5bb816e028e35473f3d7ae563552ea04f58ca2/regex-2025.7.34-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:cbe1698e5b80298dbce8df4d8d1182279fbdaf1044e864cbc9d53c20e4a2be77", size = 856457, upload-time = "2025-07-31T00:19:47.562Z" }, - { url = "https://files.pythonhosted.org/packages/91/c6/de516bc082524b27e45cb4f54e28bd800c01efb26d15646a65b87b13a91e/regex-2025.7.34-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:32b9f9bcf0f605eb094b08e8da72e44badabb63dde6b83bd530580b488d1c6da", size = 848902, upload-time = "2025-07-31T00:19:49.312Z" }, - { url = "https://files.pythonhosted.org/packages/7d/22/519ff8ba15f732db099b126f039586bd372da6cd4efb810d5d66a5daeda1/regex-2025.7.34-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:524c868ba527eab4e8744a9287809579f54ae8c62fbf07d62aacd89f6026b282", size = 788038, upload-time = "2025-07-31T00:19:50.794Z" }, - { url = "https://files.pythonhosted.org/packages/3f/7d/aabb467d8f57d8149895d133c88eb809a1a6a0fe262c1d508eb9dfabb6f9/regex-2025.7.34-cp312-cp312-win32.whl", hash = "sha256:d600e58ee6d036081c89696d2bdd55d507498a7180df2e19945c6642fac59588", size = 264417, upload-time = "2025-07-31T00:19:52.292Z" }, - { url = "https://files.pythonhosted.org/packages/3b/39/bd922b55a4fc5ad5c13753274e5b536f5b06ec8eb9747675668491c7ab7a/regex-2025.7.34-cp312-cp312-win_amd64.whl", hash = "sha256:9a9ab52a466a9b4b91564437b36417b76033e8778e5af8f36be835d8cb370d62", size = 275387, upload-time = "2025-07-31T00:19:53.593Z" }, - { url = "https://files.pythonhosted.org/packages/f7/3c/c61d2fdcecb754a40475a3d1ef9a000911d3e3fc75c096acf44b0dfb786a/regex-2025.7.34-cp312-cp312-win_arm64.whl", hash = "sha256:c83aec91af9c6fbf7c743274fd952272403ad9a9db05fe9bfc9df8d12b45f176", size = 268482, upload-time = "2025-07-31T00:19:55.183Z" }, - { url = "https://files.pythonhosted.org/packages/15/16/b709b2119975035169a25aa8e4940ca177b1a2e25e14f8d996d09130368e/regex-2025.7.34-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:c3c9740a77aeef3f5e3aaab92403946a8d34437db930a0280e7e81ddcada61f5", size = 485334, upload-time = "2025-07-31T00:19:56.58Z" }, - { url = "https://files.pythonhosted.org/packages/94/a6/c09136046be0595f0331bc58a0e5f89c2d324cf734e0b0ec53cf4b12a636/regex-2025.7.34-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:69ed3bc611540f2ea70a4080f853741ec698be556b1df404599f8724690edbcd", size = 289942, upload-time = "2025-07-31T00:19:57.943Z" }, - { url = "https://files.pythonhosted.org/packages/36/91/08fc0fd0f40bdfb0e0df4134ee37cfb16e66a1044ac56d36911fd01c69d2/regex-2025.7.34-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d03c6f9dcd562c56527c42b8530aad93193e0b3254a588be1f2ed378cdfdea1b", size = 285991, upload-time = "2025-07-31T00:19:59.837Z" }, - { url = "https://files.pythonhosted.org/packages/be/2f/99dc8f6f756606f0c214d14c7b6c17270b6bbe26d5c1f05cde9dbb1c551f/regex-2025.7.34-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6164b1d99dee1dfad33f301f174d8139d4368a9fb50bf0a3603b2eaf579963ad", size = 797415, upload-time = "2025-07-31T00:20:01.668Z" }, - { url = "https://files.pythonhosted.org/packages/62/cf/2fcdca1110495458ba4e95c52ce73b361cf1cafd8a53b5c31542cde9a15b/regex-2025.7.34-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1e4f4f62599b8142362f164ce776f19d79bdd21273e86920a7b604a4275b4f59", size = 862487, upload-time = "2025-07-31T00:20:03.142Z" }, - { url = "https://files.pythonhosted.org/packages/90/38/899105dd27fed394e3fae45607c1983e138273ec167e47882fc401f112b9/regex-2025.7.34-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:72a26dcc6a59c057b292f39d41465d8233a10fd69121fa24f8f43ec6294e5415", size = 910717, upload-time = "2025-07-31T00:20:04.727Z" }, - { url = "https://files.pythonhosted.org/packages/ee/f6/4716198dbd0bcc9c45625ac4c81a435d1c4d8ad662e8576dac06bab35b17/regex-2025.7.34-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d5273fddf7a3e602695c92716c420c377599ed3c853ea669c1fe26218867002f", size = 801943, upload-time = "2025-07-31T00:20:07.1Z" }, - { url = "https://files.pythonhosted.org/packages/40/5d/cff8896d27e4e3dd11dd72ac78797c7987eb50fe4debc2c0f2f1682eb06d/regex-2025.7.34-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c1844be23cd40135b3a5a4dd298e1e0c0cb36757364dd6cdc6025770363e06c1", size = 786664, upload-time = "2025-07-31T00:20:08.818Z" }, - { url = "https://files.pythonhosted.org/packages/10/29/758bf83cf7b4c34f07ac3423ea03cee3eb3176941641e4ccc05620f6c0b8/regex-2025.7.34-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:dde35e2afbbe2272f8abee3b9fe6772d9b5a07d82607b5788e8508974059925c", size = 856457, upload-time = "2025-07-31T00:20:10.328Z" }, - { url = "https://files.pythonhosted.org/packages/d7/30/c19d212b619963c5b460bfed0ea69a092c6a43cba52a973d46c27b3e2975/regex-2025.7.34-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:f3f6e8e7af516a7549412ce57613e859c3be27d55341a894aacaa11703a4c31a", size = 849008, upload-time = "2025-07-31T00:20:11.823Z" }, - { url = "https://files.pythonhosted.org/packages/9e/b8/3c35da3b12c87e3cc00010ef6c3a4ae787cff0bc381aa3d251def219969a/regex-2025.7.34-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:469142fb94a869beb25b5f18ea87646d21def10fbacb0bcb749224f3509476f0", size = 788101, upload-time = "2025-07-31T00:20:13.729Z" }, - { url = "https://files.pythonhosted.org/packages/47/80/2f46677c0b3c2b723b2c358d19f9346e714113865da0f5f736ca1a883bde/regex-2025.7.34-cp313-cp313-win32.whl", hash = "sha256:da7507d083ee33ccea1310447410c27ca11fb9ef18c95899ca57ff60a7e4d8f1", size = 264401, upload-time = "2025-07-31T00:20:15.233Z" }, - { url = "https://files.pythonhosted.org/packages/be/fa/917d64dd074682606a003cba33585c28138c77d848ef72fc77cbb1183849/regex-2025.7.34-cp313-cp313-win_amd64.whl", hash = "sha256:9d644de5520441e5f7e2db63aec2748948cc39ed4d7a87fd5db578ea4043d997", size = 275368, upload-time = "2025-07-31T00:20:16.711Z" }, - { url = "https://files.pythonhosted.org/packages/65/cd/f94383666704170a2154a5df7b16be28f0c27a266bffcd843e58bc84120f/regex-2025.7.34-cp313-cp313-win_arm64.whl", hash = "sha256:7bf1c5503a9f2cbd2f52d7e260acb3131b07b6273c470abb78568174fe6bde3f", size = 268482, upload-time = "2025-07-31T00:20:18.189Z" }, - { url = "https://files.pythonhosted.org/packages/ac/23/6376f3a23cf2f3c00514b1cdd8c990afb4dfbac3cb4a68b633c6b7e2e307/regex-2025.7.34-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:8283afe7042d8270cecf27cca558873168e771183d4d593e3c5fe5f12402212a", size = 485385, upload-time = "2025-07-31T00:20:19.692Z" }, - { url = "https://files.pythonhosted.org/packages/73/5b/6d4d3a0b4d312adbfd6d5694c8dddcf1396708976dd87e4d00af439d962b/regex-2025.7.34-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:6c053f9647e3421dd2f5dff8172eb7b4eec129df9d1d2f7133a4386319b47435", size = 289788, upload-time = "2025-07-31T00:20:21.941Z" }, - { url = "https://files.pythonhosted.org/packages/92/71/5862ac9913746e5054d01cb9fb8125b3d0802c0706ef547cae1e7f4428fa/regex-2025.7.34-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:a16dd56bbcb7d10e62861c3cd000290ddff28ea142ffb5eb3470f183628011ac", size = 286136, upload-time = "2025-07-31T00:20:26.146Z" }, - { url = "https://files.pythonhosted.org/packages/27/df/5b505dc447eb71278eba10d5ec940769ca89c1af70f0468bfbcb98035dc2/regex-2025.7.34-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:69c593ff5a24c0d5c1112b0df9b09eae42b33c014bdca7022d6523b210b69f72", size = 797753, upload-time = "2025-07-31T00:20:27.919Z" }, - { url = "https://files.pythonhosted.org/packages/86/38/3e3dc953d13998fa047e9a2414b556201dbd7147034fbac129392363253b/regex-2025.7.34-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:98d0ce170fcde1a03b5df19c5650db22ab58af375aaa6ff07978a85c9f250f0e", size = 863263, upload-time = "2025-07-31T00:20:29.803Z" }, - { url = "https://files.pythonhosted.org/packages/68/e5/3ff66b29dde12f5b874dda2d9dec7245c2051f2528d8c2a797901497f140/regex-2025.7.34-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d72765a4bff8c43711d5b0f5b452991a9947853dfa471972169b3cc0ba1d0751", size = 910103, upload-time = "2025-07-31T00:20:31.313Z" }, - { url = "https://files.pythonhosted.org/packages/9e/fe/14176f2182125977fba3711adea73f472a11f3f9288c1317c59cd16ad5e6/regex-2025.7.34-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4494f8fd95a77eb434039ad8460e64d57baa0434f1395b7da44015bef650d0e4", size = 801709, upload-time = "2025-07-31T00:20:33.323Z" }, - { url = "https://files.pythonhosted.org/packages/5a/0d/80d4e66ed24f1ba876a9e8e31b709f9fd22d5c266bf5f3ab3c1afe683d7d/regex-2025.7.34-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:4f42b522259c66e918a0121a12429b2abcf696c6f967fa37bdc7b72e61469f98", size = 786726, upload-time = "2025-07-31T00:20:35.252Z" }, - { url = "https://files.pythonhosted.org/packages/12/75/c3ebb30e04a56c046f5c85179dc173818551037daae2c0c940c7b19152cb/regex-2025.7.34-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:aaef1f056d96a0a5d53ad47d019d5b4c66fe4be2da87016e0d43b7242599ffc7", size = 857306, upload-time = "2025-07-31T00:20:37.12Z" }, - { url = "https://files.pythonhosted.org/packages/b1/b2/a4dc5d8b14f90924f27f0ac4c4c4f5e195b723be98adecc884f6716614b6/regex-2025.7.34-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:656433e5b7dccc9bc0da6312da8eb897b81f5e560321ec413500e5367fcd5d47", size = 848494, upload-time = "2025-07-31T00:20:38.818Z" }, - { url = "https://files.pythonhosted.org/packages/0d/21/9ac6e07a4c5e8646a90b56b61f7e9dac11ae0747c857f91d3d2bc7c241d9/regex-2025.7.34-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:e91eb2c62c39705e17b4d42d4b86c4e86c884c0d15d9c5a47d0835f8387add8e", size = 787850, upload-time = "2025-07-31T00:20:40.478Z" }, - { url = "https://files.pythonhosted.org/packages/be/6c/d51204e28e7bc54f9a03bb799b04730d7e54ff2718862b8d4e09e7110a6a/regex-2025.7.34-cp314-cp314-win32.whl", hash = "sha256:f978ddfb6216028c8f1d6b0f7ef779949498b64117fc35a939022f67f810bdcb", size = 269730, upload-time = "2025-07-31T00:20:42.253Z" }, - { url = "https://files.pythonhosted.org/packages/74/52/a7e92d02fa1fdef59d113098cb9f02c5d03289a0e9f9e5d4d6acccd10677/regex-2025.7.34-cp314-cp314-win_amd64.whl", hash = "sha256:4b7dc33b9b48fb37ead12ffc7bdb846ac72f99a80373c4da48f64b373a7abeae", size = 278640, upload-time = "2025-07-31T00:20:44.42Z" }, - { url = "https://files.pythonhosted.org/packages/d1/78/a815529b559b1771080faa90c3ab401730661f99d495ab0071649f139ebd/regex-2025.7.34-cp314-cp314-win_arm64.whl", hash = "sha256:4b8c4d39f451e64809912c82392933d80fe2e4a87eeef8859fcc5380d0173c64", size = 271757, upload-time = "2025-07-31T00:20:46.355Z" }, + { url = "https://files.pythonhosted.org/packages/46/c1/ed9ef923156105a78aa004f9390e5dd87eadc29f5ca8840f172cadb638de/regex-2025.9.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:c5aa2a6a73bf218515484b36a0d20c6ad9dc63f6339ff6224147b0e2c095ee55", size = 484813, upload-time = "2025-09-01T22:07:45.528Z" }, + { url = "https://files.pythonhosted.org/packages/05/de/97957618a774c67f892609eee2fafe3e30703fbbba66de5e6b79d7196dbc/regex-2025.9.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8c2ff5c01d5e47ad5fc9d31bcd61e78c2fa0068ed00cab86b7320214446da766", size = 288981, upload-time = "2025-09-01T22:07:48.464Z" }, + { url = "https://files.pythonhosted.org/packages/3c/b0/441afadd0a6ffccbd58a9663e5bdd182daa237893e5f8ceec6ff9df4418a/regex-2025.9.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d49dc84e796b666181de8a9973284cad6616335f01b52bf099643253094920fc", size = 286608, upload-time = "2025-09-01T22:07:50.484Z" }, + { url = "https://files.pythonhosted.org/packages/6e/cf/d89aecaf17e999ab11a3ef73fc9ab8b64f4e156f121250ef84340b35338d/regex-2025.9.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d9914fe1040874f83c15fcea86d94ea54091b0666eab330aaab69e30d106aabe", size = 780459, upload-time = "2025-09-01T22:07:52.34Z" }, + { url = "https://files.pythonhosted.org/packages/f6/05/05884594a9975a29597917bbdd6837f7b97e8ac23faf22d628aa781e58f7/regex-2025.9.1-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e71bceb3947362ec5eabd2ca0870bb78eae4edfc60c6c21495133c01b6cd2df4", size = 849276, upload-time = "2025-09-01T22:07:54.591Z" }, + { url = "https://files.pythonhosted.org/packages/8c/8d/2b3067506838d02096bf107beb129b2ce328cdf776d6474b7f542c0a7bfd/regex-2025.9.1-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:67a74456f410fe5e869239ee7a5423510fe5121549af133809d9591a8075893f", size = 897320, upload-time = "2025-09-01T22:07:56.129Z" }, + { url = "https://files.pythonhosted.org/packages/9e/b3/0f9f7766e980b900df0ba9901b52871a2e4203698fb35cdebd219240d5f7/regex-2025.9.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5c3b96ed0223b32dbdc53a83149b6de7ca3acd5acd9c8e64b42a166228abe29c", size = 789931, upload-time = "2025-09-01T22:07:57.834Z" }, + { url = "https://files.pythonhosted.org/packages/47/9f/7b2f29c8f8b698eb44be5fc68e8b9c8d32e99635eac5defc98de114e9f35/regex-2025.9.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:113d5aa950f428faf46fd77d452df62ebb4cc6531cb619f6cc30a369d326bfbd", size = 780764, upload-time = "2025-09-01T22:07:59.413Z" }, + { url = "https://files.pythonhosted.org/packages/ac/ac/56176caa86155c14462531eb0a4ddc450d17ba8875001122b3b7c0cb01bf/regex-2025.9.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:fcdeb38de4f7f3d69d798f4f371189061446792a84e7c92b50054c87aae9c07c", size = 773610, upload-time = "2025-09-01T22:08:01.042Z" }, + { url = "https://files.pythonhosted.org/packages/39/e8/9d6b9bd43998268a9de2f35602077519cacc9cb149f7381758cf8f502ba7/regex-2025.9.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:4bcdff370509164b67a6c8ec23c9fb40797b72a014766fdc159bb809bd74f7d8", size = 844090, upload-time = "2025-09-01T22:08:02.94Z" }, + { url = "https://files.pythonhosted.org/packages/fd/92/d89743b089005cae4cb81cc2fe177e180b7452e60f29de53af34349640f8/regex-2025.9.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:7383efdf6e8e8c61d85e00cfb2e2e18da1a621b8bfb4b0f1c2747db57b942b8f", size = 834775, upload-time = "2025-09-01T22:08:04.781Z" }, + { url = "https://files.pythonhosted.org/packages/01/8f/86a3e0aaa89295d2a3445bb238e56369963ef6b02a5b4aa3362f4e687413/regex-2025.9.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:1ec2bd3bdf0f73f7e9f48dca550ba7d973692d5e5e9a90ac42cc5f16c4432d8b", size = 778521, upload-time = "2025-09-01T22:08:06.596Z" }, + { url = "https://files.pythonhosted.org/packages/3e/df/72072acb370ee8577c255717f8a58264f1d0de40aa3c9e6ebd5271cac633/regex-2025.9.1-cp310-cp310-win32.whl", hash = "sha256:9627e887116c4e9c0986d5c3b4f52bcfe3df09850b704f62ec3cbf177a0ae374", size = 264105, upload-time = "2025-09-01T22:08:08.708Z" }, + { url = "https://files.pythonhosted.org/packages/97/73/fb82faaf0375aeaa1bb675008246c79b6779fa5688585a35327610ea0e2e/regex-2025.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:94533e32dc0065eca43912ee6649c90ea0681d59f56d43c45b5bcda9a740b3dd", size = 276131, upload-time = "2025-09-01T22:08:10.156Z" }, + { url = "https://files.pythonhosted.org/packages/d3/3a/77d7718a2493e54725494f44da1a1e55704743dc4b8fabe5b0596f7b8014/regex-2025.9.1-cp310-cp310-win_arm64.whl", hash = "sha256:a874a61bb580d48642ffd338570ee24ab13fa023779190513fcacad104a6e251", size = 268462, upload-time = "2025-09-01T22:08:11.651Z" }, + { url = "https://files.pythonhosted.org/packages/06/4d/f741543c0c59f96c6625bc6c11fea1da2e378b7d293ffff6f318edc0ce14/regex-2025.9.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e5bcf112b09bfd3646e4db6bf2e598534a17d502b0c01ea6550ba4eca780c5e6", size = 484811, upload-time = "2025-09-01T22:08:12.834Z" }, + { url = "https://files.pythonhosted.org/packages/c2/bd/27e73e92635b6fbd51afc26a414a3133243c662949cd1cda677fe7bb09bd/regex-2025.9.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:67a0295a3c31d675a9ee0238d20238ff10a9a2fdb7a1323c798fc7029578b15c", size = 288977, upload-time = "2025-09-01T22:08:14.499Z" }, + { url = "https://files.pythonhosted.org/packages/eb/7d/7dc0c6efc8bc93cd6e9b947581f5fde8a5dbaa0af7c4ec818c5729fdc807/regex-2025.9.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ea8267fbadc7d4bd7c1301a50e85c2ff0de293ff9452a1a9f8d82c6cafe38179", size = 286606, upload-time = "2025-09-01T22:08:15.881Z" }, + { url = "https://files.pythonhosted.org/packages/d1/01/9b5c6dd394f97c8f2c12f6e8f96879c9ac27292a718903faf2e27a0c09f6/regex-2025.9.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6aeff21de7214d15e928fb5ce757f9495214367ba62875100d4c18d293750cc1", size = 792436, upload-time = "2025-09-01T22:08:17.38Z" }, + { url = "https://files.pythonhosted.org/packages/fc/24/b7430cfc6ee34bbb3db6ff933beb5e7692e5cc81e8f6f4da63d353566fb0/regex-2025.9.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:d89f1bbbbbc0885e1c230f7770d5e98f4f00b0ee85688c871d10df8b184a6323", size = 858705, upload-time = "2025-09-01T22:08:19.037Z" }, + { url = "https://files.pythonhosted.org/packages/d6/98/155f914b4ea6ae012663188545c4f5216c11926d09b817127639d618b003/regex-2025.9.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ca3affe8ddea498ba9d294ab05f5f2d3b5ad5d515bc0d4a9016dd592a03afe52", size = 905881, upload-time = "2025-09-01T22:08:20.377Z" }, + { url = "https://files.pythonhosted.org/packages/8a/a7/a470e7bc8259c40429afb6d6a517b40c03f2f3e455c44a01abc483a1c512/regex-2025.9.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:91892a7a9f0a980e4c2c85dd19bc14de2b219a3a8867c4b5664b9f972dcc0c78", size = 798968, upload-time = "2025-09-01T22:08:22.081Z" }, + { url = "https://files.pythonhosted.org/packages/1d/fa/33f6fec4d41449fea5f62fdf5e46d668a1c046730a7f4ed9f478331a8e3a/regex-2025.9.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e1cb40406f4ae862710615f9f636c1e030fd6e6abe0e0f65f6a695a2721440c6", size = 781884, upload-time = "2025-09-01T22:08:23.832Z" }, + { url = "https://files.pythonhosted.org/packages/42/de/2b45f36ab20da14eedddf5009d370625bc5942d9953fa7e5037a32d66843/regex-2025.9.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:94f6cff6f7e2149c7e6499a6ecd4695379eeda8ccbccb9726e8149f2fe382e92", size = 852935, upload-time = "2025-09-01T22:08:25.536Z" }, + { url = "https://files.pythonhosted.org/packages/1e/f9/878f4fc92c87e125e27aed0f8ee0d1eced9b541f404b048f66f79914475a/regex-2025.9.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:6c0226fb322b82709e78c49cc33484206647f8a39954d7e9de1567f5399becd0", size = 844340, upload-time = "2025-09-01T22:08:27.141Z" }, + { url = "https://files.pythonhosted.org/packages/90/c2/5b6f2bce6ece5f8427c718c085eca0de4bbb4db59f54db77aa6557aef3e9/regex-2025.9.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a12f59c7c380b4fcf7516e9cbb126f95b7a9518902bcf4a852423ff1dcd03e6a", size = 787238, upload-time = "2025-09-01T22:08:28.75Z" }, + { url = "https://files.pythonhosted.org/packages/47/66/1ef1081c831c5b611f6f55f6302166cfa1bc9574017410ba5595353f846a/regex-2025.9.1-cp311-cp311-win32.whl", hash = "sha256:49865e78d147a7a4f143064488da5d549be6bfc3f2579e5044cac61f5c92edd4", size = 264118, upload-time = "2025-09-01T22:08:30.388Z" }, + { url = "https://files.pythonhosted.org/packages/ad/e0/8adc550d7169df1d6b9be8ff6019cda5291054a0107760c2f30788b6195f/regex-2025.9.1-cp311-cp311-win_amd64.whl", hash = "sha256:d34b901f6f2f02ef60f4ad3855d3a02378c65b094efc4b80388a3aeb700a5de7", size = 276151, upload-time = "2025-09-01T22:08:32.073Z" }, + { url = "https://files.pythonhosted.org/packages/cb/bd/46fef29341396d955066e55384fb93b0be7d64693842bf4a9a398db6e555/regex-2025.9.1-cp311-cp311-win_arm64.whl", hash = "sha256:47d7c2dab7e0b95b95fd580087b6ae196039d62306a592fa4e162e49004b6299", size = 268460, upload-time = "2025-09-01T22:08:33.281Z" }, + { url = "https://files.pythonhosted.org/packages/39/ef/a0372febc5a1d44c1be75f35d7e5aff40c659ecde864d7fa10e138f75e74/regex-2025.9.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:84a25164bd8dcfa9f11c53f561ae9766e506e580b70279d05a7946510bdd6f6a", size = 486317, upload-time = "2025-09-01T22:08:34.529Z" }, + { url = "https://files.pythonhosted.org/packages/b5/25/d64543fb7eb41a1024786d518cc57faf1ce64aa6e9ddba097675a0c2f1d2/regex-2025.9.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:645e88a73861c64c1af558dd12294fb4e67b5c1eae0096a60d7d8a2143a611c7", size = 289698, upload-time = "2025-09-01T22:08:36.162Z" }, + { url = "https://files.pythonhosted.org/packages/d8/dc/fbf31fc60be317bd9f6f87daa40a8a9669b3b392aa8fe4313df0a39d0722/regex-2025.9.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:10a450cba5cd5409526ee1d4449f42aad38dd83ac6948cbd6d7f71ca7018f7db", size = 287242, upload-time = "2025-09-01T22:08:37.794Z" }, + { url = "https://files.pythonhosted.org/packages/0f/74/f933a607a538f785da5021acf5323961b4620972e2c2f1f39b6af4b71db7/regex-2025.9.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e9dc5991592933a4192c166eeb67b29d9234f9c86344481173d1bc52f73a7104", size = 797441, upload-time = "2025-09-01T22:08:39.108Z" }, + { url = "https://files.pythonhosted.org/packages/89/d0/71fc49b4f20e31e97f199348b8c4d6e613e7b6a54a90eb1b090c2b8496d7/regex-2025.9.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a32291add816961aab472f4fad344c92871a2ee33c6c219b6598e98c1f0108f2", size = 862654, upload-time = "2025-09-01T22:08:40.586Z" }, + { url = "https://files.pythonhosted.org/packages/59/05/984edce1411a5685ba9abbe10d42cdd9450aab4a022271f9585539788150/regex-2025.9.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:588c161a68a383478e27442a678e3b197b13c5ba51dbba40c1ccb8c4c7bee9e9", size = 910862, upload-time = "2025-09-01T22:08:42.416Z" }, + { url = "https://files.pythonhosted.org/packages/b2/02/5c891bb5fe0691cc1bad336e3a94b9097fbcf9707ec8ddc1dce9f0397289/regex-2025.9.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:47829ffaf652f30d579534da9085fe30c171fa2a6744a93d52ef7195dc38218b", size = 801991, upload-time = "2025-09-01T22:08:44.072Z" }, + { url = "https://files.pythonhosted.org/packages/f1/ae/fd10d6ad179910f7a1b3e0a7fde1ef8bb65e738e8ac4fd6ecff3f52252e4/regex-2025.9.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1e978e5a35b293ea43f140c92a3269b6ab13fe0a2bf8a881f7ac740f5a6ade85", size = 786651, upload-time = "2025-09-01T22:08:46.079Z" }, + { url = "https://files.pythonhosted.org/packages/30/cf/9d686b07bbc5bf94c879cc168db92542d6bc9fb67088d03479fef09ba9d3/regex-2025.9.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4cf09903e72411f4bf3ac1eddd624ecfd423f14b2e4bf1c8b547b72f248b7bf7", size = 856556, upload-time = "2025-09-01T22:08:48.376Z" }, + { url = "https://files.pythonhosted.org/packages/91/9d/302f8a29bb8a49528abbab2d357a793e2a59b645c54deae0050f8474785b/regex-2025.9.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:d016b0f77be63e49613c9e26aaf4a242f196cd3d7a4f15898f5f0ab55c9b24d2", size = 849001, upload-time = "2025-09-01T22:08:50.067Z" }, + { url = "https://files.pythonhosted.org/packages/93/fa/b4c6dbdedc85ef4caec54c817cd5f4418dbfa2453214119f2538082bf666/regex-2025.9.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:656563e620de6908cd1c9d4f7b9e0777e3341ca7db9d4383bcaa44709c90281e", size = 788138, upload-time = "2025-09-01T22:08:51.933Z" }, + { url = "https://files.pythonhosted.org/packages/4a/1b/91ee17a3cbf87f81e8c110399279d0e57f33405468f6e70809100f2ff7d8/regex-2025.9.1-cp312-cp312-win32.whl", hash = "sha256:df33f4ef07b68f7ab637b1dbd70accbf42ef0021c201660656601e8a9835de45", size = 264524, upload-time = "2025-09-01T22:08:53.75Z" }, + { url = "https://files.pythonhosted.org/packages/92/28/6ba31cce05b0f1ec6b787921903f83bd0acf8efde55219435572af83c350/regex-2025.9.1-cp312-cp312-win_amd64.whl", hash = "sha256:5aba22dfbc60cda7c0853516104724dc904caa2db55f2c3e6e984eb858d3edf3", size = 275489, upload-time = "2025-09-01T22:08:55.037Z" }, + { url = "https://files.pythonhosted.org/packages/bd/ed/ea49f324db00196e9ef7fe00dd13c6164d5173dd0f1bbe495e61bb1fb09d/regex-2025.9.1-cp312-cp312-win_arm64.whl", hash = "sha256:ec1efb4c25e1849c2685fa95da44bfde1b28c62d356f9c8d861d4dad89ed56e9", size = 268589, upload-time = "2025-09-01T22:08:56.369Z" }, + { url = "https://files.pythonhosted.org/packages/98/25/b2959ce90c6138c5142fe5264ee1f9b71a0c502ca4c7959302a749407c79/regex-2025.9.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:bc6834727d1b98d710a63e6c823edf6ffbf5792eba35d3fa119531349d4142ef", size = 485932, upload-time = "2025-09-01T22:08:57.913Z" }, + { url = "https://files.pythonhosted.org/packages/49/2e/6507a2a85f3f2be6643438b7bd976e67ad73223692d6988eb1ff444106d3/regex-2025.9.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c3dc05b6d579875719bccc5f3037b4dc80433d64e94681a0061845bd8863c025", size = 289568, upload-time = "2025-09-01T22:08:59.258Z" }, + { url = "https://files.pythonhosted.org/packages/c7/d8/de4a4b57215d99868f1640e062a7907e185ec7476b4b689e2345487c1ff4/regex-2025.9.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:22213527df4c985ec4a729b055a8306272d41d2f45908d7bacb79be0fa7a75ad", size = 286984, upload-time = "2025-09-01T22:09:00.835Z" }, + { url = "https://files.pythonhosted.org/packages/03/15/e8cb403403a57ed316e80661db0e54d7aa2efcd85cb6156f33cc18746922/regex-2025.9.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8e3f6e3c5a5a1adc3f7ea1b5aec89abfc2f4fbfba55dafb4343cd1d084f715b2", size = 797514, upload-time = "2025-09-01T22:09:02.538Z" }, + { url = "https://files.pythonhosted.org/packages/e4/26/2446f2b9585fed61faaa7e2bbce3aca7dd8df6554c32addee4c4caecf24a/regex-2025.9.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:bcb89c02a0d6c2bec9b0bb2d8c78782699afe8434493bfa6b4021cc51503f249", size = 862586, upload-time = "2025-09-01T22:09:04.322Z" }, + { url = "https://files.pythonhosted.org/packages/fd/b8/82ffbe9c0992c31bbe6ae1c4b4e21269a5df2559102b90543c9b56724c3c/regex-2025.9.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b0e2f95413eb0c651cd1516a670036315b91b71767af83bc8525350d4375ccba", size = 910815, upload-time = "2025-09-01T22:09:05.978Z" }, + { url = "https://files.pythonhosted.org/packages/2f/d8/7303ea38911759c1ee30cc5bc623ee85d3196b733c51fd6703c34290a8d9/regex-2025.9.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:09a41dc039e1c97d3c2ed3e26523f748e58c4de3ea7a31f95e1cf9ff973fff5a", size = 802042, upload-time = "2025-09-01T22:09:07.865Z" }, + { url = "https://files.pythonhosted.org/packages/fc/0e/6ad51a55ed4b5af512bb3299a05d33309bda1c1d1e1808fa869a0bed31bc/regex-2025.9.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4f0b4258b161094f66857a26ee938d3fe7b8a5063861e44571215c44fbf0e5df", size = 786764, upload-time = "2025-09-01T22:09:09.362Z" }, + { url = "https://files.pythonhosted.org/packages/8d/d5/394e3ffae6baa5a9217bbd14d96e0e5da47bb069d0dbb8278e2681a2b938/regex-2025.9.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:bf70e18ac390e6977ea7e56f921768002cb0fa359c4199606c7219854ae332e0", size = 856557, upload-time = "2025-09-01T22:09:11.129Z" }, + { url = "https://files.pythonhosted.org/packages/cd/80/b288d3910c41194ad081b9fb4b371b76b0bbfdce93e7709fc98df27b37dc/regex-2025.9.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:b84036511e1d2bb0a4ff1aec26951caa2dea8772b223c9e8a19ed8885b32dbac", size = 849108, upload-time = "2025-09-01T22:09:12.877Z" }, + { url = "https://files.pythonhosted.org/packages/d1/cd/5ec76bf626d0d5abdc277b7a1734696f5f3d14fbb4a3e2540665bc305d85/regex-2025.9.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c2e05dcdfe224047f2a59e70408274c325d019aad96227ab959403ba7d58d2d7", size = 788201, upload-time = "2025-09-01T22:09:14.561Z" }, + { url = "https://files.pythonhosted.org/packages/b5/36/674672f3fdead107565a2499f3007788b878188acec6d42bc141c5366c2c/regex-2025.9.1-cp313-cp313-win32.whl", hash = "sha256:3b9a62107a7441b81ca98261808fed30ae36ba06c8b7ee435308806bd53c1ed8", size = 264508, upload-time = "2025-09-01T22:09:16.193Z" }, + { url = "https://files.pythonhosted.org/packages/83/ad/931134539515eb64ce36c24457a98b83c1b2e2d45adf3254b94df3735a76/regex-2025.9.1-cp313-cp313-win_amd64.whl", hash = "sha256:b38afecc10c177eb34cfae68d669d5161880849ba70c05cbfbe409f08cc939d7", size = 275469, upload-time = "2025-09-01T22:09:17.462Z" }, + { url = "https://files.pythonhosted.org/packages/24/8c/96d34e61c0e4e9248836bf86d69cb224fd222f270fa9045b24e218b65604/regex-2025.9.1-cp313-cp313-win_arm64.whl", hash = "sha256:ec329890ad5e7ed9fc292858554d28d58d56bf62cf964faf0aa57964b21155a0", size = 268586, upload-time = "2025-09-01T22:09:18.948Z" }, + { url = "https://files.pythonhosted.org/packages/21/b1/453cbea5323b049181ec6344a803777914074b9726c9c5dc76749966d12d/regex-2025.9.1-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:72fb7a016467d364546f22b5ae86c45680a4e0de6b2a6f67441d22172ff641f1", size = 486111, upload-time = "2025-09-01T22:09:20.734Z" }, + { url = "https://files.pythonhosted.org/packages/f6/0e/92577f197bd2f7652c5e2857f399936c1876978474ecc5b068c6d8a79c86/regex-2025.9.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:c9527fa74eba53f98ad86be2ba003b3ebe97e94b6eb2b916b31b5f055622ef03", size = 289520, upload-time = "2025-09-01T22:09:22.249Z" }, + { url = "https://files.pythonhosted.org/packages/af/c6/b472398116cca7ea5a6c4d5ccd0fc543f7fd2492cb0c48d2852a11972f73/regex-2025.9.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c905d925d194c83a63f92422af7544ec188301451b292c8b487f0543726107ca", size = 287215, upload-time = "2025-09-01T22:09:23.657Z" }, + { url = "https://files.pythonhosted.org/packages/cf/11/f12ecb0cf9ca792a32bb92f758589a84149017467a544f2f6bfb45c0356d/regex-2025.9.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:74df7c74a63adcad314426b1f4ea6054a5ab25d05b0244f0c07ff9ce640fa597", size = 797855, upload-time = "2025-09-01T22:09:25.197Z" }, + { url = "https://files.pythonhosted.org/packages/46/88/bbb848f719a540fb5997e71310f16f0b33a92c5d4b4d72d4311487fff2a3/regex-2025.9.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4f6e935e98ea48c7a2e8be44494de337b57a204470e7f9c9c42f912c414cd6f5", size = 863363, upload-time = "2025-09-01T22:09:26.705Z" }, + { url = "https://files.pythonhosted.org/packages/54/a9/2321eb3e2838f575a78d48e03c1e83ea61bd08b74b7ebbdeca8abc50fc25/regex-2025.9.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4a62d033cd9ebefc7c5e466731a508dfabee827d80b13f455de68a50d3c2543d", size = 910202, upload-time = "2025-09-01T22:09:28.906Z" }, + { url = "https://files.pythonhosted.org/packages/33/07/d1d70835d7d11b7e126181f316f7213c4572ecf5c5c97bdbb969fb1f38a2/regex-2025.9.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ef971ebf2b93bdc88d8337238be4dfb851cc97ed6808eb04870ef67589415171", size = 801808, upload-time = "2025-09-01T22:09:30.733Z" }, + { url = "https://files.pythonhosted.org/packages/13/d1/29e4d1bed514ef2bf3a4ead3cb8bb88ca8af94130239a4e68aa765c35b1c/regex-2025.9.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:d936a1db208bdca0eca1f2bb2c1ba1d8370b226785c1e6db76e32a228ffd0ad5", size = 786824, upload-time = "2025-09-01T22:09:32.61Z" }, + { url = "https://files.pythonhosted.org/packages/33/27/20d8ccb1bee460faaa851e6e7cc4cfe852a42b70caa1dca22721ba19f02f/regex-2025.9.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:7e786d9e4469698fc63815b8de08a89165a0aa851720eb99f5e0ea9d51dd2b6a", size = 857406, upload-time = "2025-09-01T22:09:34.117Z" }, + { url = "https://files.pythonhosted.org/packages/74/fe/60c6132262dc36430d51e0c46c49927d113d3a38c1aba6a26c7744c84cf3/regex-2025.9.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:6b81d7dbc5466ad2c57ce3a0ddb717858fe1a29535c8866f8514d785fdb9fc5b", size = 848593, upload-time = "2025-09-01T22:09:35.598Z" }, + { url = "https://files.pythonhosted.org/packages/cc/ae/2d4ff915622fabbef1af28387bf71e7f2f4944a348b8460d061e85e29bf0/regex-2025.9.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:cd4890e184a6feb0ef195338a6ce68906a8903a0f2eb7e0ab727dbc0a3156273", size = 787951, upload-time = "2025-09-01T22:09:37.139Z" }, + { url = "https://files.pythonhosted.org/packages/85/37/dc127703a9e715a284cc2f7dbdd8a9776fd813c85c126eddbcbdd1ca5fec/regex-2025.9.1-cp314-cp314-win32.whl", hash = "sha256:34679a86230e46164c9e0396b56cab13c0505972343880b9e705083cc5b8ec86", size = 269833, upload-time = "2025-09-01T22:09:39.245Z" }, + { url = "https://files.pythonhosted.org/packages/83/bf/4bed4d3d0570e16771defd5f8f15f7ea2311edcbe91077436d6908956c4a/regex-2025.9.1-cp314-cp314-win_amd64.whl", hash = "sha256:a1196e530a6bfa5f4bde029ac5b0295a6ecfaaffbfffede4bbaf4061d9455b70", size = 278742, upload-time = "2025-09-01T22:09:40.651Z" }, + { url = "https://files.pythonhosted.org/packages/cf/3e/7d7ac6fd085023312421e0d69dfabdfb28e116e513fadbe9afe710c01893/regex-2025.9.1-cp314-cp314-win_arm64.whl", hash = "sha256:f46d525934871ea772930e997d577d48c6983e50f206ff7b66d4ac5f8941e993", size = 271860, upload-time = "2025-09-01T22:09:42.413Z" }, ] [[package]] @@ -319,11 +319,11 @@ wheels = [ [[package]] name = "typing-extensions" -version = "4.14.1" +version = "4.15.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/98/5a/da40306b885cc8c09109dc2e1abd358d5684b1425678151cdaed4731c822/typing_extensions-4.14.1.tar.gz", hash = "sha256:38b39f4aeeab64884ce9f74c94263ef78f3c22467c8724005483154c26648d36", size = 107673, upload-time = "2025-07-04T13:28:34.16Z" } +sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b5/00/d631e67a838026495268c2f6884f3711a15a9a2a96cd244fdaea53b823fb/typing_extensions-4.14.1-py3-none-any.whl", hash = "sha256:d1e1e3b58374dc93031d6eda2420a48ea44a36c2b4766a4fdeb3710755731d76", size = 43906, upload-time = "2025-07-04T13:28:32.743Z" }, + { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, ] [[package]] From fb247f640e1759101396300723c468c9b554e482 Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Wed, 10 Sep 2025 00:33:42 +0000 Subject: [PATCH 03/30] [skip ci] Updated translations via Crowdin --- options/locale/locale_fr-FR.ini | 14 +++++++++ options/locale/locale_pt-BR.ini | 52 ++++++++++++++++----------------- 2 files changed, 40 insertions(+), 26 deletions(-) diff --git a/options/locale/locale_fr-FR.ini b/options/locale/locale_fr-FR.ini index f75976bc4f0..adf349e9d8e 100644 --- a/options/locale/locale_fr-FR.ini +++ b/options/locale/locale_fr-FR.ini @@ -120,6 +120,7 @@ error404=La page que vous essayez d'atteindre n'existe pas ou < error503=Le serveur n’a pas pu répondre à votre demande. Veuillez réessayer plus tard. go_back=Retour invalid_data=Données invalides : %v +nothing_has_been_changed=Rien n’a été changé. never=Jamais unknown=Inconnu @@ -550,6 +551,13 @@ repo.transfer.body=Pour l’accepter ou le rejeter, visitez %s ou ignorez-le. repo.collaborator.added.subject=%s vous a ajouté à %s repo.collaborator.added.text=Vous avez été ajouté en tant que collaborateur du dépôt : +repo.actions.run.failed=L’exécution a échoué +repo.actions.run.succeeded=L’exécution a réussi +repo.actions.run.cancelled=L’exécution a été annulée +repo.actions.jobs.all_succeeded=Tous les tâches ont réussi. +repo.actions.jobs.all_failed=Toutes les tâches ont échoué. +repo.actions.jobs.some_not_successful=Certaines tâches n’ont pas réussi. +repo.actions.jobs.all_cancelled=Toutes les tâches ont bien été annulés. team_invite.subject=%[1]s vous a invité à rejoindre l’organisation %[2]s team_invite.text_1=%[1]s vous a invité à rejoindre l’équipe %[2]s dans l’organisation %[3]s. @@ -2844,6 +2852,11 @@ settings.location=Localisation settings.permission=Autorisations settings.repoadminchangeteam=L'administrateur de dépôt peut ajouter et supprimer l'accès aux équipes settings.visibility=Visibilité +settings.change_visibility=Modifier la visibilité +settings.change_visibility_notices_1=Si l’organisation est convertie en privé, les étoiles du dépôt seront supprimées et ne pourront pas être restaurées. +settings.change_visibility_notices_2=Les non-membres ne pourront plus accéder aux dépôts de l’organisation si la visibilité devient privée. +settings.change_visibility_success=La visibilité de l’organisation %s a été modifiée. +settings.visibility_desc=Changez qui peut voir l’organisation et ses dépôts. settings.visibility.public=Public settings.visibility.limited=Limité (Visible uniquement aux utilisateurs authentifiés) settings.visibility.limited_shortname=Limité @@ -3420,6 +3433,7 @@ config.picture_service=Service d'Imagerie config.disable_gravatar=Désactiver Gravatar config.enable_federated_avatar=Activer les avatars unifiés config.open_with_editor_app_help=Les éditeurs disponibles via « Ouvrir avec ». Si laissé vide, la valeur par défaut sera utilisée. Développez pour voir la valeur par défaut. +config.git_guide_remote_name=Nom du dépôt distant pour les commandes git dans le guide config.git_config=Configuration de Git config.git_disable_diff_highlight=Désactiver la surbrillance syntaxique de Diff diff --git a/options/locale/locale_pt-BR.ini b/options/locale/locale_pt-BR.ini index e345c336b40..42325629944 100644 --- a/options/locale/locale_pt-BR.ini +++ b/options/locale/locale_pt-BR.ini @@ -1010,9 +1010,9 @@ visibility.private_tooltip=Visível apenas para membros das organizações às q new_repo_helper=Um repositório contém todos os arquivos do projeto, inclusive o histórico de revisões. Já está hospedando um em outro lugar? Migre o repositório. owner=Proprietário owner_helper=Algumas organizações podem não aparecer no menu devido a um limite de contagem dos repositórios. -repo_name=Nome do repositório +repo_name=Nome do Repositório repo_name_helper=Bons nomes de repositórios usam palavras-chave curtas, memorizáveis e únicas. Um repositório chamado ".profile" ou ".profile-private" pode ser usado para adicionar um README.md para seu perfil de usuário/organização. -repo_size=Tamanho do repositório +repo_size=Tamanho do Repositório template=Modelo template_select=Selecione um modelo. template_helper=Tornar repositório um modelo @@ -1079,7 +1079,7 @@ mirror_lfs=Armazenamento de Arquivo Grande (LFS) mirror_lfs_desc=Ativar espelhamento de dados LFS. mirror_lfs_endpoint=Destino LFS mirror_lfs_endpoint_desc=A sincronização tentará usar o URL de clonagem para determinar o servidor LFS. Você também pode especificar um destino personalizado se os dados do repositório LFS forem armazenados em outro lugar. -mirror_last_synced=Última sincronização +mirror_last_synced=Última Sincronização mirror_password_placeholder=(inalterada) mirror_password_blank_placeholder=(não definida) mirror_password_help=Altere o nome de usuário para apagar uma senha armazenada. @@ -1148,7 +1148,7 @@ migrate_options_lfs_endpoint.label=Destino LFS migrate_options_lfs_endpoint.description=A migração tentará usar seu controle remoto Git para determinar o servidor LFS. Você também pode especificar um destino personalizado se os dados do repositório LFS forem armazenados em outro lugar. migrate_options_lfs_endpoint.description.local=Um caminho de servidor local também é suportado. migrate_options_lfs_endpoint.placeholder=Se for deixado em branco, o destino será derivado do URL de clone. -migrate_items=Itens da migração +migrate_items=Itens da Migração migrate_items_wiki=Wiki migrate_items_milestones=Marcos migrate_items_labels=Etiquetas @@ -1232,7 +1232,7 @@ find_tag=Pesquisar etiqueta branches=Branches tags=Tags issues=Issues -pulls=Pull requests +pulls=Pull Requests projects=Projetos packages=Pacotes actions=Ações @@ -1396,7 +1396,7 @@ projects.description=Descrição (opcional) projects.description_placeholder=Descrição projects.create=Criar Projeto projects.title=Título -projects.new=Novo projeto +projects.new=Novo Projeto projects.new_subheader=Coordene, acompanhe e atualize seu trabalho em um só lugar, para que os projetos permaneçam transparentes e dentro do cronograma. projects.create_success=Projeto "%s" criado. projects.deletion=Apagar Projeto @@ -1407,25 +1407,25 @@ projects.edit_subheader=Projetos organizam issues e acompanham o progresso. projects.modify=Atualizar Projeto projects.edit_success=Projeto "%s" atualizado. projects.type.none=Nenhum -projects.type.basic_kanban=Kanban básico +projects.type.basic_kanban=Kanban Básico projects.type.bug_triage=Triagem de Bugs projects.template.desc=Modelo de projeto projects.template.desc_helper=Selecione um modelo de projeto para começar projects.column.edit=Editar coluna projects.column.edit_title=Nome projects.column.new_title=Nome -projects.column.new_submit=Criar coluna +projects.column.new_submit=Criar Coluna projects.column.new=Nova Coluna -projects.column.set_default=Atribuir como padrão +projects.column.set_default=Atribuir como Padrão projects.column.set_default_desc=Definir esta coluna como padrão para pull e issues sem categoria -projects.column.delete=Excluir coluna +projects.column.delete=Excluir Coluna projects.column.color=Cor projects.open=Abrir projects.close=Fechar projects.column.assigned_to=Atribuído a projects.card_type.desc=Pré-visualizações de Cards projects.card_type.images_and_text=Imagens e Texto -projects.card_type.text_only=Somente texto +projects.card_type.text_only=Somente Texto issues.desc=Organize relatórios de bugs, tarefas e marcos. issues.filter_assignees=Filtrar Atribuição @@ -1665,7 +1665,7 @@ issues.add_time_hours=Horas issues.add_time_minutes=Minutos issues.add_time_sum_to_small=Nenhum tempo foi inserido. issues.time_spent_total=Tempo Total Gasto -issues.time_spent_from_all_authors=`Tempo total gasto: %s` +issues.time_spent_from_all_authors=`Tempo Total Gasto: %s` issues.due_date=Data Limite issues.invalid_due_date_format=Formato da data limite inválido, deve ser 'dd/mm/aaaa'. @@ -1755,9 +1755,9 @@ compare.compare_base=base compare.compare_head=comparar pulls.desc=Habilitar pull requests e revisões de código. -pulls.new=Novo pull request +pulls.new=Novo Pull Request pulls.view=Ver Pull Request -pulls.compare_changes=Novo pull request +pulls.compare_changes=Novo Pull Request pulls.allow_edits_from_maintainers=Permitir edições de mantenedores pulls.allow_edits_from_maintainers_desc=Usuários com acesso de gravação para o branch base também podem fazer push para este branch pulls.allow_edits_from_maintainers_err=Falha na atualização @@ -1787,7 +1787,7 @@ pulls.merged_title_desc=aplicou merge dos %[1]d commits de %[2]s em pulls.change_target_branch_at=`mudou o branch de destino de %s para %s %s` pulls.tab_conversation=Conversação pulls.tab_commits=Commits -pulls.tab_files=Arquivos alterados +pulls.tab_files=Arquivos Alterados pulls.reopen_to_merge=Por favor reabra este pull request para aplicar o merge. pulls.cant_reopen_deleted_branch=Este pull request não pode ser reaberto porque o branch foi excluído. pulls.merged=Merge aplicado @@ -1837,9 +1837,9 @@ pulls.merge_commit_id=A ID de merge commit pulls.require_signed_wont_sign=O branch requer commits assinados, mas este merge não será assinado pulls.invalid_merge_option=Você não pode usar esta opção de merge neste pull request. -pulls.merge_conflict_summary=Mensagem de erro +pulls.merge_conflict_summary=Mensagem de Erro pulls.rebase_conflict_summary=Mensagem de Erro -pulls.push_rejected_summary=Mensagem completa da rejeição +pulls.push_rejected_summary=Mensagem Completa da Rejeição pulls.open_unmerged_pull_exists=`Não é possível executar uma operação de reabertura pois há um pull request pendente (#%d) com propriedades idênticas.` pulls.status_checking=Algumas verificações estão pendentes pulls.status_checks_success=Todas as verificações foram bem sucedidas @@ -1855,7 +1855,7 @@ pulls.update_branch_rebase=Atualizar branch por rebase pulls.update_branch_success=Atualização do branch foi bem-sucedida pulls.update_not_allowed=Você não tem permissão para atualizar o branch pulls.outdated_with_base_branch=Este branch está desatualizado com o branch base -pulls.close=Fechar pull request +pulls.close=Fechar Pull Request pulls.closed_at=`fechou este pull request %[2]s` pulls.reopened_at=`reabriu este pull request %[2]s` pulls.cmd_instruction_checkout_title=Checkout @@ -1885,7 +1885,7 @@ pull.deleted_branch=(excluído):%s pull.agit_documentation=Veja a documentação sobre AGit -milestones.new=Novo marco +milestones.new=Novo Marco milestones.closed=Fechado %s milestones.update_ago=Atualizado há %s milestones.no_due_date=Sem data limite @@ -1896,11 +1896,11 @@ milestones.completeness=%d%% Concluído milestones.create=Criar Marco milestones.title=Título milestones.desc=Descrição -milestones.due_date=Data limite (opcional) +milestones.due_date=Data Limite (opcional) milestones.clear=Limpar milestones.invalid_due_date_format=Formato da data limite deve ser 'dd/mm/aaaa'. milestones.create_success=O marco "%s" foi criado. -milestones.edit=Editar marco +milestones.edit=Editar Marco milestones.edit_subheader=Marcos organizam as issues e acompanham o progresso. milestones.cancel=Cancelar milestones.modify=Atualizar Marco @@ -2459,7 +2459,7 @@ releases.desc=Acompanhe as versões e downloads do projeto. release.releases=Versões release.detail=Detalhes da versão release.tags=Tags -release.new_release=Nova versão +release.new_release=Nova Versão release.draft=Rascunho release.prerelease=Versão prévia release.stable=Estável @@ -2482,12 +2482,12 @@ release.message=Descreva esta versão release.prerelease_desc=Marcar como pré-lançamento release.prerelease_helper=Marcar esta versão como inadequada para uso em produção. release.cancel=Cancelar -release.publish=Publicar versão -release.save_draft=Salvar rascunho -release.edit_release=Atualizar versão +release.publish=Publicar Versão +release.save_draft=Salvar Rascunho +release.edit_release=Atualizar Versão release.delete_release=Excluir Versão release.delete_tag=Apagar Tag -release.deletion=Excluir versão +release.deletion=Excluir Versão release.deletion_desc=A exclusão de uma versão apenas a remove do Gitea. Isso não afetará a tag do Git, o conteúdo do seu repositório ou seu histórico. Continuar? release.deletion_success=A versão foi excluída. release.deletion_tag_desc=A tag será excluída do repositório. Conteúdo do repositório e histórico permanecerão inalterados. Continuar? From e35e724e42c98172d9eee679b0cb931f1a6af833 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Tue, 9 Sep 2025 20:15:01 -0700 Subject: [PATCH 04/30] Use db.WithTx/WithTx2 instead of TxContext when possible (#35428) --- models/asymkey/gpg_key_add.go | 146 +++++++++++++------------- models/git/branch.go | 185 ++++++++++++++++----------------- models/git/lfs.go | 102 ++++++++---------- models/issues/assignees.go | 16 +-- models/issues/issue_update.go | 47 ++++----- models/user/email_address.go | 85 +++++++-------- models/user/user.go | 130 +++++++++++------------ services/issue/issue.go | 113 ++++++++++---------- services/org/org.go | 53 +++++----- services/org/user.go | 87 ++++++++-------- services/release/release.go | 101 +++++++++--------- services/repository/migrate.go | 150 +++++++++++++------------- services/user/user.go | 80 +++++++------- 13 files changed, 601 insertions(+), 694 deletions(-) diff --git a/models/asymkey/gpg_key_add.go b/models/asymkey/gpg_key_add.go index 1c7d2c1da26..3969edcc869 100644 --- a/models/asymkey/gpg_key_add.go +++ b/models/asymkey/gpg_key_add.go @@ -72,96 +72,90 @@ func AddGPGKey(ctx context.Context, ownerID int64, content, token, signature str return nil, err } - ctx, committer, err := db.TxContext(ctx) - if err != nil { - return nil, err - } - defer committer.Close() + return db.WithTx2(ctx, func(ctx context.Context) ([]*GPGKey, error) { + keys := make([]*GPGKey, 0, len(ekeys)) - keys := make([]*GPGKey, 0, len(ekeys)) - - verified := false - // Handle provided signature - if signature != "" { - signer, err := openpgp.CheckArmoredDetachedSignature(ekeys, strings.NewReader(token), strings.NewReader(signature), nil) - if err != nil { - signer, err = openpgp.CheckArmoredDetachedSignature(ekeys, strings.NewReader(token+"\n"), strings.NewReader(signature), nil) - } - if err != nil { - signer, err = openpgp.CheckArmoredDetachedSignature(ekeys, strings.NewReader(token+"\r\n"), strings.NewReader(signature), nil) - } - if err != nil { - log.Debug("AddGPGKey CheckArmoredDetachedSignature failed: %v", err) - return nil, ErrGPGInvalidTokenSignature{ - ID: ekeys[0].PrimaryKey.KeyIdString(), - Wrapped: err, + verified := false + // Handle provided signature + if signature != "" { + signer, err := openpgp.CheckArmoredDetachedSignature(ekeys, strings.NewReader(token), strings.NewReader(signature), nil) + if err != nil { + signer, err = openpgp.CheckArmoredDetachedSignature(ekeys, strings.NewReader(token+"\n"), strings.NewReader(signature), nil) } + if err != nil { + signer, err = openpgp.CheckArmoredDetachedSignature(ekeys, strings.NewReader(token+"\r\n"), strings.NewReader(signature), nil) + } + if err != nil { + log.Debug("AddGPGKey CheckArmoredDetachedSignature failed: %v", err) + return nil, ErrGPGInvalidTokenSignature{ + ID: ekeys[0].PrimaryKey.KeyIdString(), + Wrapped: err, + } + } + ekeys = []*openpgp.Entity{signer} + verified = true } - ekeys = []*openpgp.Entity{signer} - verified = true - } - if len(ekeys) > 1 { - id2key := map[string]*openpgp.Entity{} - newEKeys := make([]*openpgp.Entity, 0, len(ekeys)) - for _, ekey := range ekeys { - id := ekey.PrimaryKey.KeyIdString() - if original, has := id2key[id]; has { - // Coalesce this with the other one - for _, subkey := range ekey.Subkeys { - if subkey.PublicKey == nil { - continue - } - found := false - - for _, originalSubkey := range original.Subkeys { - if originalSubkey.PublicKey == nil { + if len(ekeys) > 1 { + id2key := map[string]*openpgp.Entity{} + newEKeys := make([]*openpgp.Entity, 0, len(ekeys)) + for _, ekey := range ekeys { + id := ekey.PrimaryKey.KeyIdString() + if original, has := id2key[id]; has { + // Coalesce this with the other one + for _, subkey := range ekey.Subkeys { + if subkey.PublicKey == nil { continue } - if originalSubkey.PublicKey.KeyId == subkey.PublicKey.KeyId { - found = true - break + found := false + + for _, originalSubkey := range original.Subkeys { + if originalSubkey.PublicKey == nil { + continue + } + if originalSubkey.PublicKey.KeyId == subkey.PublicKey.KeyId { + found = true + break + } + } + if !found { + original.Subkeys = append(original.Subkeys, subkey) } } - if !found { - original.Subkeys = append(original.Subkeys, subkey) + for name, identity := range ekey.Identities { + if _, has := original.Identities[name]; has { + continue + } + original.Identities[name] = identity } + continue } - for name, identity := range ekey.Identities { - if _, has := original.Identities[name]; has { - continue - } - original.Identities[name] = identity - } - continue + id2key[id] = ekey + newEKeys = append(newEKeys, ekey) } - id2key[id] = ekey - newEKeys = append(newEKeys, ekey) - } - ekeys = newEKeys - } - - for _, ekey := range ekeys { - // Key ID cannot be duplicated. - has, err := db.GetEngine(ctx).Where("key_id=?", ekey.PrimaryKey.KeyIdString()). - Get(new(GPGKey)) - if err != nil { - return nil, err - } else if has { - return nil, ErrGPGKeyIDAlreadyUsed{ekey.PrimaryKey.KeyIdString()} + ekeys = newEKeys } - // Get DB session + for _, ekey := range ekeys { + // Key ID cannot be duplicated. + has, err := db.GetEngine(ctx).Where("key_id=?", ekey.PrimaryKey.KeyIdString()). + Get(new(GPGKey)) + if err != nil { + return nil, err + } else if has { + return nil, ErrGPGKeyIDAlreadyUsed{ekey.PrimaryKey.KeyIdString()} + } - key, err := parseGPGKey(ctx, ownerID, ekey, verified) - if err != nil { - return nil, err - } + key, err := parseGPGKey(ctx, ownerID, ekey, verified) + if err != nil { + return nil, err + } - if err = addGPGKey(ctx, key, content); err != nil { - return nil, err + if err = addGPGKey(ctx, key, content); err != nil { + return nil, err + } + keys = append(keys, key) } - keys = append(keys, key) - } - return keys, committer.Commit() + return keys, nil + }) } diff --git a/models/git/branch.go b/models/git/branch.go index 6021e1101f6..54351649cc5 100644 --- a/models/git/branch.go +++ b/models/git/branch.go @@ -334,122 +334,111 @@ func FindRenamedBranch(ctx context.Context, repoID int64, from string) (branch * // RenameBranch rename a branch func RenameBranch(ctx context.Context, repo *repo_model.Repository, from, to string, gitAction func(ctx context.Context, isDefault bool) error) (err error) { - ctx, committer, err := db.TxContext(ctx) - if err != nil { - return err - } - defer committer.Close() + return db.WithTx(ctx, func(ctx context.Context) error { + sess := db.GetEngine(ctx) - sess := db.GetEngine(ctx) - - // check whether from branch exist - var branch Branch - exist, err := db.GetEngine(ctx).Where("repo_id=? AND name=?", repo.ID, from).Get(&branch) - if err != nil { - return err - } else if !exist || branch.IsDeleted { - return ErrBranchNotExist{ - RepoID: repo.ID, - BranchName: from, - } - } - - // check whether to branch exist or is_deleted - var dstBranch Branch - exist, err = db.GetEngine(ctx).Where("repo_id=? AND name=?", repo.ID, to).Get(&dstBranch) - if err != nil { - return err - } - if exist { - if !dstBranch.IsDeleted { - return ErrBranchAlreadyExists{ - BranchName: to, + // check whether from branch exist + var branch Branch + exist, err := db.GetEngine(ctx).Where("repo_id=? AND name=?", repo.ID, from).Get(&branch) + if err != nil { + return err + } else if !exist || branch.IsDeleted { + return ErrBranchNotExist{ + RepoID: repo.ID, + BranchName: from, } } - if _, err := db.GetEngine(ctx).ID(dstBranch.ID).NoAutoCondition().Delete(&dstBranch); err != nil { - return err - } - } - - // 1. update branch in database - if n, err := sess.Where("repo_id=? AND name=?", repo.ID, from).Update(&Branch{ - Name: to, - }); err != nil { - return err - } else if n <= 0 { - return ErrBranchNotExist{ - RepoID: repo.ID, - BranchName: from, - } - } - - // 2. update default branch if needed - isDefault := repo.DefaultBranch == from - if isDefault { - repo.DefaultBranch = to - _, err = sess.ID(repo.ID).Cols("default_branch").Update(repo) + // check whether to branch exist or is_deleted + var dstBranch Branch + exist, err = db.GetEngine(ctx).Where("repo_id=? AND name=?", repo.ID, to).Get(&dstBranch) if err != nil { return err } - } + if exist { + if !dstBranch.IsDeleted { + return ErrBranchAlreadyExists{ + BranchName: to, + } + } - // 3. Update protected branch if needed - protectedBranch, err := GetProtectedBranchRuleByName(ctx, repo.ID, from) - if err != nil { - return err - } + if _, err := db.GetEngine(ctx).ID(dstBranch.ID).NoAutoCondition().Delete(&dstBranch); err != nil { + return err + } + } - if protectedBranch != nil { - // there is a protect rule for this branch - protectedBranch.RuleName = to - _, err = sess.ID(protectedBranch.ID).Cols("branch_name").Update(protectedBranch) + // 1. update branch in database + if n, err := sess.Where("repo_id=? AND name=?", repo.ID, from).Update(&Branch{ + Name: to, + }); err != nil { + return err + } else if n <= 0 { + return ErrBranchNotExist{ + RepoID: repo.ID, + BranchName: from, + } + } + + // 2. update default branch if needed + isDefault := repo.DefaultBranch == from + if isDefault { + repo.DefaultBranch = to + _, err = sess.ID(repo.ID).Cols("default_branch").Update(repo) + if err != nil { + return err + } + } + + // 3. Update protected branch if needed + protectedBranch, err := GetProtectedBranchRuleByName(ctx, repo.ID, from) if err != nil { return err } - } else { - // some glob protect rules may match this branch - protected, err := IsBranchProtected(ctx, repo.ID, from) + + if protectedBranch != nil { + // there is a protect rule for this branch + protectedBranch.RuleName = to + if _, err = sess.ID(protectedBranch.ID).Cols("branch_name").Update(protectedBranch); err != nil { + return err + } + } else { + // some glob protect rules may match this branch + protected, err := IsBranchProtected(ctx, repo.ID, from) + if err != nil { + return err + } + if protected { + return ErrBranchIsProtected + } + } + + // 4. Update all not merged pull request base branch name + _, err = sess.Table("pull_request").Where("base_repo_id=? AND base_branch=? AND has_merged=?", + repo.ID, from, false). + Update(map[string]any{"base_branch": to}) if err != nil { return err } - if protected { - return ErrBranchIsProtected + + // 4.1 Update all not merged pull request head branch name + if _, err = sess.Table("pull_request").Where("head_repo_id=? AND head_branch=? AND has_merged=?", + repo.ID, from, false). + Update(map[string]any{"head_branch": to}); err != nil { + return err } - } - // 4. Update all not merged pull request base branch name - _, err = sess.Table("pull_request").Where("base_repo_id=? AND base_branch=? AND has_merged=?", - repo.ID, from, false). - Update(map[string]any{"base_branch": to}) - if err != nil { - return err - } + // 5. insert renamed branch record + if err = db.Insert(ctx, &RenamedBranch{ + RepoID: repo.ID, + From: from, + To: to, + }); err != nil { + return err + } - // 4.1 Update all not merged pull request head branch name - if _, err = sess.Table("pull_request").Where("head_repo_id=? AND head_branch=? AND has_merged=?", - repo.ID, from, false). - Update(map[string]any{"head_branch": to}); err != nil { - return err - } - - // 5. insert renamed branch record - renamedBranch := &RenamedBranch{ - RepoID: repo.ID, - From: from, - To: to, - } - err = db.Insert(ctx, renamedBranch) - if err != nil { - return err - } - - // 6. do git action - if err = gitAction(ctx, isDefault); err != nil { - return err - } - - return committer.Commit() + // 6. do git action + return gitAction(ctx, isDefault) + }) } type FindRecentlyPushedNewBranchesOptions struct { diff --git a/models/git/lfs.go b/models/git/lfs.go index c471baf5880..8bba060ff97 100644 --- a/models/git/lfs.go +++ b/models/git/lfs.go @@ -180,29 +180,25 @@ func RemoveLFSMetaObjectByOidFn(ctx context.Context, repoID int64, oid string, f return 0, ErrLFSObjectNotExist } - ctx, committer, err := db.TxContext(ctx) - if err != nil { - return 0, err - } - defer committer.Close() + return db.WithTx2(ctx, func(ctx context.Context) (int64, error) { + m := &LFSMetaObject{Pointer: lfs.Pointer{Oid: oid}, RepositoryID: repoID} + if _, err := db.DeleteByBean(ctx, m); err != nil { + return -1, err + } - m := &LFSMetaObject{Pointer: lfs.Pointer{Oid: oid}, RepositoryID: repoID} - if _, err := db.DeleteByBean(ctx, m); err != nil { - return -1, err - } - - count, err := db.CountByBean(ctx, &LFSMetaObject{Pointer: lfs.Pointer{Oid: oid}}) - if err != nil { - return count, err - } - - if fn != nil { - if err := fn(count); err != nil { + count, err := db.CountByBean(ctx, &LFSMetaObject{Pointer: lfs.Pointer{Oid: oid}}) + if err != nil { return count, err } - } - return count, committer.Commit() + if fn != nil { + if err := fn(count); err != nil { + return count, err + } + } + + return count, nil + }) } // GetLFSMetaObjects returns all LFSMetaObjects associated with a repository @@ -243,56 +239,46 @@ func ExistsLFSObject(ctx context.Context, oid string) (bool, error) { // LFSAutoAssociate auto associates accessible LFSMetaObjects func LFSAutoAssociate(ctx context.Context, metas []*LFSMetaObject, user *user_model.User, repoID int64) error { - ctx, committer, err := db.TxContext(ctx) - if err != nil { - return err - } - defer committer.Close() + return db.WithTx(ctx, func(ctx context.Context) error { + oids := make([]any, len(metas)) + oidMap := make(map[string]*LFSMetaObject, len(metas)) + for i, meta := range metas { + oids[i] = meta.Oid + oidMap[meta.Oid] = meta + } - sess := db.GetEngine(ctx) + if !user.IsAdmin { + newMetas := make([]*LFSMetaObject, 0, len(metas)) + cond := builder.In( + "`lfs_meta_object`.repository_id", + builder.Select("`repository`.id").From("repository").Where(repo_model.AccessibleRepositoryCondition(user, unit.TypeInvalid)), + ) + if err := db.GetEngine(ctx).Cols("oid").Where(cond).In("oid", oids...).GroupBy("oid").Find(&newMetas); err != nil { + return err + } + if len(newMetas) != len(oidMap) { + return fmt.Errorf("unable collect all LFS objects from database, expected %d, actually %d", len(oidMap), len(newMetas)) + } + for i := range newMetas { + newMetas[i].Size = oidMap[newMetas[i].Oid].Size + newMetas[i].RepositoryID = repoID + } + return db.Insert(ctx, newMetas) + } - oids := make([]any, len(metas)) - oidMap := make(map[string]*LFSMetaObject, len(metas)) - for i, meta := range metas { - oids[i] = meta.Oid - oidMap[meta.Oid] = meta - } - - if !user.IsAdmin { - newMetas := make([]*LFSMetaObject, 0, len(metas)) - cond := builder.In( - "`lfs_meta_object`.repository_id", - builder.Select("`repository`.id").From("repository").Where(repo_model.AccessibleRepositoryCondition(user, unit.TypeInvalid)), - ) - err = sess.Cols("oid").Where(cond).In("oid", oids...).GroupBy("oid").Find(&newMetas) - if err != nil { - return err - } - if len(newMetas) != len(oidMap) { - return fmt.Errorf("unable collect all LFS objects from database, expected %d, actually %d", len(oidMap), len(newMetas)) - } - for i := range newMetas { - newMetas[i].Size = oidMap[newMetas[i].Oid].Size - newMetas[i].RepositoryID = repoID - } - if err = db.Insert(ctx, newMetas); err != nil { - return err - } - } else { // admin can associate any LFS object to any repository, and we do not care about errors (eg: duplicated unique key), // even if error occurs, it won't hurt users and won't make things worse for i := range metas { p := lfs.Pointer{Oid: metas[i].Oid, Size: metas[i].Size} - _, err = sess.Insert(&LFSMetaObject{ + if err := db.Insert(ctx, &LFSMetaObject{ Pointer: p, RepositoryID: repoID, - }) - if err != nil { + }); err != nil { log.Warn("failed to insert LFS meta object %-v for repo_id: %d into database, err=%v", p, repoID, err) } } - } - return committer.Commit() + return nil + }) } // CopyLFS copies LFS data from one repo to another diff --git a/models/issues/assignees.go b/models/issues/assignees.go index efd992cda2b..54f995dd2e9 100644 --- a/models/issues/assignees.go +++ b/models/issues/assignees.go @@ -91,18 +91,10 @@ func GetAssignedIssues(ctx context.Context, opts *AssignedIssuesOptions) ([]*Iss // ToggleIssueAssignee changes a user between assigned and not assigned for this issue, and make issue comment for it. func ToggleIssueAssignee(ctx context.Context, issue *Issue, doer *user_model.User, assigneeID int64) (removed bool, comment *Comment, err error) { - ctx, committer, err := db.TxContext(ctx) - if err != nil { - return false, nil, err - } - defer committer.Close() - - removed, comment, err = toggleIssueAssignee(ctx, issue, doer, assigneeID, false) - if err != nil { - return false, nil, err - } - - if err := committer.Commit(); err != nil { + if err := db.WithTx(ctx, func(ctx context.Context) error { + removed, comment, err = toggleIssueAssignee(ctx, issue, doer, assigneeID, false) + return err + }); err != nil { return false, nil, err } diff --git a/models/issues/issue_update.go b/models/issues/issue_update.go index 1c168174918..553e99aece2 100644 --- a/models/issues/issue_update.go +++ b/models/issues/issue_update.go @@ -415,37 +415,28 @@ func NewIssueWithIndex(ctx context.Context, doer *user_model.User, opts NewIssue // NewIssue creates new issue with labels for repository. // The title will be cut off at 255 characters if it's longer than 255 characters. func NewIssue(ctx context.Context, repo *repo_model.Repository, issue *Issue, labelIDs []int64, uuids []string) (err error) { - ctx, committer, err := db.TxContext(ctx) - if err != nil { - return err - } - defer committer.Close() - - idx, err := db.GetNextResourceIndex(ctx, "issue_index", repo.ID) - if err != nil { - return fmt.Errorf("generate issue index failed: %w", err) - } - - issue.Index = idx - issue.Title = util.EllipsisDisplayString(issue.Title, 255) - - if err = NewIssueWithIndex(ctx, issue.Poster, NewIssueOptions{ - Repo: repo, - Issue: issue, - LabelIDs: labelIDs, - Attachments: uuids, - }); err != nil { - if repo_model.IsErrUserDoesNotHaveAccessToRepo(err) || IsErrNewIssueInsert(err) { - return err + return db.WithTx(ctx, func(ctx context.Context) error { + idx, err := db.GetNextResourceIndex(ctx, "issue_index", repo.ID) + if err != nil { + return fmt.Errorf("generate issue index failed: %w", err) } - return fmt.Errorf("newIssue: %w", err) - } - if err = committer.Commit(); err != nil { - return fmt.Errorf("Commit: %w", err) - } + issue.Index = idx + issue.Title = util.EllipsisDisplayString(issue.Title, 255) - return nil + if err = NewIssueWithIndex(ctx, issue.Poster, NewIssueOptions{ + Repo: repo, + Issue: issue, + LabelIDs: labelIDs, + Attachments: uuids, + }); err != nil { + if repo_model.IsErrUserDoesNotHaveAccessToRepo(err) || IsErrNewIssueInsert(err) { + return err + } + return fmt.Errorf("newIssue: %w", err) + } + return nil + }) } // UpdateIssueMentions updates issue-user relations for mentioned users. diff --git a/models/user/email_address.go b/models/user/email_address.go index cb423945f8a..67aa1bdd822 100644 --- a/models/user/email_address.go +++ b/models/user/email_address.go @@ -442,58 +442,53 @@ func SearchEmails(ctx context.Context, opts *SearchEmailOptions) ([]*SearchEmail // ActivateUserEmail will change the activated state of an email address, // either primary or secondary (all in the email_address table) func ActivateUserEmail(ctx context.Context, userID int64, email string, activate bool) (err error) { - ctx, committer, err := db.TxContext(ctx) - if err != nil { - return err - } - defer committer.Close() - - // Activate/deactivate a user's secondary email address - // First check if there's another user active with the same address - addr, exist, err := db.Get[EmailAddress](ctx, builder.Eq{"uid": userID, "lower_email": strings.ToLower(email)}) - if err != nil { - return err - } else if !exist { - return fmt.Errorf("no such email: %d (%s)", userID, email) - } - - if addr.IsActivated == activate { - // Already in the desired state; no action - return nil - } - if activate { - if used, err := IsEmailActive(ctx, email, addr.ID); err != nil { - return fmt.Errorf("unable to check isEmailActive() for %s: %w", email, err) - } else if used { - return ErrEmailAlreadyUsed{Email: email} - } - } - if err = updateActivation(ctx, addr, activate); err != nil { - return fmt.Errorf("unable to updateActivation() for %d:%s: %w", addr.ID, addr.Email, err) - } - - // Activate/deactivate a user's primary email address and account - if addr.IsPrimary { - user, exist, err := db.Get[User](ctx, builder.Eq{"id": userID}) + return db.WithTx(ctx, func(ctx context.Context) error { + // Activate/deactivate a user's secondary email address + // First check if there's another user active with the same address + addr, exist, err := db.Get[EmailAddress](ctx, builder.Eq{"uid": userID, "lower_email": strings.ToLower(email)}) if err != nil { return err - } else if !exist || !strings.EqualFold(user.Email, email) { - return fmt.Errorf("no user with ID: %d and Email: %s", userID, email) + } else if !exist { + return fmt.Errorf("no such email: %d (%s)", userID, email) } - // The user's activation state should be synchronized with the primary email - if user.IsActive != activate { - user.IsActive = activate - if user.Rands, err = GetUserSalt(); err != nil { - return fmt.Errorf("unable to generate salt: %w", err) - } - if err = UpdateUserCols(ctx, user, "is_active", "rands"); err != nil { - return fmt.Errorf("unable to updateUserCols() for user ID: %d: %w", userID, err) + if addr.IsActivated == activate { + // Already in the desired state; no action + return nil + } + if activate { + if used, err := IsEmailActive(ctx, email, addr.ID); err != nil { + return fmt.Errorf("unable to check isEmailActive() for %s: %w", email, err) + } else if used { + return ErrEmailAlreadyUsed{Email: email} } } - } + if err = updateActivation(ctx, addr, activate); err != nil { + return fmt.Errorf("unable to updateActivation() for %d:%s: %w", addr.ID, addr.Email, err) + } - return committer.Commit() + // Activate/deactivate a user's primary email address and account + if addr.IsPrimary { + user, exist, err := db.Get[User](ctx, builder.Eq{"id": userID}) + if err != nil { + return err + } else if !exist || !strings.EqualFold(user.Email, email) { + return fmt.Errorf("no user with ID: %d and Email: %s", userID, email) + } + + // The user's activation state should be synchronized with the primary email + if user.IsActive != activate { + user.IsActive = activate + if user.Rands, err = GetUserSalt(); err != nil { + return fmt.Errorf("unable to generate salt: %w", err) + } + if err = UpdateUserCols(ctx, user, "is_active", "rands"); err != nil { + return fmt.Errorf("unable to updateUserCols() for user ID: %d: %w", userID, err) + } + } + } + return nil + }) } // validateEmailBasic checks whether the email complies with the rules diff --git a/models/user/user.go b/models/user/user.go index ae500f3a1f2..6143992a253 100644 --- a/models/user/user.go +++ b/models/user/user.go @@ -716,90 +716,82 @@ func createUser(ctx context.Context, u *User, meta *Meta, createdByAdmin bool, o } } - ctx, committer, err := db.TxContext(ctx) - if err != nil { - return err - } - defer committer.Close() - - isExist, err := IsUserExist(ctx, 0, u.Name) - if err != nil { - return err - } else if isExist { - return ErrUserAlreadyExist{u.Name} - } - - isExist, err = IsEmailUsed(ctx, u.Email) - if err != nil { - return err - } else if isExist { - return ErrEmailAlreadyUsed{ - Email: u.Email, + return db.WithTx(ctx, func(ctx context.Context) error { + isExist, err := IsUserExist(ctx, 0, u.Name) + if err != nil { + return err + } else if isExist { + return ErrUserAlreadyExist{u.Name} } - } - // prepare for database + isExist, err = IsEmailUsed(ctx, u.Email) + if err != nil { + return err + } else if isExist { + return ErrEmailAlreadyUsed{ + Email: u.Email, + } + } - u.LowerName = strings.ToLower(u.Name) - u.AvatarEmail = u.Email - if u.Rands, err = GetUserSalt(); err != nil { - return err - } - if u.Passwd != "" { - if err = u.SetPassword(u.Passwd); err != nil { + // prepare for database + + u.LowerName = strings.ToLower(u.Name) + u.AvatarEmail = u.Email + if u.Rands, err = GetUserSalt(); err != nil { return err } - } else { - u.Salt = "" - u.PasswdHashAlgo = "" - } + if u.Passwd != "" { + if err = u.SetPassword(u.Passwd); err != nil { + return err + } + } else { + u.Salt = "" + u.PasswdHashAlgo = "" + } - // save changes to database + // save changes to database - if err = DeleteUserRedirect(ctx, u.Name); err != nil { - return err - } - - if u.CreatedUnix == 0 { - // Caller expects auto-time for creation & update timestamps. - err = db.Insert(ctx, u) - } else { - // Caller sets the timestamps themselves. They are responsible for ensuring - // both `CreatedUnix` and `UpdatedUnix` are set appropriately. - _, err = db.GetEngine(ctx).NoAutoTime().Insert(u) - } - if err != nil { - return err - } - - if setting.RecordUserSignupMetadata { - // insert initial IP and UserAgent - if err = SetUserSetting(ctx, u.ID, SignupIP, meta.InitialIP); err != nil { + if err = DeleteUserRedirect(ctx, u.Name); err != nil { return err } - // trim user agent string to a reasonable length, if necessary - userAgent := strings.TrimSpace(meta.InitialUserAgent) - if len(userAgent) > 255 { - userAgent = userAgent[:255] + if u.CreatedUnix == 0 { + // Caller expects auto-time for creation & update timestamps. + err = db.Insert(ctx, u) + } else { + // Caller sets the timestamps themselves. They are responsible for ensuring + // both `CreatedUnix` and `UpdatedUnix` are set appropriately. + _, err = db.GetEngine(ctx).NoAutoTime().Insert(u) } - if err = SetUserSetting(ctx, u.ID, SignupUserAgent, userAgent); err != nil { + if err != nil { return err } - } - // insert email address - if err := db.Insert(ctx, &EmailAddress{ - UID: u.ID, - Email: u.Email, - LowerEmail: strings.ToLower(u.Email), - IsActivated: u.IsActive, - IsPrimary: true, - }); err != nil { - return err - } + if setting.RecordUserSignupMetadata { + // insert initial IP and UserAgent + if err = SetUserSetting(ctx, u.ID, SignupIP, meta.InitialIP); err != nil { + return err + } - return committer.Commit() + // trim user agent string to a reasonable length, if necessary + userAgent := strings.TrimSpace(meta.InitialUserAgent) + if len(userAgent) > 255 { + userAgent = userAgent[:255] + } + if err = SetUserSetting(ctx, u.ID, SignupUserAgent, userAgent); err != nil { + return err + } + } + + // insert email address + return db.Insert(ctx, &EmailAddress{ + UID: u.ID, + Email: u.Email, + LowerEmail: strings.ToLower(u.Email), + IsActivated: u.IsActive, + IsPrimary: true, + }) + }) } // ErrDeleteLastAdminUser represents a "DeleteLastAdminUser" kind of error. diff --git a/services/issue/issue.go b/services/issue/issue.go index f03be3e18f6..ae81b9f48b6 100644 --- a/services/issue/issue.go +++ b/services/issue/issue.go @@ -261,74 +261,67 @@ func GetRefEndNamesAndURLs(issues []*issues_model.Issue, repoLink string) (map[i // deleteIssue deletes the issue func deleteIssue(ctx context.Context, issue *issues_model.Issue) ([]string, error) { - ctx, committer, err := db.TxContext(ctx) - if err != nil { - return nil, err - } - defer committer.Close() - - if _, err := db.GetEngine(ctx).ID(issue.ID).NoAutoCondition().Delete(issue); err != nil { - return nil, err - } - - // update the total issue numbers - if err := repo_model.UpdateRepoIssueNumbers(ctx, issue.RepoID, issue.IsPull, false); err != nil { - return nil, err - } - // if the issue is closed, update the closed issue numbers - if issue.IsClosed { - if err := repo_model.UpdateRepoIssueNumbers(ctx, issue.RepoID, issue.IsPull, true); err != nil { + return db.WithTx2(ctx, func(ctx context.Context) ([]string, error) { + if _, err := db.GetEngine(ctx).ID(issue.ID).NoAutoCondition().Delete(issue); err != nil { return nil, err } - } - if err := issues_model.UpdateMilestoneCounters(ctx, issue.MilestoneID); err != nil { - return nil, fmt.Errorf("error updating counters for milestone id %d: %w", - issue.MilestoneID, err) - } + // update the total issue numbers + if err := repo_model.UpdateRepoIssueNumbers(ctx, issue.RepoID, issue.IsPull, false); err != nil { + return nil, err + } + // if the issue is closed, update the closed issue numbers + if issue.IsClosed { + if err := repo_model.UpdateRepoIssueNumbers(ctx, issue.RepoID, issue.IsPull, true); err != nil { + return nil, err + } + } - if err := activities_model.DeleteIssueActions(ctx, issue.RepoID, issue.ID, issue.Index); err != nil { - return nil, err - } + if err := issues_model.UpdateMilestoneCounters(ctx, issue.MilestoneID); err != nil { + return nil, fmt.Errorf("error updating counters for milestone id %d: %w", + issue.MilestoneID, err) + } - // find attachments related to this issue and remove them - if err := issue.LoadAttachments(ctx); err != nil { - return nil, err - } + if err := activities_model.DeleteIssueActions(ctx, issue.RepoID, issue.ID, issue.Index); err != nil { + return nil, err + } - var attachmentPaths []string - for i := range issue.Attachments { - attachmentPaths = append(attachmentPaths, issue.Attachments[i].RelativePath()) - } + // find attachments related to this issue and remove them + if err := issue.LoadAttachments(ctx); err != nil { + return nil, err + } - // delete all database data still assigned to this issue - if err := db.DeleteBeans(ctx, - &issues_model.ContentHistory{IssueID: issue.ID}, - &issues_model.Comment{IssueID: issue.ID}, - &issues_model.IssueLabel{IssueID: issue.ID}, - &issues_model.IssueDependency{IssueID: issue.ID}, - &issues_model.IssueAssignees{IssueID: issue.ID}, - &issues_model.IssueUser{IssueID: issue.ID}, - &activities_model.Notification{IssueID: issue.ID}, - &issues_model.Reaction{IssueID: issue.ID}, - &issues_model.IssueWatch{IssueID: issue.ID}, - &issues_model.Stopwatch{IssueID: issue.ID}, - &issues_model.TrackedTime{IssueID: issue.ID}, - &project_model.ProjectIssue{IssueID: issue.ID}, - &repo_model.Attachment{IssueID: issue.ID}, - &issues_model.PullRequest{IssueID: issue.ID}, - &issues_model.Comment{RefIssueID: issue.ID}, - &issues_model.IssueDependency{DependencyID: issue.ID}, - &issues_model.Comment{DependentIssueID: issue.ID}, - &issues_model.IssuePin{IssueID: issue.ID}, - ); err != nil { - return nil, err - } + var attachmentPaths []string + for i := range issue.Attachments { + attachmentPaths = append(attachmentPaths, issue.Attachments[i].RelativePath()) + } - if err := committer.Commit(); err != nil { - return nil, err - } - return attachmentPaths, nil + // delete all database data still assigned to this issue + if err := db.DeleteBeans(ctx, + &issues_model.ContentHistory{IssueID: issue.ID}, + &issues_model.Comment{IssueID: issue.ID}, + &issues_model.IssueLabel{IssueID: issue.ID}, + &issues_model.IssueDependency{IssueID: issue.ID}, + &issues_model.IssueAssignees{IssueID: issue.ID}, + &issues_model.IssueUser{IssueID: issue.ID}, + &activities_model.Notification{IssueID: issue.ID}, + &issues_model.Reaction{IssueID: issue.ID}, + &issues_model.IssueWatch{IssueID: issue.ID}, + &issues_model.Stopwatch{IssueID: issue.ID}, + &issues_model.TrackedTime{IssueID: issue.ID}, + &project_model.ProjectIssue{IssueID: issue.ID}, + &repo_model.Attachment{IssueID: issue.ID}, + &issues_model.PullRequest{IssueID: issue.ID}, + &issues_model.Comment{RefIssueID: issue.ID}, + &issues_model.IssueDependency{DependencyID: issue.ID}, + &issues_model.Comment{DependentIssueID: issue.ID}, + &issues_model.IssuePin{IssueID: issue.ID}, + ); err != nil { + return nil, err + } + + return attachmentPaths, nil + }) } // DeleteOrphanedIssues delete issues without a repo diff --git a/services/org/org.go b/services/org/org.go index 142a643f9fc..8da77c691c1 100644 --- a/services/org/org.go +++ b/services/org/org.go @@ -52,39 +52,34 @@ func deleteOrganization(ctx context.Context, org *org_model.Organization) error // DeleteOrganization completely and permanently deletes everything of organization. func DeleteOrganization(ctx context.Context, org *org_model.Organization, purge bool) error { - ctx, committer, err := db.TxContext(ctx) - if err != nil { - return err - } - defer committer.Close() - - if purge { - err := repo_service.DeleteOwnerRepositoriesDirectly(ctx, org.AsUser()) - if err != nil { - return err + if err := db.WithTx(ctx, func(ctx context.Context) error { + if purge { + err := repo_service.DeleteOwnerRepositoriesDirectly(ctx, org.AsUser()) + if err != nil { + return err + } } - } - // Check ownership of repository. - count, err := repo_model.CountRepositories(ctx, repo_model.CountRepositoryOptions{OwnerID: org.ID}) - if err != nil { - return fmt.Errorf("GetRepositoryCount: %w", err) - } else if count > 0 { - return repo_model.ErrUserOwnRepos{UID: org.ID} - } + // Check ownership of repository. + count, err := repo_model.CountRepositories(ctx, repo_model.CountRepositoryOptions{OwnerID: org.ID}) + if err != nil { + return fmt.Errorf("GetRepositoryCount: %w", err) + } else if count > 0 { + return repo_model.ErrUserOwnRepos{UID: org.ID} + } - // Check ownership of packages. - if ownsPackages, err := packages_model.HasOwnerPackages(ctx, org.ID); err != nil { - return fmt.Errorf("HasOwnerPackages: %w", err) - } else if ownsPackages { - return packages_model.ErrUserOwnPackages{UID: org.ID} - } + // Check ownership of packages. + if ownsPackages, err := packages_model.HasOwnerPackages(ctx, org.ID); err != nil { + return fmt.Errorf("HasOwnerPackages: %w", err) + } else if ownsPackages { + return packages_model.ErrUserOwnPackages{UID: org.ID} + } - if err := deleteOrganization(ctx, org); err != nil { - return fmt.Errorf("DeleteOrganization: %w", err) - } - - if err := committer.Commit(); err != nil { + if err := deleteOrganization(ctx, org); err != nil { + return fmt.Errorf("DeleteOrganization: %w", err) + } + return nil + }); err != nil { return err } diff --git a/services/org/user.go b/services/org/user.go index 26927253d25..68582718582 100644 --- a/services/org/user.go +++ b/services/org/user.go @@ -47,57 +47,52 @@ func RemoveOrgUser(ctx context.Context, org *organization.Organization, user *us } } - ctx, committer, err := db.TxContext(ctx) - if err != nil { - return err - } - defer committer.Close() + return db.WithTx(ctx, func(ctx context.Context) error { + if _, err := db.DeleteByID[organization.OrgUser](ctx, ou.ID); err != nil { + return err + } else if _, err = db.Exec(ctx, "UPDATE `user` SET num_members=num_members-1 WHERE id=?", org.ID); err != nil { + return err + } - if _, err := db.DeleteByID[organization.OrgUser](ctx, ou.ID); err != nil { - return err - } else if _, err = db.Exec(ctx, "UPDATE `user` SET num_members=num_members-1 WHERE id=?", org.ID); err != nil { - return err - } + // Delete all repository accesses and unwatch them. + env, err := repo_model.AccessibleReposEnv(ctx, org, user.ID) + if err != nil { + return fmt.Errorf("AccessibleReposEnv: %w", err) + } + repoIDs, err := env.RepoIDs(ctx) + if err != nil { + return fmt.Errorf("GetUserRepositories [%d]: %w", user.ID, err) + } - // Delete all repository accesses and unwatch them. - env, err := repo_model.AccessibleReposEnv(ctx, org, user.ID) - if err != nil { - return fmt.Errorf("AccessibleReposEnv: %w", err) - } - repoIDs, err := env.RepoIDs(ctx) - if err != nil { - return fmt.Errorf("GetUserRepositories [%d]: %w", user.ID, err) - } + for _, repoID := range repoIDs { + repo, err := repo_model.GetRepositoryByID(ctx, repoID) + if err != nil { + return err + } + if err = repo_model.WatchRepo(ctx, user, repo, false); err != nil { + return err + } + } - for _, repoID := range repoIDs { - repo, err := repo_model.GetRepositoryByID(ctx, repoID) + if len(repoIDs) > 0 { + if _, err = db.GetEngine(ctx). + Where("user_id = ?", user.ID). + In("repo_id", repoIDs). + Delete(new(access_model.Access)); err != nil { + return err + } + } + + // Delete member in their teams. + teams, err := organization.GetUserOrgTeams(ctx, org.ID, user.ID) if err != nil { return err } - if err = repo_model.WatchRepo(ctx, user, repo, false); err != nil { - return err + for _, t := range teams { + if err = removeTeamMember(ctx, t, user); err != nil { + return err + } } - } - - if len(repoIDs) > 0 { - if _, err = db.GetEngine(ctx). - Where("user_id = ?", user.ID). - In("repo_id", repoIDs). - Delete(new(access_model.Access)); err != nil { - return err - } - } - - // Delete member in their teams. - teams, err := organization.GetUserOrgTeams(ctx, org.ID, user.ID) - if err != nil { - return err - } - for _, t := range teams { - if err = removeTeamMember(ctx, t, user); err != nil { - return err - } - } - - return committer.Commit() + return nil + }) } diff --git a/services/release/release.go b/services/release/release.go index 0b8a74252a0..1e2132bb60c 100644 --- a/services/release/release.go +++ b/services/release/release.go @@ -267,74 +267,69 @@ func UpdateRelease(ctx context.Context, doer *user_model.User, gitRepo *git.Repo } rel.LowerTagName = strings.ToLower(rel.TagName) - ctx, committer, err := db.TxContext(ctx) - if err != nil { - return err - } - defer committer.Close() - oldRelease, err := repo_model.GetReleaseByID(ctx, rel.ID) if err != nil { return err } isConvertedFromTag := oldRelease.IsTag && !rel.IsTag - if err = repo_model.UpdateRelease(ctx, rel); err != nil { - return err - } - - if err = repo_model.AddReleaseAttachments(ctx, rel.ID, addAttachmentUUIDs); err != nil { - return fmt.Errorf("AddReleaseAttachments: %w", err) - } - - deletedUUIDs := make(container.Set[string]) - if len(delAttachmentUUIDs) > 0 { - // Check attachments - attachments, err := repo_model.GetAttachmentsByUUIDs(ctx, delAttachmentUUIDs) - if err != nil { - return fmt.Errorf("GetAttachmentsByUUIDs [uuids: %v]: %w", delAttachmentUUIDs, err) + if err := db.WithTx(ctx, func(ctx context.Context) error { + if err = repo_model.UpdateRelease(ctx, rel); err != nil { + return err } - for _, attach := range attachments { - if attach.ReleaseID != rel.ID { - return util.NewPermissionDeniedErrorf("delete attachment of release permission denied") + + if err = repo_model.AddReleaseAttachments(ctx, rel.ID, addAttachmentUUIDs); err != nil { + return fmt.Errorf("AddReleaseAttachments: %w", err) + } + + deletedUUIDs := make(container.Set[string]) + if len(delAttachmentUUIDs) > 0 { + // Check attachments + attachments, err := repo_model.GetAttachmentsByUUIDs(ctx, delAttachmentUUIDs) + if err != nil { + return fmt.Errorf("GetAttachmentsByUUIDs [uuids: %v]: %w", delAttachmentUUIDs, err) + } + for _, attach := range attachments { + if attach.ReleaseID != rel.ID { + return util.NewPermissionDeniedErrorf("delete attachment of release permission denied") + } + deletedUUIDs.Add(attach.UUID) } - deletedUUIDs.Add(attach.UUID) - } - if _, err := repo_model.DeleteAttachments(ctx, attachments, true); err != nil { - return fmt.Errorf("DeleteAttachments [uuids: %v]: %w", delAttachmentUUIDs, err) - } - } - - if len(editAttachments) > 0 { - updateAttachmentsList := make([]string, 0, len(editAttachments)) - for k := range editAttachments { - updateAttachmentsList = append(updateAttachmentsList, k) - } - // Check attachments - attachments, err := repo_model.GetAttachmentsByUUIDs(ctx, updateAttachmentsList) - if err != nil { - return fmt.Errorf("GetAttachmentsByUUIDs [uuids: %v]: %w", updateAttachmentsList, err) - } - for _, attach := range attachments { - if attach.ReleaseID != rel.ID { - return util.NewPermissionDeniedErrorf("update attachment of release permission denied") + if _, err := repo_model.DeleteAttachments(ctx, attachments, true); err != nil { + return fmt.Errorf("DeleteAttachments [uuids: %v]: %w", delAttachmentUUIDs, err) } } - for uuid, newName := range editAttachments { - if !deletedUUIDs.Contains(uuid) { - if err = repo_model.UpdateAttachmentByUUID(ctx, &repo_model.Attachment{ - UUID: uuid, - Name: newName, - }, "name"); err != nil { - return err + if len(editAttachments) > 0 { + updateAttachmentsList := make([]string, 0, len(editAttachments)) + for k := range editAttachments { + updateAttachmentsList = append(updateAttachmentsList, k) + } + // Check attachments + attachments, err := repo_model.GetAttachmentsByUUIDs(ctx, updateAttachmentsList) + if err != nil { + return fmt.Errorf("GetAttachmentsByUUIDs [uuids: %v]: %w", updateAttachmentsList, err) + } + for _, attach := range attachments { + if attach.ReleaseID != rel.ID { + return util.NewPermissionDeniedErrorf("update attachment of release permission denied") + } + } + + for uuid, newName := range editAttachments { + if !deletedUUIDs.Contains(uuid) { + if err = repo_model.UpdateAttachmentByUUID(ctx, &repo_model.Attachment{ + UUID: uuid, + Name: newName, + }, "name"); err != nil { + return err + } } } } - } - - if err := committer.Commit(); err != nil { + return nil + }); err != nil { return err } diff --git a/services/repository/migrate.go b/services/repository/migrate.go index 664f0cf0974..66622f1601f 100644 --- a/services/repository/migrate.go +++ b/services/repository/migrate.go @@ -173,92 +173,88 @@ func MigrateRepositoryGitData(ctx context.Context, u *user_model.User, } } - ctx, committer, err := db.TxContext(ctx) - if err != nil { - return nil, err - } - defer committer.Close() - - if opts.Mirror { - remoteAddress, err := util.SanitizeURL(opts.CloneAddr) - if err != nil { - return repo, err - } - mirrorModel := repo_model.Mirror{ - RepoID: repo.ID, - Interval: setting.Mirror.DefaultInterval, - EnablePrune: true, - NextUpdateUnix: timeutil.TimeStampNow().AddDuration(setting.Mirror.DefaultInterval), - LFS: opts.LFS, - RemoteAddress: remoteAddress, - } - if opts.LFS { - mirrorModel.LFSEndpoint = opts.LFSEndpoint - } - - if opts.MirrorInterval != "" { - parsedInterval, err := time.ParseDuration(opts.MirrorInterval) + return db.WithTx2(ctx, func(ctx context.Context) (*repo_model.Repository, error) { + if opts.Mirror { + remoteAddress, err := util.SanitizeURL(opts.CloneAddr) if err != nil { - log.Error("Failed to set Interval: %v", err) return repo, err } - if parsedInterval == 0 { - mirrorModel.Interval = 0 - mirrorModel.NextUpdateUnix = 0 - } else if parsedInterval < setting.Mirror.MinInterval { - err := fmt.Errorf("interval %s is set below Minimum Interval of %s", parsedInterval, setting.Mirror.MinInterval) - log.Error("Interval: %s is too frequent", opts.MirrorInterval) - return repo, err - } else { - mirrorModel.Interval = parsedInterval - mirrorModel.NextUpdateUnix = timeutil.TimeStampNow().AddDuration(parsedInterval) + mirrorModel := repo_model.Mirror{ + RepoID: repo.ID, + Interval: setting.Mirror.DefaultInterval, + EnablePrune: true, + NextUpdateUnix: timeutil.TimeStampNow().AddDuration(setting.Mirror.DefaultInterval), + LFS: opts.LFS, + RemoteAddress: remoteAddress, + } + if opts.LFS { + mirrorModel.LFSEndpoint = opts.LFSEndpoint + } + + if opts.MirrorInterval != "" { + parsedInterval, err := time.ParseDuration(opts.MirrorInterval) + if err != nil { + log.Error("Failed to set Interval: %v", err) + return repo, err + } + if parsedInterval == 0 { + mirrorModel.Interval = 0 + mirrorModel.NextUpdateUnix = 0 + } else if parsedInterval < setting.Mirror.MinInterval { + err := fmt.Errorf("interval %s is set below Minimum Interval of %s", parsedInterval, setting.Mirror.MinInterval) + log.Error("Interval: %s is too frequent", opts.MirrorInterval) + return repo, err + } else { + mirrorModel.Interval = parsedInterval + mirrorModel.NextUpdateUnix = timeutil.TimeStampNow().AddDuration(parsedInterval) + } + } + + if err = repo_model.InsertMirror(ctx, &mirrorModel); err != nil { + return repo, fmt.Errorf("InsertOne: %w", err) + } + + repo.IsMirror = true + if err = repo_model.UpdateRepositoryColsNoAutoTime(ctx, repo, "num_watches", "is_empty", "default_branch", "default_wiki_branch", "is_mirror"); err != nil { + return nil, err + } + + if err = repo_module.UpdateRepoSize(ctx, repo); err != nil { + log.Error("Failed to update size for repository: %v", err) + } + + // this is necessary for sync local tags from remote + configName := fmt.Sprintf("remote.%s.fetch", mirrorModel.GetRemoteName()) + if stdout, _, err := git.NewCommand("config"). + AddOptionValues("--add", configName, `+refs/tags/*:refs/tags/*`). + RunStdString(ctx, &git.RunOpts{Dir: repoPath}); err != nil { + log.Error("MigrateRepositoryGitData(git config --add +refs/tags/*:refs/tags/*) in %v: Stdout: %s\nError: %v", repo, stdout, err) + return repo, fmt.Errorf("error in MigrateRepositoryGitData(git config --add +refs/tags/*:refs/tags/*): %w", err) + } + } else { + if err = repo_module.UpdateRepoSize(ctx, repo); err != nil { + log.Error("Failed to update size for repository: %v", err) + } + if repo, err = CleanUpMigrateInfo(ctx, repo); err != nil { + return nil, err } } - if err = repo_model.InsertMirror(ctx, &mirrorModel); err != nil { - return repo, fmt.Errorf("InsertOne: %w", err) + var enableRepoUnits []repo_model.RepoUnit + if opts.Releases && !unit_model.TypeReleases.UnitGlobalDisabled() { + enableRepoUnits = append(enableRepoUnits, repo_model.RepoUnit{RepoID: repo.ID, Type: unit_model.TypeReleases}) } - - repo.IsMirror = true - if err = repo_model.UpdateRepositoryColsNoAutoTime(ctx, repo, "num_watches", "is_empty", "default_branch", "default_wiki_branch", "is_mirror"); err != nil { - return nil, err + if opts.Wiki && !unit_model.TypeWiki.UnitGlobalDisabled() { + enableRepoUnits = append(enableRepoUnits, repo_model.RepoUnit{RepoID: repo.ID, Type: unit_model.TypeWiki}) } - - if err = repo_module.UpdateRepoSize(ctx, repo); err != nil { - log.Error("Failed to update size for repository: %v", err) + if len(enableRepoUnits) > 0 { + err = UpdateRepositoryUnits(ctx, repo, enableRepoUnits, nil) + if err != nil { + return nil, err + } } - - // this is necessary for sync local tags from remote - configName := fmt.Sprintf("remote.%s.fetch", mirrorModel.GetRemoteName()) - if stdout, _, err := git.NewCommand("config"). - AddOptionValues("--add", configName, `+refs/tags/*:refs/tags/*`). - RunStdString(ctx, &git.RunOpts{Dir: repoPath}); err != nil { - log.Error("MigrateRepositoryGitData(git config --add +refs/tags/*:refs/tags/*) in %v: Stdout: %s\nError: %v", repo, stdout, err) - return repo, fmt.Errorf("error in MigrateRepositoryGitData(git config --add +refs/tags/*:refs/tags/*): %w", err) - } - } else { - if err = repo_module.UpdateRepoSize(ctx, repo); err != nil { - log.Error("Failed to update size for repository: %v", err) - } - if repo, err = CleanUpMigrateInfo(ctx, repo); err != nil { - return nil, err - } - } - - var enableRepoUnits []repo_model.RepoUnit - if opts.Releases && !unit_model.TypeReleases.UnitGlobalDisabled() { - enableRepoUnits = append(enableRepoUnits, repo_model.RepoUnit{RepoID: repo.ID, Type: unit_model.TypeReleases}) - } - if opts.Wiki && !unit_model.TypeWiki.UnitGlobalDisabled() { - enableRepoUnits = append(enableRepoUnits, repo_model.RepoUnit{RepoID: repo.ID, Type: unit_model.TypeWiki}) - } - if len(enableRepoUnits) > 0 { - err = UpdateRepositoryUnits(ctx, repo, enableRepoUnits, nil) - if err != nil { - return nil, err - } - } - return repo, committer.Commit() + return repo, nil + }) } // CleanUpMigrateInfo finishes migrating repository and/or wiki with things that don't need to be done for mirrors. diff --git a/services/user/user.go b/services/user/user.go index c7252430dea..d8abf199c3f 100644 --- a/services/user/user.go +++ b/services/user/user.go @@ -210,65 +210,59 @@ func DeleteUser(ctx context.Context, u *user_model.User, purge bool) error { } } - ctx, committer, err := db.TxContext(ctx) - if err != nil { + if err := db.WithTx(ctx, func(ctx context.Context) error { + // Note: A user owns any repository or belongs to any organization + // cannot perform delete operation. This causes a race with the purge above + // however consistency requires that we ensure that this is the case + + // Check ownership of repository. + count, err := repo_model.CountRepositories(ctx, repo_model.CountRepositoryOptions{OwnerID: u.ID}) + if err != nil { + return fmt.Errorf("GetRepositoryCount: %w", err) + } else if count > 0 { + return repo_model.ErrUserOwnRepos{UID: u.ID} + } + + // Check membership of organization. + count, err = organization.GetOrganizationCount(ctx, u) + if err != nil { + return fmt.Errorf("GetOrganizationCount: %w", err) + } else if count > 0 { + return organization.ErrUserHasOrgs{UID: u.ID} + } + + // Check ownership of packages. + if ownsPackages, err := packages_model.HasOwnerPackages(ctx, u.ID); err != nil { + return fmt.Errorf("HasOwnerPackages: %w", err) + } else if ownsPackages { + return packages_model.ErrUserOwnPackages{UID: u.ID} + } + + if err := deleteUser(ctx, u, purge); err != nil { + return fmt.Errorf("DeleteUser: %w", err) + } + return nil + }); err != nil { return err } - defer committer.Close() - // Note: A user owns any repository or belongs to any organization - // cannot perform delete operation. This causes a race with the purge above - // however consistency requires that we ensure that this is the case - - // Check ownership of repository. - count, err := repo_model.CountRepositories(ctx, repo_model.CountRepositoryOptions{OwnerID: u.ID}) - if err != nil { - return fmt.Errorf("GetRepositoryCount: %w", err) - } else if count > 0 { - return repo_model.ErrUserOwnRepos{UID: u.ID} - } - - // Check membership of organization. - count, err = organization.GetOrganizationCount(ctx, u) - if err != nil { - return fmt.Errorf("GetOrganizationCount: %w", err) - } else if count > 0 { - return organization.ErrUserHasOrgs{UID: u.ID} - } - - // Check ownership of packages. - if ownsPackages, err := packages_model.HasOwnerPackages(ctx, u.ID); err != nil { - return fmt.Errorf("HasOwnerPackages: %w", err) - } else if ownsPackages { - return packages_model.ErrUserOwnPackages{UID: u.ID} - } - - if err := deleteUser(ctx, u, purge); err != nil { - return fmt.Errorf("DeleteUser: %w", err) - } - - if err := committer.Commit(); err != nil { + if err := asymkey_service.RewriteAllPublicKeys(ctx); err != nil { return err } - _ = committer.Close() - - if err = asymkey_service.RewriteAllPublicKeys(ctx); err != nil { - return err - } - if err = asymkey_service.RewriteAllPrincipalKeys(ctx); err != nil { + if err := asymkey_service.RewriteAllPrincipalKeys(ctx); err != nil { return err } // Note: There are something just cannot be roll back, so just keep error logs of those operations. path := user_model.UserPath(u.Name) - if err = util.RemoveAll(path); err != nil { + if err := util.RemoveAll(path); err != nil { err = fmt.Errorf("failed to RemoveAll %s: %w", path, err) _ = system_model.CreateNotice(ctx, system_model.NoticeTask, fmt.Sprintf("delete user '%s': %v", u.Name, err)) } if u.Avatar != "" { avatarPath := u.CustomAvatarRelativePath() - if err = storage.Avatars.Delete(avatarPath); err != nil { + if err := storage.Avatars.Delete(avatarPath); err != nil { err = fmt.Errorf("failed to remove %s: %w", avatarPath, err) _ = system_model.CreateNotice(ctx, system_model.NoticeTask, fmt.Sprintf("delete user '%s': %v", u.Name, err)) } From 274f4aea7e944128b9ed033fade20caafbb8fca8 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Tue, 9 Sep 2025 21:04:32 -0700 Subject: [PATCH 05/30] Fix a compare page 404 bug when the pull request disabled (#35441) --- routers/web/repo/compare.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/routers/web/repo/compare.go b/routers/web/repo/compare.go index 20f5d6262ef..a7084bf0aec 100644 --- a/routers/web/repo/compare.go +++ b/routers/web/repo/compare.go @@ -524,7 +524,7 @@ func ParseCompareInfo(ctx *context.Context) *common.CompareInfo { // Treat as pull request if both references are branches if ctx.Data["PageIsComparePull"] == nil { - ctx.Data["PageIsComparePull"] = headIsBranch && baseIsBranch + ctx.Data["PageIsComparePull"] = headIsBranch && baseIsBranch && permBase.CanReadIssuesOrPulls(true) } if ctx.Data["PageIsComparePull"] == true && !permBase.CanReadIssuesOrPulls(true) { @@ -730,6 +730,7 @@ func CompareDiff(ctx *context.Context) { return } + ctx.Data["PageIsViewCode"] = true ctx.Data["PullRequestWorkInProgressPrefixes"] = setting.Repository.PullRequest.WorkInProgressPrefixes ctx.Data["DirectComparison"] = ci.DirectComparison ctx.Data["OtherCompareSeparator"] = ".." From b76e69fee7ad286db72a48ad375e7d7596d06ce9 Mon Sep 17 00:00:00 2001 From: silverwind Date: Wed, 10 Sep 2025 15:05:35 +0200 Subject: [PATCH 06/30] Fix overflow in notifications list (#35446) Before: Screenshot 2025-09-10 at 02 29 09 After: Screenshot 2025-09-10 at 02 29 17 --- web_src/css/user.css | 1 + 1 file changed, 1 insertion(+) diff --git a/web_src/css/user.css b/web_src/css/user.css index d42e8688fbc..a9b283b5047 100644 --- a/web_src/css/user.css +++ b/web_src/css/user.css @@ -120,6 +120,7 @@ flex-wrap: wrap; gap: 0.5em; padding: 0.5em 1em; + overflow-wrap: anywhere; } .notifications-item:hover { From 2653ac95e08ca61e9d0d8e76333901a6e516dd20 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Wed, 10 Sep 2025 06:31:59 -0700 Subject: [PATCH 07/30] Extend comment treepath length (#35389) Extend the maximum length of comment.treepath from 255 to 4000 characters. All databases supported by Gitea allow VARCHAR fields of 4000, so compatibility is ensured. Git itself does not impose a strict limit on path length. On Windows, the `core.longpaths` setting has already been enabled to handle long file paths. Fix #33716 --------- Signed-off-by: wxiaoguang Co-authored-by: wxiaoguang Co-authored-by: Giteabot --- models/issues/comment.go | 4 ++-- models/migrations/migrations.go | 1 + models/migrations/v1_25/v322.go | 28 ++++++++++++++++++++++++++++ 3 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 models/migrations/v1_25/v322.go diff --git a/models/issues/comment.go b/models/issues/comment.go index a366b7c6a9c..3a4049700de 100644 --- a/models/issues/comment.go +++ b/models/issues/comment.go @@ -279,8 +279,8 @@ type Comment struct { DependentIssue *Issue `xorm:"-"` CommitID int64 - Line int64 // - previous line / + proposed line - TreePath string + Line int64 // - previous line / + proposed line + TreePath string `xorm:"VARCHAR(4000)"` // SQLServer only supports up to 4000 Content string `xorm:"LONGTEXT"` ContentVersion int `xorm:"NOT NULL DEFAULT 0"` RenderedContent template.HTML `xorm:"-"` diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index 88967a8b870..1b1558f39d1 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -393,6 +393,7 @@ func prepareMigrationTasks() []*migration { // Gitea 1.24.0 ends at database version 321 newMigration(321, "Use LONGTEXT for some columns and fix review_state.updated_files column", v1_25.UseLongTextInSomeColumnsAndFixBugs), + newMigration(322, "Extend comment tree_path length limit", v1_25.ExtendCommentTreePathLength), } return preparedMigrations } diff --git a/models/migrations/v1_25/v322.go b/models/migrations/v1_25/v322.go new file mode 100644 index 00000000000..32dae9945ae --- /dev/null +++ b/models/migrations/v1_25/v322.go @@ -0,0 +1,28 @@ +// Copyright 2025 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package v1_25 + +import ( + "code.gitea.io/gitea/models/migrations/base" + + "xorm.io/xorm" + "xorm.io/xorm/schemas" +) + +func ExtendCommentTreePathLength(x *xorm.Engine) error { + dbType := x.Dialect().URI().DBType + if dbType == schemas.SQLITE { // For SQLITE, varchar or char will always be represented as TEXT + return nil + } + + return base.ModifyColumn(x, "comment", &schemas.Column{ + Name: "tree_path", + SQLType: schemas.SQLType{ + Name: "VARCHAR", + }, + Length: 4000, + Nullable: true, // To keep compatible as nullable + DefaultIsEmpty: true, + }) +} From 4d43d85941420fc2fbaa977f82ff870809c03190 Mon Sep 17 00:00:00 2001 From: silverwind Date: Wed, 10 Sep 2025 18:11:14 +0200 Subject: [PATCH 08/30] Bump setup-node to v5 (#35448) See https://github.com/actions/setup-node/releases/tag/v5.0.0 Caching is now enabled by default when `packageManager` is present in package.json, and we have that. `cache-dependency-path` is unneccesary because the action will automatically detect it. --- .github/workflows/pull-compliance.yml | 16 ++++------------ .github/workflows/pull-e2e-tests.yml | 4 +--- .github/workflows/release-nightly.yml | 4 +--- .github/workflows/release-tag-rc.yml | 4 +--- .github/workflows/release-tag-version.yml | 4 +--- 5 files changed, 8 insertions(+), 24 deletions(-) diff --git a/.github/workflows/pull-compliance.yml b/.github/workflows/pull-compliance.yml index c6daee84115..6f8991ed4ee 100644 --- a/.github/workflows/pull-compliance.yml +++ b/.github/workflows/pull-compliance.yml @@ -35,11 +35,9 @@ jobs: - uses: astral-sh/setup-uv@v6 - run: uv python install 3.12 - uses: pnpm/action-setup@v4 - - uses: actions/setup-node@v4 + - uses: actions/setup-node@v5 with: node-version: 24 - cache: pnpm - cache-dependency-path: pnpm-lock.yaml - run: make deps-py - run: make deps-frontend - run: make lint-templates @@ -62,11 +60,9 @@ jobs: steps: - uses: actions/checkout@v4 - uses: pnpm/action-setup@v4 - - uses: actions/setup-node@v4 + - uses: actions/setup-node@v5 with: node-version: 24 - cache: pnpm - cache-dependency-path: pnpm-lock.yaml - run: make deps-frontend - run: make lint-swagger @@ -134,11 +130,9 @@ jobs: steps: - uses: actions/checkout@v4 - uses: pnpm/action-setup@v4 - - uses: actions/setup-node@v4 + - uses: actions/setup-node@v5 with: node-version: 24 - cache: pnpm - cache-dependency-path: pnpm-lock.yaml - run: make deps-frontend - run: make lint-frontend - run: make checks-frontend @@ -184,11 +178,9 @@ jobs: steps: - uses: actions/checkout@v4 - uses: pnpm/action-setup@v4 - - uses: actions/setup-node@v4 + - uses: actions/setup-node@v5 with: node-version: 24 - cache: pnpm - cache-dependency-path: pnpm-lock.yaml - run: make deps-frontend - run: make lint-md diff --git a/.github/workflows/pull-e2e-tests.yml b/.github/workflows/pull-e2e-tests.yml index 9f42581e0c8..89b32260ca0 100644 --- a/.github/workflows/pull-e2e-tests.yml +++ b/.github/workflows/pull-e2e-tests.yml @@ -24,11 +24,9 @@ jobs: go-version-file: go.mod check-latest: true - uses: pnpm/action-setup@v4 - - uses: actions/setup-node@v4 + - uses: actions/setup-node@v5 with: node-version: 24 - cache: pnpm - cache-dependency-path: pnpm-lock.yaml - run: make deps-frontend frontend deps-backend - run: pnpm exec playwright install --with-deps - run: make test-e2e-sqlite diff --git a/.github/workflows/release-nightly.yml b/.github/workflows/release-nightly.yml index 81041bf564c..3d652e4ad8b 100644 --- a/.github/workflows/release-nightly.yml +++ b/.github/workflows/release-nightly.yml @@ -21,11 +21,9 @@ jobs: go-version-file: go.mod check-latest: true - uses: pnpm/action-setup@v4 - - uses: actions/setup-node@v4 + - uses: actions/setup-node@v5 with: node-version: 24 - cache: pnpm - cache-dependency-path: pnpm-lock.yaml - run: make deps-frontend deps-backend # xgo build - run: make release diff --git a/.github/workflows/release-tag-rc.yml b/.github/workflows/release-tag-rc.yml index f7ca1d0a139..f4776a9ed8c 100644 --- a/.github/workflows/release-tag-rc.yml +++ b/.github/workflows/release-tag-rc.yml @@ -22,11 +22,9 @@ jobs: go-version-file: go.mod check-latest: true - uses: pnpm/action-setup@v4 - - uses: actions/setup-node@v4 + - uses: actions/setup-node@v5 with: node-version: 24 - cache: pnpm - cache-dependency-path: pnpm-lock.yaml - run: make deps-frontend deps-backend # xgo build - run: make release diff --git a/.github/workflows/release-tag-version.yml b/.github/workflows/release-tag-version.yml index 43ea6dce2fd..ad0820f31fe 100644 --- a/.github/workflows/release-tag-version.yml +++ b/.github/workflows/release-tag-version.yml @@ -26,11 +26,9 @@ jobs: go-version-file: go.mod check-latest: true - uses: pnpm/action-setup@v4 - - uses: actions/setup-node@v4 + - uses: actions/setup-node@v5 with: node-version: 24 - cache: pnpm - cache-dependency-path: pnpm-lock.yaml - run: make deps-frontend deps-backend # xgo build - run: make release From 593a52c2f04979a4a12091c0b5a3ac1977883923 Mon Sep 17 00:00:00 2001 From: silverwind Date: Wed, 10 Sep 2025 22:20:23 +0200 Subject: [PATCH 09/30] Vertically center date in file view latest commit (#35456) --- templates/repo/view_file.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/repo/view_file.tmpl b/templates/repo/view_file.tmpl index d022af38fdf..8fce1b6f2c8 100644 --- a/templates/repo/view_file.tmpl +++ b/templates/repo/view_file.tmpl @@ -17,7 +17,7 @@ {{template "repo/latest_commit" .}} {{if .LatestCommit}} {{if .LatestCommit.Committer}} -
+
{{DateUtils.TimeSince .LatestCommit.Committer.When}}
{{end}} From 89d79297112b965aa8a8f53cc97fe7c19dd0e352 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Wed, 10 Sep 2025 16:50:17 -0700 Subject: [PATCH 10/30] Fix package link setting can only list limited repositories (#35394) Fix #24801 image --------- Co-authored-by: wxiaoguang Co-authored-by: Giteabot --- options/locale/locale_en-US.ini | 5 +- routers/web/user/package.go | 113 ++++++++++++---------- services/forms/user_form.go | 4 +- templates/org/team/repositories.tmpl | 2 +- templates/package/settings.tmpl | 26 ++--- web_src/js/features/common-page.ts | 7 +- web_src/js/features/comp/SearchRepoBox.ts | 26 +++++ web_src/js/features/org-team.ts | 27 ------ web_src/js/index-domready.ts | 5 +- 9 files changed, 104 insertions(+), 111 deletions(-) create mode 100644 web_src/js/features/comp/SearchRepoBox.ts diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index a974b172256..b3eb7b1f4a4 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -3729,11 +3729,14 @@ swift.install = Add the package in your Package.swift file: swift.install2 = and run the following command: vagrant.install = To add a Vagrant box, run the following command: settings.link = Link this package to a repository -settings.link.description = If you link a package with a repository, the package is listed in the repository's package list. +settings.link.description = If you link a package with a repository, the package will appear in the repository's package list. Only repositories under the same owner can be linked. Leaving the field empty will remove the link. settings.link.select = Select Repository settings.link.button = Update Repository Link settings.link.success = Repository link was successfully updated. settings.link.error = Failed to update repository link. +settings.link.repo_not_found = Repository %s not found. +settings.unlink.error = Failed to remove repository link. +settings.unlink.success = Repository link was successfully removed. settings.delete = Delete package settings.delete.description = Deleting a package is permanent and cannot be undone. settings.delete.notice = You are about to delete %s (%s). This operation is irreversible, are you sure? diff --git a/routers/web/user/package.go b/routers/web/user/package.go index d130d1dca18..924a10041b0 100644 --- a/routers/web/user/package.go +++ b/routers/web/user/package.go @@ -431,74 +431,81 @@ func PackageSettings(ctx *context.Context) { ctx.Data["Title"] = pd.Package.Name ctx.Data["IsPackagesPage"] = true ctx.Data["PackageDescriptor"] = pd - - repos, _, _ := repo_model.GetUserRepositories(ctx, repo_model.SearchRepoOptions{ - Actor: pd.Owner, - Private: true, - }) - ctx.Data["Repos"] = repos ctx.Data["CanWritePackages"] = ctx.Package.AccessMode >= perm.AccessModeWrite || ctx.IsUserSiteAdmin() + if pd.Package.RepoID > 0 { + repo, err := repo_model.GetRepositoryByID(ctx, pd.Package.RepoID) + if err != nil { + ctx.ServerError("GetRepositoryByID", err) + return + } + ctx.Data["LinkedRepoName"] = repo.Name + } + ctx.HTML(http.StatusOK, tplPackagesSettings) } // PackageSettingsPost updates the package settings func PackageSettingsPost(ctx *context.Context) { - pd := ctx.Package.Descriptor - form := web.GetForm(ctx).(*forms.PackageSettingForm) switch form.Action { case "link": - success := func() bool { - repoID := int64(0) - if form.RepoID != 0 { - repo, err := repo_model.GetRepositoryByID(ctx, form.RepoID) - if err != nil { - log.Error("Error getting repository: %v", err) - return false - } - - if repo.OwnerID != pd.Owner.ID { - return false - } - - repoID = repo.ID - } - - if err := packages_model.SetRepositoryLink(ctx, pd.Package.ID, repoID); err != nil { - log.Error("Error updating package: %v", err) - return false - } - - return true - }() - - if success { - ctx.Flash.Success(ctx.Tr("packages.settings.link.success")) - } else { - ctx.Flash.Error(ctx.Tr("packages.settings.link.error")) - } - - ctx.Redirect(ctx.Link) - return + packageSettingsPostActionLink(ctx, form) case "delete": - err := packages_service.RemovePackageVersion(ctx, ctx.Doer, ctx.Package.Descriptor.Version) - if err != nil { - log.Error("Error deleting package: %v", err) - ctx.Flash.Error(ctx.Tr("packages.settings.delete.error")) - } else { - ctx.Flash.Success(ctx.Tr("packages.settings.delete.success")) + packageSettingsPostActionDelete(ctx) + default: + ctx.NotFound(nil) + } +} + +func packageSettingsPostActionLink(ctx *context.Context, form *forms.PackageSettingForm) { + pd := ctx.Package.Descriptor + if form.RepoName == "" { // remove the link + if err := packages_model.SetRepositoryLink(ctx, pd.Package.ID, 0); err != nil { + ctx.JSONError(ctx.Tr("packages.settings.unlink.error")) + return } - redirectURL := ctx.Package.Owner.HomeLink() + "/-/packages" - // redirect to the package if there are still versions available - if has, _ := packages_model.ExistVersion(ctx, &packages_model.PackageSearchOptions{PackageID: ctx.Package.Descriptor.Package.ID, IsInternal: optional.Some(false)}); has { - redirectURL = ctx.Package.Descriptor.PackageWebLink() - } - - ctx.Redirect(redirectURL) + ctx.Flash.Success(ctx.Tr("packages.settings.unlink.success")) + ctx.JSONRedirect("") return } + + repo, err := repo_model.GetRepositoryByName(ctx, pd.Owner.ID, form.RepoName) + if err != nil { + if repo_model.IsErrRepoNotExist(err) { + ctx.JSONError(ctx.Tr("packages.settings.link.repo_not_found", form.RepoName)) + } else { + ctx.ServerError("GetRepositoryByOwnerAndName", err) + } + return + } + + if err := packages_model.SetRepositoryLink(ctx, pd.Package.ID, repo.ID); err != nil { + ctx.JSONError(ctx.Tr("packages.settings.link.error")) + return + } + + ctx.Flash.Success(ctx.Tr("packages.settings.link.success")) + ctx.JSONRedirect("") +} + +func packageSettingsPostActionDelete(ctx *context.Context) { + err := packages_service.RemovePackageVersion(ctx, ctx.Doer, ctx.Package.Descriptor.Version) + if err != nil { + log.Error("Error deleting package: %v", err) + ctx.Flash.Error(ctx.Tr("packages.settings.delete.error")) + } else { + ctx.Flash.Success(ctx.Tr("packages.settings.delete.success")) + } + + redirectURL := ctx.Package.Owner.HomeLink() + "/-/packages" + // redirect to the package if there are still versions available + if has, _ := packages_model.ExistVersion(ctx, &packages_model.PackageSearchOptions{PackageID: ctx.Package.Descriptor.Package.ID, IsInternal: optional.Some(false)}); has { + redirectURL = ctx.Package.Descriptor.PackageWebLink() + } + + ctx.Redirect(redirectURL) } // DownloadPackageFile serves the content of a package file diff --git a/services/forms/user_form.go b/services/forms/user_form.go index ddf2bd09b0b..618294d4341 100644 --- a/services/forms/user_form.go +++ b/services/forms/user_form.go @@ -416,8 +416,8 @@ func (f *WebauthnDeleteForm) Validate(req *http.Request, errs binding.Errors) bi // PackageSettingForm form for package settings type PackageSettingForm struct { - Action string - RepoID int64 `form:"repo_id"` + Action string + RepoName string `form:"repo_name"` } // Validate validates the fields diff --git a/templates/org/team/repositories.tmpl b/templates/org/team/repositories.tmpl index 4f4667ca8bf..2f38071e89f 100644 --- a/templates/org/team/repositories.tmpl +++ b/templates/org/team/repositories.tmpl @@ -12,7 +12,7 @@
{{.CsrfTokenHtml}} -