From 48d5adb39ca21e324f278fd196f6586738421f68 Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Mon, 12 Jan 2026 00:42:33 +0000 Subject: [PATCH 01/23] [skip ci] Updated translations via Crowdin --- options/locale/locale_ga-IE.json | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/options/locale/locale_ga-IE.json b/options/locale/locale_ga-IE.json index 679963630a..18bef7188c 100644 --- a/options/locale/locale_ga-IE.json +++ b/options/locale/locale_ga-IE.json @@ -32,6 +32,7 @@ "password": "Pasfhocal", "access_token": "Comhartha Rochtana", "re_type": "Deimhnigh Pasfhocal", + "captcha": "CAPTCHA", "twofa": "Fíordheimhniú Dhá-Fhachtóir", "twofa_scratch": "Cód Scratch Dhá-Fhachtóra", "passcode": "Paschód", @@ -132,6 +133,7 @@ "confirm_delete_selected": "Deimhnigh chun gach earra roghnaithe a scriosadh?", "name": "Ainm", "value": "Luach", + "readme": "Léigh-mé", "filter_title": "Scagaire", "filter.clear": "Scagaire Soiléir", "filter.is_archived": "Cartlannaithe", @@ -229,6 +231,7 @@ "install.db_name": "Ainm Bunachar Sonraí", "install.db_schema": "Scéim", "install.db_schema_helper": "Fág bán le haghaidh réamhshocraithe bunachar sonraí (\"poiblí\").", + "install.ssl_mode": "SSL", "install.path": "Cosán", "install.sqlite_helper": "Conair comhad don bhunachar sonraí SQLite3. Cuir
isteach cosán iomlán má reáchtáil tú Gitea mar sheirbhís.", "install.reinstall_error": "Tá tú ag iarraidh a shuiteáil i mbunachar sonraí Gitea atá ann cheana", @@ -406,6 +409,7 @@ "auth.twofa_scratch_token_incorrect": "Tá do chód scratch mícheart.", "auth.twofa_required": "Ní mór duit fíordheimhniú dhá fhachtóir a shocrú chun rochtain a fháil ar stórtha, nó iarracht a dhéanamh logáil isteach arís.", "auth.login_userpass": "Sínigh isteach", + "auth.login_openid": "OpenID", "auth.oauth_signup_tab": "Cláraigh Cuntas Nua", "auth.oauth_signup_title": "Comhlánaigh Cuntas Nua", "auth.oauth_signup_submit": "Cuntas Comhlánaigh", @@ -654,6 +658,7 @@ "settings.twofa": "Fíordheimhniú Dhá Fachtóir (TOTP)", "settings.account_link": "Cuntais Nasctha", "settings.organization": "Eagraíochtaí", + "settings.uid": "UID", "settings.webauthn": "Fíordheimhniú Dhá-Fachtóir (Eochracha Slándála)", "settings.public_profile": "Próifíl Phoiblí", "settings.biography_placeholder": "Inis dúinn beagán fút féin! (Is féidir leat Markdown a úsáid)", @@ -991,6 +996,7 @@ "repo.multiple_licenses": "Ceadúnais Iolracha", "repo.object_format": "Formáid Oibiacht", "repo.object_format_helper": "Formáid oibiacht an stór. Ní féidir é a athrú níos déanaí. Is é SHA1 an comhoiriúnacht is fearr.", + "repo.readme": "LÉIGHMÉ", "repo.readme_helper": "Roghnaigh comhad teimpléad README.", "repo.readme_helper_desc": "Seo an áit inar féidir leat cur síos iomlán a scríobh do thionscadal.", "repo.auto_init": "Taisce a thionscnamh (Cuireann sé .gitignore, Ceadúnas agus README)", @@ -1055,6 +1061,7 @@ "repo.desc.template": "Teimpléad", "repo.desc.internal": "Inmheánach", "repo.desc.archived": "Cartlannaithe", + "repo.desc.sha256": "SHA256", "repo.template.items": "Míreanna Teimpléad", "repo.template.git_content": "Ábhar Git (Brainse Réamhshocraithe)", "repo.template.git_hooks": "Crúcanna Git", @@ -1083,6 +1090,7 @@ "repo.migrate_options_lfs_endpoint.description.local": "Tacaítear le cosán freastalaí áitiúil freisin.", "repo.migrate_options_lfs_endpoint.placeholder": "Mura bhfágtar bán é, díorthófar an críochphointe ón URL clónála.", "repo.migrate_items": "Míreanna Imirce", + "repo.migrate_items_wiki": "Vicí", "repo.migrate_items_milestones": "Clocha míle", "repo.migrate_items_labels": "Lipéid", "repo.migrate_items_issues": "Saincheisteanna", @@ -1728,8 +1736,11 @@ "repo.issues.reference_link": "Tagairt: %s", "repo.compare.compare_base": "bonn", "repo.compare.compare_head": "déan comparáid", + "repo.compare.title": "Athruithe a chur i gcomparáid", + "repo.compare.description": "Roghnaigh dhá bhrainse nó clib chun a fheiceáil cad atá athraithe nó chun iarratas tarraingthe nua a thosú.", "repo.pulls.desc": "Cumasaigh iarratais tarraingthe agus athbhreithnithe cód.", "repo.pulls.new": "Iarratas Tarraingthe Nua", + "repo.pulls.new.description": "Pléigh agus athbhreithnigh na hathruithe sa chomparáid seo le daoine eile.", "repo.pulls.new.blocked_user": "Ní féidir iarratas tarraingthe a chruthú toisc go bhfuil úinéir an stórais bac ort.", "repo.pulls.new.must_collaborator": "Caithfidh tú a bheith ina chomhoibritheoir chun iarratas tarraingthe a chruthú.", "repo.pulls.new.already_existed": "Tá iarratas tarraingthe idir na brainsí seo ann cheana féin", @@ -1739,7 +1750,6 @@ "repo.pulls.allow_edits_from_maintainers": "Ceadaigh eagarthóirí ó chothabhálaí", "repo.pulls.allow_edits_from_maintainers_desc": "Is féidir le húsáideoirí a bhfuil rochtain scríofa acu ar an mbunbhrainse brú chuig an bhrainse", "repo.pulls.allow_edits_from_maintainers_err": "Theip ar nuashonrú", - "repo.pulls.compare_changes_desc": "Roghnaigh an brainse le cumasc isteach agus an brainse le tarraingt uaidh.", "repo.pulls.has_viewed_file": "Breathnaithe", "repo.pulls.has_changed_since_last_review": "Athraithe ó d'athbhreithniú deire", "repo.pulls.viewed_files_label": "Breathnaíodh ar %[1]d / %[2]d comhaid", @@ -2313,8 +2323,19 @@ "repo.settings.slack_domain": "Fearann", "repo.settings.slack_channel": "Cainéal", "repo.settings.add_web_hook_desc": "Comhtháthaigh %s isteach i do stóras.", + "repo.settings.web_hook_name_gitea": "Gitea", + "repo.settings.web_hook_name_gogs": "Gogs", + "repo.settings.web_hook_name_slack": "Slack", + "repo.settings.web_hook_name_discord": "Discord", + "repo.settings.web_hook_name_dingtalk": "DingTalk", "repo.settings.web_hook_name_telegram": "Teileagram", "repo.settings.web_hook_name_matrix": "Maitrís", + "repo.settings.web_hook_name_msteams": "Microsoft Teams", + "repo.settings.web_hook_name_feishu_or_larksuite": "Feishu / Lark Suite", + "repo.settings.web_hook_name_feishu": "Feishu", + "repo.settings.web_hook_name_larksuite": "Lark Suite", + "repo.settings.web_hook_name_wechatwork": "WeCom (Wechat Work)", + "repo.settings.web_hook_name_packagist": "Packagist", "repo.settings.packagist_username": "Ainm úsáideora Pacagist", "repo.settings.packagist_api_token": "Comhartha API", "repo.settings.packagist_package_url": "URL pacáiste Packagist", @@ -2460,6 +2481,7 @@ "repo.settings.unarchive.success": "Rinneadh an stóras a dhíchartlann go rathúil.", "repo.settings.unarchive.error": "Tharla earráid agus tú ag iarraidh an stóras a dhíchartlannú. Féach an logáil le haghaidh tuilleadh sonraí.", "repo.settings.update_avatar_success": "Nuashonraíodh avatar an stóras.", + "repo.settings.lfs": "LFS", "repo.settings.lfs_filelist": "Comhaid LFS a stóráiltear sa stóras seo", "repo.settings.lfs_no_lfs_files": "Níl aon chomhaid LFS stóráilte sa stóras seo", "repo.settings.lfs_findcommits": "Aimsigh gealltanais", @@ -2479,6 +2501,7 @@ "repo.settings.lfs_force_unlock": "Díghlasáil Fórsa", "repo.settings.lfs_pointers.found": "Fuarthas %d pointeoir(í) bloba — %d gaolmhar, %d neamhghaolmhar (%d ar iarraidh ón stóras)", "repo.settings.lfs_pointers.sha": "SHA Blob", + "repo.settings.lfs_pointers.oid": "OID", "repo.settings.lfs_pointers.inRepo": "I Stóras", "repo.settings.lfs_pointers.exists": "Ann sa siopa", "repo.settings.lfs_pointers.accessible": "Inrochtana don Úsáideoir", @@ -2844,6 +2867,7 @@ "admin.dashboard.task.finished": "Tasc: Tá %[1]s tosaithe ag %[2]s críochnaithe", "admin.dashboard.task.unknown": "Tasc anaithnid: %[1]s", "admin.dashboard.cron.started": "Cron tosaithe: %[1]s", + "admin.dashboard.cron.process": "Cron: %[1]s", "admin.dashboard.cron.cancelled": "Cron: %[1]s cealaithe: %[3]s", "admin.dashboard.cron.error": "Earráid i gCron: %s: %[3]s", "admin.dashboard.cron.finished": "Cron: %[1]s críochnaithe", @@ -2923,6 +2947,7 @@ "admin.users.reserved": "In áirithe", "admin.users.bot": "Bota", "admin.users.remote": "Iargúlta", + "admin.users.2fa": "2FA", "admin.users.repos": "Stórais", "admin.users.created": "Cruthaithe", "admin.users.last_login": "Sínigh Isteach Deiridh", @@ -3044,6 +3069,7 @@ "admin.auths.attribute_mail": "Tréith ríomhphoist", "admin.auths.attribute_ssh_public_key": "Tréith Eochair SSH Phoiblí", "admin.auths.attribute_avatar": "Tréith Avatar", + "admin.auths.ssh_keys_are_verified": "Meastar gur fíoraithe iad eochracha SSH in LDAP", "admin.auths.attributes_in_bind": "Faigh tréithe i gComhthéacs Bind DN", "admin.auths.allow_deactivate_all": "Lig do thoradh cuardaigh folamh gach úsáideoir a dhíghníomhachtú", "admin.auths.use_paged_search": "Úsáid Cuardach Leathanaigh", @@ -3177,6 +3203,7 @@ "admin.config.db_name": "Ainm", "admin.config.db_user": "Ainm úsáideora", "admin.config.db_schema": "Scéim", + "admin.config.db_ssl_mode": "SSL", "admin.config.db_path": "Cosán", "admin.config.service_config": "Cumraíocht Seirbhíse", "admin.config.register_email_confirm": "Deimhniú Ríomhphost a éileamh chun Clárú", @@ -3430,6 +3457,7 @@ "packages.assets": "Sócmhainní", "packages.versions": "Leaganacha", "packages.versions.view_all": "Féach ar gach", + "packages.dependency.id": "ID", "packages.dependency.version": "Leagan", "packages.search_in_external_registry": "Cuardaigh i %s", "packages.alpine.registry": "Socraigh an clárlann seo tríd an URL a chur i do chomhad /etc/apk/repositories:", @@ -3594,6 +3622,7 @@ "actions.runners.new": "Cruthaigh reathaí nua", "actions.runners.new_notice": "Conas reathaí a thosú", "actions.runners.status": "Stádas", + "actions.runners.id": "ID", "actions.runners.name": "Ainm", "actions.runners.owner_type": "Cineál", "actions.runners.description": "Cur síos", @@ -3693,6 +3722,7 @@ "projects.type-3.display_name": "Tionscadal Eagrúcháin", "projects.enter_fullscreen": "Lánscáileán", "projects.exit_fullscreen": "Scoir Lánscáileáin", + "git.filemode.changed_filemode": "%[1]s → %[2]s", "git.filemode.directory": "Eolaire", "git.filemode.normal_file": "Comhad gnáth", "git.filemode.executable_file": "Comhad infheidhmithe", From fbea2c68e8df11cfa94e8ead913b79946780ed30 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 12 Jan 2026 00:16:59 -0800 Subject: [PATCH 02/23] Fix delete attachment check (#36320) --- routers/api/v1/repo/release_attachment.go | 1 - routers/web/repo/attachment.go | 44 +++++++++++++++++++--- tests/integration/attachment_test.go | 46 ++++++++++++++++++++++- 3 files changed, 83 insertions(+), 8 deletions(-) diff --git a/routers/api/v1/repo/release_attachment.go b/routers/api/v1/repo/release_attachment.go index 43e97beb27..5f5423fafe 100644 --- a/routers/api/v1/repo/release_attachment.go +++ b/routers/api/v1/repo/release_attachment.go @@ -398,7 +398,6 @@ func DeleteReleaseAttachment(ctx *context.APIContext) { ctx.APIErrorNotFound() return } - // FIXME Should prove the existence of the given repo, but results in unnecessary database requests if err := repo_model.DeleteAttachment(ctx, attach, true); err != nil { ctx.APIErrorInternal(err) diff --git a/routers/web/repo/attachment.go b/routers/web/repo/attachment.go index 54200d8de8..bff91b51a7 100644 --- a/routers/web/repo/attachment.go +++ b/routers/web/repo/attachment.go @@ -4,11 +4,12 @@ package repo import ( - "fmt" "net/http" + issues_model "code.gitea.io/gitea/models/issues" access_model "code.gitea.io/gitea/models/perm/access" repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/modules/httpcache" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" @@ -40,7 +41,7 @@ func uploadAttachment(ctx *context.Context, repoID int64, allowedTypes string) { file, header, err := ctx.Req.FormFile("file") if err != nil { - ctx.HTTPError(http.StatusInternalServerError, fmt.Sprintf("FormFile: %v", err)) + ctx.ServerError("FormFile", err) return } defer file.Close() @@ -56,7 +57,7 @@ func uploadAttachment(ctx *context.Context, repoID int64, allowedTypes string) { ctx.HTTPError(http.StatusBadRequest, err.Error()) return } - ctx.HTTPError(http.StatusInternalServerError, fmt.Sprintf("NewAttachment: %v", err)) + ctx.ServerError("UploadAttachmentGeneralSizeLimit", err) return } @@ -74,13 +75,44 @@ func DeleteAttachment(ctx *context.Context) { ctx.HTTPError(http.StatusBadRequest, err.Error()) return } - if !ctx.IsSigned || (ctx.Doer.ID != attach.UploaderID) { + + if !ctx.IsSigned { ctx.HTTPError(http.StatusForbidden) return } + + if attach.RepoID != ctx.Repo.Repository.ID { + ctx.HTTPError(http.StatusBadRequest, "attachment does not belong to this repository") + return + } + + if ctx.Doer.ID != attach.UploaderID { + if attach.IssueID > 0 { + issue, err := issues_model.GetIssueByID(ctx, attach.IssueID) + if err != nil { + ctx.ServerError("GetIssueByID", err) + return + } + if !ctx.Repo.Permission.CanWriteIssuesOrPulls(issue.IsPull) { + ctx.HTTPError(http.StatusForbidden) + return + } + } else if attach.ReleaseID > 0 { + if !ctx.Repo.Permission.CanWrite(unit.TypeReleases) { + ctx.HTTPError(http.StatusForbidden) + return + } + } else { + if !ctx.Repo.Permission.IsAdmin() && !ctx.Repo.Permission.IsOwner() { + ctx.HTTPError(http.StatusForbidden) + return + } + } + } + err = repo_model.DeleteAttachment(ctx, attach, true) if err != nil { - ctx.HTTPError(http.StatusInternalServerError, fmt.Sprintf("DeleteAttachment: %v", err)) + ctx.ServerError("DeleteAttachment", err) return } ctx.JSON(http.StatusOK, map[string]string{ @@ -114,7 +146,7 @@ func ServeAttachment(ctx *context.Context, uuid string) { } else { // If we have the repository we check access perm, err := access_model.GetUserRepoPermission(ctx, repository, ctx.Doer) if err != nil { - ctx.HTTPError(http.StatusInternalServerError, "GetUserRepoPermission", err.Error()) + ctx.ServerError("GetUserRepoPermission", err) return } if !perm.CanRead(unitType) { diff --git a/tests/integration/attachment_test.go b/tests/integration/attachment_test.go index 0459371e3d..1e4e7c8e1c 100644 --- a/tests/integration/attachment_test.go +++ b/tests/integration/attachment_test.go @@ -34,6 +34,14 @@ func testGeneratePngBytes() []byte { } func testCreateIssueAttachment(t *testing.T, session *TestSession, repoURL, filename string, content []byte, expectedStatus int) string { + return testCreateAttachment(t, session, repoURL, "issues", filename, content, expectedStatus) +} + +func testCreateReleaseAttachment(t *testing.T, session *TestSession, repoURL, filename string, content []byte, expectedStatus int) string { + return testCreateAttachment(t, session, repoURL, "releases", filename, content, expectedStatus) +} + +func testCreateAttachment(t *testing.T, session *TestSession, repoURL, issueOrRelease, filename string, content []byte, expectedStatus int) string { body := &bytes.Buffer{} // Setup multi-part @@ -45,7 +53,7 @@ func testCreateIssueAttachment(t *testing.T, session *TestSession, repoURL, file err = writer.Close() assert.NoError(t, err) - req := NewRequestWithBody(t, "POST", repoURL+"/issues/attachments", body) + req := NewRequestWithBody(t, "POST", repoURL+"/"+issueOrRelease+"/attachments", body) req.Header.Add("Content-Type", writer.FormDataContentType()) resp := session.MakeRequest(t, req, expectedStatus) @@ -57,12 +65,23 @@ func testCreateIssueAttachment(t *testing.T, session *TestSession, repoURL, file return obj["uuid"] } +func testDeleteIssueAttachment(t *testing.T, session *TestSession, repoURL, uuid string, expectedStatus int) { + req := NewRequestWithValues(t, "POST", repoURL+"/issues/attachments/remove", map[string]string{"file": uuid}) + session.MakeRequest(t, req, expectedStatus) +} + +func testDeleteReleaseAttachment(t *testing.T, session *TestSession, repoURL, uuid string, expectedStatus int) { + req := NewRequestWithValues(t, "POST", repoURL+"/releases/attachments/remove", map[string]string{"file": uuid}) + session.MakeRequest(t, req, expectedStatus) +} + func TestAttachments(t *testing.T) { defer tests.PrepareTestEnv(t)() t.Run("CreateAnonymousAttachment", testCreateAnonymousAttachment) t.Run("CreateUser2IssueAttachment", testCreateUser2IssueAttachment) t.Run("UploadAttachmentDeleteTemp", testUploadAttachmentDeleteTemp) t.Run("GetAttachment", testGetAttachment) + t.Run("DeleteAttachmentPermissions", testDeleteAttachmentPermissions) } func testUploadAttachmentDeleteTemp(t *testing.T) { @@ -157,3 +176,28 @@ func testGetAttachment(t *testing.T) { }) } } + +func testDeleteAttachmentPermissions(t *testing.T) { + const repoURL = "user2/repo1" + + ownerSession := loginUser(t, "user2") + readonlySession := loginUser(t, "user5") + + issueFromOwner := testCreateIssueAttachment(t, ownerSession, repoURL, "owner-issue.png", testGeneratePngBytes(), http.StatusOK) + testDeleteIssueAttachment(t, readonlySession, repoURL, issueFromOwner, http.StatusForbidden) + + issueFromReader := testCreateIssueAttachment(t, readonlySession, repoURL, "reader-issue.png", testGeneratePngBytes(), http.StatusOK) + testDeleteIssueAttachment(t, ownerSession, repoURL, issueFromReader, http.StatusOK) + + testCreateReleaseAttachment(t, readonlySession, repoURL, "reader-release.png", testGeneratePngBytes(), http.StatusNotFound) + + crossRepoUUID := testCreateIssueAttachment(t, ownerSession, repoURL, "cross-repo.png", testGeneratePngBytes(), http.StatusOK) + testDeleteIssueAttachment(t, ownerSession, "user2/repo2", crossRepoUUID, http.StatusBadRequest) + testDeleteIssueAttachment(t, ownerSession, repoURL, crossRepoUUID, http.StatusOK) + + releaseUUID := testCreateReleaseAttachment(t, ownerSession, repoURL, "reader-release.png", testGeneratePngBytes(), http.StatusOK) + testDeleteReleaseAttachment(t, ownerSession, repoURL, releaseUUID, http.StatusOK) + + // test deleting release attachment from another repo + testDeleteReleaseAttachment(t, ownerSession, "user2/repo2", crossRepoUUID, http.StatusBadRequest) +} From 1d399bb1d18d77da519bfa70e0d1f1285cc9ae3f Mon Sep 17 00:00:00 2001 From: silverwind Date: Mon, 12 Jan 2026 13:29:35 +0100 Subject: [PATCH 03/23] Improve diff file headers (#36215) - reduce file name font size from 15px to 14px - fix labels and buttons being cut off when their size is constrained - change labels from monospace to sans-serif font - move diff stats to right and change them from sum of changes to +/- - change filemode to label and change text to match other labels --------- Co-authored-by: wxiaoguang --- modules/git/parse.go | 4 +- modules/git/tree_entry_mode.go | 36 ++++++++--- modules/git/tree_entry_test.go | 27 +++++++++ options/locale/locale_en-US.json | 10 +-- services/gitdiff/git_diff_tree.go | 14 +---- services/gitdiff/gitdiff.go | 77 ++++++++++++++---------- templates/repo/diff/box.tmpl | 69 +++++++++++---------- templates/repo/diff/stats.tmpl | 22 +++++-- templates/repo/pulls/tab_menu.tmpl | 7 +-- web_src/css/repo.css | 25 +++++--- web_src/css/themes/theme-gitea-dark.css | 2 + web_src/css/themes/theme-gitea-light.css | 2 + 12 files changed, 181 insertions(+), 114 deletions(-) diff --git a/modules/git/parse.go b/modules/git/parse.go index d4ff0ecb23..94020e690d 100644 --- a/modules/git/parse.go +++ b/modules/git/parse.go @@ -46,8 +46,8 @@ func parseLsTreeLine(line []byte) (*LsTreeEntry, error) { entry.Size = optional.Some(size) } - entry.EntryMode, err = ParseEntryMode(string(entryMode)) - if err != nil || entry.EntryMode == EntryModeNoEntry { + entry.EntryMode = ParseEntryMode(string(entryMode)) + if entry.EntryMode == EntryModeNoEntry { return nil, fmt.Errorf("invalid ls-tree output (invalid mode): %q, err: %w", line, err) } diff --git a/modules/git/tree_entry_mode.go b/modules/git/tree_entry_mode.go index f36c07bc2a..2ceba11374 100644 --- a/modules/git/tree_entry_mode.go +++ b/modules/git/tree_entry_mode.go @@ -4,7 +4,6 @@ package git import ( - "fmt" "strconv" ) @@ -55,21 +54,38 @@ func (e EntryMode) IsExecutable() bool { return e == EntryModeExec } -func ParseEntryMode(mode string) (EntryMode, error) { +func ParseEntryMode(mode string) EntryMode { switch mode { case "000000": - return EntryModeNoEntry, nil + return EntryModeNoEntry case "100644": - return EntryModeBlob, nil + return EntryModeBlob case "100755": - return EntryModeExec, nil + return EntryModeExec case "120000": - return EntryModeSymlink, nil + return EntryModeSymlink case "160000": - return EntryModeCommit, nil - case "040000", "040755": // git uses 040000 for tree object, but some users may get 040755 for unknown reasons - return EntryModeTree, nil + return EntryModeCommit + case "040000": + return EntryModeTree default: - return 0, fmt.Errorf("unparsable entry mode: %s", mode) + // git uses 040000 for tree object, but some users may get 040755 from non-standard git implementations + m, _ := strconv.ParseInt(mode, 8, 32) + modeInt := EntryMode(m) + switch modeInt & 0o770000 { + case 0o040000: + return EntryModeTree + case 0o160000: + return EntryModeCommit + case 0o120000: + return EntryModeSymlink + case 0o100000: + if modeInt&0o777 == 0o755 { + return EntryModeExec + } + return EntryModeBlob + default: + return EntryModeNoEntry + } } } diff --git a/modules/git/tree_entry_test.go b/modules/git/tree_entry_test.go index b28abfb545..8e3fb5ff99 100644 --- a/modules/git/tree_entry_test.go +++ b/modules/git/tree_entry_test.go @@ -27,3 +27,30 @@ func TestEntriesCustomSort(t *testing.T) { entries.CustomSort(strings.Compare) assert.Equal(t, expected, entries) } + +func TestParseEntryMode(t *testing.T) { + tests := []struct { + modeStr string + expectMod EntryMode + }{ + {"000000", EntryModeNoEntry}, + {"000755", EntryModeNoEntry}, + + {"100644", EntryModeBlob}, + {"100755", EntryModeExec}, + + {"120000", EntryModeSymlink}, + {"120755", EntryModeSymlink}, + {"160000", EntryModeCommit}, + {"160755", EntryModeCommit}, + + {"040000", EntryModeTree}, + {"040755", EntryModeTree}, + + {"777777", EntryModeNoEntry}, // invalid mode + } + for _, test := range tests { + mod := ParseEntryMode(test.modeStr) + assert.Equal(t, test.expectMod, mod, "modeStr: %s", test.modeStr) + } +} diff --git a/options/locale/locale_en-US.json b/options/locale/locale_en-US.json index 480aafe879..1dbb0975a3 100644 --- a/options/locale/locale_en-US.json +++ b/options/locale/locale_en-US.json @@ -2542,8 +2542,8 @@ "repo.diff.too_many_files": "Some files were not shown because too many files have changed in this diff", "repo.diff.show_more": "Show More", "repo.diff.load": "Load Diff", - "repo.diff.generated": "generated", - "repo.diff.vendored": "vendored", + "repo.diff.generated": "Generated", + "repo.diff.vendored": "Vendored", "repo.diff.comment.add_line_comment": "Add line comment", "repo.diff.comment.placeholder": "Leave a comment", "repo.diff.comment.add_single_comment": "Add single comment", @@ -3724,8 +3724,8 @@ "projects.exit_fullscreen": "Exit Fullscreen", "git.filemode.changed_filemode": "%[1]s → %[2]s", "git.filemode.directory": "Directory", - "git.filemode.normal_file": "Normal file", - "git.filemode.executable_file": "Executable file", - "git.filemode.symbolic_link": "Symbolic link", + "git.filemode.normal_file": "Regular", + "git.filemode.executable_file": "Executable", + "git.filemode.symbolic_link": "Symlink", "git.filemode.submodule": "Submodule" } diff --git a/services/gitdiff/git_diff_tree.go b/services/gitdiff/git_diff_tree.go index 2a3c7c9445..b4f26210be 100644 --- a/services/gitdiff/git_diff_tree.go +++ b/services/gitdiff/git_diff_tree.go @@ -166,16 +166,6 @@ func parseGitDiffTreeLine(line string) (*DiffTreeRecord, error) { return nil, fmt.Errorf("unparsable output for diff-tree --raw: `%s`, expected 5 space delimited values got %d)", line, len(fields)) } - baseMode, err := git.ParseEntryMode(fields[0]) - if err != nil { - return nil, err - } - - headMode, err := git.ParseEntryMode(fields[1]) - if err != nil { - return nil, err - } - baseBlobID := fields[2] headBlobID := fields[3] @@ -201,8 +191,8 @@ func parseGitDiffTreeLine(line string) (*DiffTreeRecord, error) { return &DiffTreeRecord{ Status: status, Score: score, - BaseMode: baseMode, - HeadMode: headMode, + BaseMode: git.ParseEntryMode(fields[0]), + HeadMode: git.ParseEntryMode(fields[1]), BaseBlobID: baseBlobID, HeadBlobID: headBlobID, BasePath: basePath, diff --git a/services/gitdiff/gitdiff.go b/services/gitdiff/gitdiff.go index be5c1dbece..f00c90d737 100644 --- a/services/gitdiff/gitdiff.go +++ b/services/gitdiff/gitdiff.go @@ -399,20 +399,20 @@ type DiffFile struct { isAmbiguous bool // basic fields (parsed from diff result) - Name string - NameHash string - OldName string - Addition int - Deletion int - Type DiffFileType - Mode string - OldMode string - IsCreated bool - IsDeleted bool - IsBin bool - IsLFSFile bool - IsRenamed bool - IsSubmodule bool + Name string + NameHash string + OldName string + Addition int + Deletion int + Type DiffFileType + EntryMode string + OldEntryMode string + IsCreated bool + IsDeleted bool + IsBin bool + IsLFSFile bool + IsRenamed bool + IsSubmodule bool // basic fields but for render purpose only Sections []*DiffSection IsIncomplete bool @@ -501,21 +501,36 @@ func (diffFile *DiffFile) ShouldBeHidden() bool { return diffFile.IsGenerated || diffFile.IsViewed } -func (diffFile *DiffFile) ModeTranslationKey(mode string) string { - switch mode { - case "040000": - return "git.filemode.directory" - case "100644": - return "git.filemode.normal_file" - case "100755": - return "git.filemode.executable_file" - case "120000": - return "git.filemode.symbolic_link" - case "160000": - return "git.filemode.submodule" - default: - return mode +func (diffFile *DiffFile) TranslateDiffEntryMode(locale translation.Locale) string { + entryModeTr := func(mode string) string { + entryMode := git.ParseEntryMode(mode) + switch { + case entryMode.IsDir(): + return locale.TrString("git.filemode.directory") + case entryMode.IsRegular(): + return locale.TrString("git.filemode.normal_file") + case entryMode.IsExecutable(): + return locale.TrString("git.filemode.executable_file") + case entryMode.IsLink(): + return locale.TrString("git.filemode.symbolic_link") + case entryMode.IsSubModule(): + return locale.TrString("git.filemode.submodule") + default: + return mode + } } + + if diffFile.EntryMode != "" && diffFile.OldEntryMode != "" { + oldMode := entryModeTr(diffFile.OldEntryMode) + newMode := entryModeTr(diffFile.EntryMode) + return locale.TrString("git.filemode.changed_filemode", oldMode, newMode) + } + if diffFile.EntryMode != "" { + if entryMode := git.ParseEntryMode(diffFile.EntryMode); !entryMode.IsRegular() { + return entryModeTr(diffFile.EntryMode) + } + } + return "" } type limitByteWriter struct { @@ -695,10 +710,10 @@ parsingLoop: strings.HasPrefix(line, "new mode "): if strings.HasPrefix(line, "old mode ") { - curFile.OldMode = prepareValue(line, "old mode ") + curFile.OldEntryMode = prepareValue(line, "old mode ") } if strings.HasPrefix(line, "new mode ") { - curFile.Mode = prepareValue(line, "new mode ") + curFile.EntryMode = prepareValue(line, "new mode ") } if strings.HasSuffix(line, " 160000\n") { curFile.IsSubmodule, curFile.SubmoduleDiffInfo = true, &SubmoduleDiffInfo{} @@ -733,7 +748,7 @@ parsingLoop: curFile.Type = DiffFileAdd curFile.IsCreated = true if strings.HasPrefix(line, "new file mode ") { - curFile.Mode = prepareValue(line, "new file mode ") + curFile.EntryMode = prepareValue(line, "new file mode ") } if strings.HasSuffix(line, " 160000\n") { curFile.IsSubmodule, curFile.SubmoduleDiffInfo = true, &SubmoduleDiffInfo{} diff --git a/templates/repo/diff/box.tmpl b/templates/repo/diff/box.tmpl index ff9bd2e792..2a3330d890 100644 --- a/templates/repo/diff/box.tmpl +++ b/templates/repo/diff/box.tmpl @@ -82,43 +82,42 @@ {{$isExpandable := or (gt $file.Addition 0) (gt $file.Deletion 0) $file.IsBin}} {{$isReviewFile := and $.IsSigned $.PageIsPullFiles (not $.Repository.IsArchived) $.IsShowingAllCommits}}
-

+
- -
- {{if $file.IsBin}} - - {{ctx.Locale.Tr "repo.diff.bin"}} - - {{else}} - {{template "repo/diff/stats" dict "file" . "root" $}} - {{end}} +
+ + {{$entryModeText := $file.TranslateDiffEntryMode ctx.Locale}} + + {{if $file.IsRenamed}}{{$file.OldName}} → {{end}}{{$file.Name}} +
- {{if $file.IsRenamed}}{{$file.OldName}} → {{end}}{{$file.Name}} - - {{if .IsLFSFile}}LFS{{end}} - {{if $file.IsGenerated}} - {{ctx.Locale.Tr "repo.diff.generated"}} - {{end}} - {{if $file.IsVendored}} - {{ctx.Locale.Tr "repo.diff.vendored"}} - {{end}} - {{if and $file.Mode $file.OldMode}} - {{$old := ctx.Locale.Tr ($file.ModeTranslationKey $file.OldMode)}} - {{$new := ctx.Locale.Tr ($file.ModeTranslationKey $file.Mode)}} - {{ctx.Locale.Tr "git.filemode.changed_filemode" $old $new}} - {{else if $file.Mode}} - {{ctx.Locale.Tr ($file.ModeTranslationKey $file.Mode)}} - {{end}} - + + {{if $file.IsLFSFile}} + LFS + {{end}} + {{if $file.IsGenerated}} + {{ctx.Locale.Tr "repo.diff.generated"}} + {{end}} + {{if $file.IsVendored}} + {{ctx.Locale.Tr "repo.diff.vendored"}} + {{end}} + {{if $entryModeText}} + {{$entryModeText}} + {{end}}
-
+
+ {{if $file.IsBin}} + {{ctx.Locale.Tr "repo.diff.bin"}} + {{else}} + {{template "repo/diff/stats" dict "Addition" .Addition "Deletion" .Deletion}} + {{end}} + {{if $showFileViewToggle}}
@@ -157,7 +156,7 @@
{{end}}
-

+
{{if or $file.IsIncomplete $file.IsBin}} diff --git a/templates/repo/diff/stats.tmpl b/templates/repo/diff/stats.tmpl index d0dff1bd09..31797cd970 100644 --- a/templates/repo/diff/stats.tmpl +++ b/templates/repo/diff/stats.tmpl @@ -1,5 +1,17 @@ -{{Eval .file.Addition "+" .file.Deletion}} - - {{/* if the denominator is zero, then the float result is "width: NaNpx", as before, it just works */}} -
-
+{{/* Template Attributes: +* Addition: Number of additions +* Deletion: Number of deletions +* Classes: Additional classes for the root element +*/}} +{{if or .Addition .Deletion}} +
+ + {{if .Addition}}+{{.Addition}}{{end}} + {{if .Deletion}}-{{.Deletion}}{{end}} + + + {{/* if the denominator is zero, then the float result is "width: NaNpx", as before, it just works */}} +
+
+
+{{end}} diff --git a/templates/repo/pulls/tab_menu.tmpl b/templates/repo/pulls/tab_menu.tmpl index a0ecdf96cd..70ce8271bd 100644 --- a/templates/repo/pulls/tab_menu.tmpl +++ b/templates/repo/pulls/tab_menu.tmpl @@ -16,12 +16,7 @@ {{if .NumFiles}}{{.NumFiles}}{{else}}-{{end}} {{if or .DiffShortStat.TotalAddition .DiffShortStat.TotalDeletion}} - - {{if .DiffShortStat.TotalAddition}}+{{.DiffShortStat.TotalAddition}}{{end}} {{if .DiffShortStat.TotalDeletion}}-{{.DiffShortStat.TotalDeletion}}{{end}} - -
-
-
+ {{template "repo/diff/stats" dict "Addition" .DiffShortStat.TotalAddition "Deletion" .DiffShortStat.TotalDeletion "Classes" "tw-ml-auto tw-pl-3 tw-font-semibold"}} {{end}}
diff --git a/web_src/css/repo.css b/web_src/css/repo.css index 0bf37ca083..4de1f3ccdf 100644 --- a/web_src/css/repo.css +++ b/web_src/css/repo.css @@ -1293,8 +1293,7 @@ td .commit-summary { filter: drop-shadow(-4px 0 0 var(--color-primary-alpha-30)) !important; } -.code-comment:target, -.diff-file-box:target { +.code-comment:target { border-color: var(--color-primary) !important; border-radius: var(--border-radius) !important; box-shadow: 0 0 0 3px var(--color-primary-alpha-30) !important; @@ -1681,18 +1680,27 @@ tbody.commit-list { margin-top: 1em; } +.diff-file-box:target { + border-color: var(--color-primary) !important; + border-radius: var(--border-radius) !important; + box-shadow: 0 0 0 3px var(--color-primary-alpha-30) !important; +} + .diff-file-header { padding: 5px 8px !important; - box-shadow: 0 -1px 0 1px var(--color-body); /* prevent borders being visible behind top corners when sticky and scrolled */ - font-weight: var(--font-weight-normal); display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; + gap: 0.5em; + + /* prevent borders from being visible behind top corners when sticky and scrolled, + this "shadow" is used to use body's color to cover the scrolled-up left and right borders at corners */ + box-shadow: 0 -1px 0 1px var(--color-body); } -.diff-file-header .file { - min-width: 0; +.diff-file-box:target .diff-file-header { + box-shadow: unset; /* when targeted, still use the parent's box-shadow, remove the patched above */ } .diff-file-header .file-link { @@ -1715,6 +1723,7 @@ tbody.commit-list { .diff-file-header { flex-direction: column; align-items: stretch; + gap: 0; } } @@ -1743,13 +1752,13 @@ tbody.commit-list { .diff-stats-bar { display: inline-block; - background-color: var(--color-red); + background-color: var(--color-diff-prompt-del-fg); /* the background is used as "text foreground color" */ height: 12px; width: 44px; } .diff-stats-bar .diff-stats-add-bar { - background-color: var(--color-green); + background-color: var(--color-diff-prompt-add-fg); height: 100%; } diff --git a/web_src/css/themes/theme-gitea-dark.css b/web_src/css/themes/theme-gitea-dark.css index f89752dc79..7998f54990 100644 --- a/web_src/css/themes/theme-gitea-dark.css +++ b/web_src/css/themes/theme-gitea-dark.css @@ -158,6 +158,8 @@ gitea-theme-meta-info { --color-diff-removed-row-bg: #301e1e; --color-diff-removed-row-border: #634343; --color-diff-removed-word-bg: #6f3333; + --color-diff-prompt-add-fg: #87ab63; + --color-diff-prompt-del-fg: #cc4848; --color-diff-inactive: #22282d; --color-error-border: #a04141; --color-error-bg: #522; diff --git a/web_src/css/themes/theme-gitea-light.css b/web_src/css/themes/theme-gitea-light.css index 1261ef8be0..d169492041 100644 --- a/web_src/css/themes/theme-gitea-light.css +++ b/web_src/css/themes/theme-gitea-light.css @@ -158,6 +158,8 @@ gitea-theme-meta-info { --color-diff-removed-row-bg: #ffeef0; --color-diff-removed-row-border: #f1c0c0; --color-diff-removed-word-bg: #fdb8c0; + --color-diff-prompt-add-fg: #21ba45; + --color-diff-prompt-del-fg: #db2828; --color-diff-inactive: #f0f2f4; --color-error-border: #e0b4b4; --color-error-bg: #fff6f6; From b1b58977952d103d84885a137e88786fc0fc1885 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Jan 2026 17:47:41 +0000 Subject: [PATCH 04/23] Bump appleboy/git-push-action from 1.0.0 to 1.2.0 (#36306) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [appleboy/git-push-action](https://github.com/appleboy/git-push-action) from 1.0.0 to 1.2.0.
Release notes

Sourced from appleboy/git-push-action's releases.

v1.2.0

Changelog

Features

  • 2722561d2c158e67f0e4b908bda83937e53bbdd4: feat: add options for insecure SSL and SSH version selection (@​appleboy)

Others

  • 2c87d5bacd46972f72523394e67af39825081037: style: standardize YAML quoting and update input descriptions (@​appleboy)

Bug fixes

  • 66a962f89a56024b2a36de61fe65ba6b9994be15: fix: rename drone-git-push env vars and update default version (@​appleboy)

Enhancements

  • e37f17de403a8b0b59184d852be6b7a7e017d376: chore: mark all directories as safe in global git configuration (@​appleboy)

Refactor

  • 7bdda76242d8f6b40576a039a2d2233c43b7661e: refactor: refactor GitHub Action to use Bash instead of Docker (@​appleboy)
  • 4873de66e7bed19267cc8cd66959005c42d41cc7: refactor: simplify stdout capturing by removing legacy logic (@​appleboy)

Build process updates

  • d1c361f2d2e128593b5dfeb3c2d9a5c6a1af7128: ci: run Docker actions as nobody and inject GITHUB_WORKSPACE (@​appleboy)
  • fdf995de1284df95f38a3d99275eb38537eb05a4: ci: simplify Docker action environment variable configuration (@​appleboy)
  • 8e938ac7df8937d595e4c4fcf345139339a34819: ci: update GITHUB_WORKSPACE to use /github/home path (@​appleboy)

Documentation updates

  • 3b2c8661652360dbf1afe1b319a49dbb739c39f1: docs: migrate to composite GitHub Action and standardize env vars (@​appleboy)

v1.1.0

Changelog

Features

  • 28a54bbef16233cbea6f9fe39f318a4f055cd749: feat: add mirror input support to GitHub Action configuration (@​appleboy)

Bug fixes

  • a63ac675f748ad297929b6d9688f94939fbe3dea: fix: fix spelling of 'force' option in git push actions (@​appleboy)

Enhancements

  • ee39884535468c8b6f101c0980aec38a61bc6c8b: chore(readme): refactor codebase and update dependencies (@​appleboy)
  • 94fb0c0d87ba52affdcb2daf8505a0e7f086f205: chore: bump drone-git-push base image to version 1.2.0 (@​appleboy)
  • a939634b19fa88f0d4c853f4b604a4df5549911d: chore: pin Drone Git Push image to a specific version (@​appleboy)

Build process updates

  • 0a16d15bfdca306c84a299db735f248e9d408bb3: ci: improve CI workflow for semantic version releases (@​appleboy)
  • 1807bf9a1b801f99799e4e2a64ca1c6b11301fc3: ci: automate maintenance and enhance repository security (@​appleboy)
  • f39abba130277d16a141588c1b4c194a8f0b4636: build: run container as non-root user for enhanced security (@​appleboy)
  • ed86ac596a332db5353062d7cbdf24d61554f5f1: ci: update CI workflows to trigger on main branch (@​appleboy)
  • cd8de7f6c86b1390f0108011580b6c9845b9f5df: build: eliminate "nobody" user references from Dockerfile (@​appleboy)
  • 7465fee0c6ac1466048408a99c52598be9abf00f: ci: update CI workflow to use newer actions/checkout version (@​appleboy)
  • b9d4e07212dd711b7e57352e5b6172038ab20f6e: build: simplify Docker build by removing entrypoint.sh chmod step (@​appleboy)
  • 14d3003b72ea485bf8707bfbef4926eca78cc341: build: upgrade CI pipeline to latest drone-git-push base image (@​appleboy)

Documentation updates

  • 378ab1be62cfbae4111d3bbbec417d5b2e97134d: docs: clarify and standardize input and action descriptions (@​appleboy)
  • 4c679526c0d1910c6e058a82fdde978d5cd8c0c2: docs: revamp documentation with expanded features and usage examples (@​appleboy)
  • 61f29e5108e85fa252a0556c08ec87f0c425f1b2: docs: document GitHub Action integration and Claude Code guidelines (@​appleboy)
  • a7ef8abff3f71345b67dc056ac3d7b2d006efa42: docs: add Trivy security scan badge to documentation (@​appleboy)
Commits
  • 3b2c866 docs: migrate to composite GitHub Action and standardize env vars
  • 4873de6 refactor: simplify stdout capturing by removing legacy logic
  • 2c87d5b style: standardize YAML quoting and update input descriptions
  • 2722561 feat: add options for insecure SSL and SSH version selection
  • 66a962f fix: rename drone-git-push env vars and update default version
  • 7bdda76 refactor: refactor GitHub Action to use Bash instead of Docker
  • 8e938ac ci: update GITHUB_WORKSPACE to use /github/home path
  • e37f17d chore: mark all directories as safe in global git configuration
  • fdf995d ci: simplify Docker action environment variable configuration
  • d1c361f ci: run Docker actions as nobody and inject GITHUB_WORKSPACE
  • Additional commits viewable in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=appleboy/git-push-action&package-manager=github_actions&previous-version=1.0.0&new-version=1.2.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/cron-licenses.yml | 2 +- .github/workflows/cron-translations.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/cron-licenses.yml b/.github/workflows/cron-licenses.yml index c5dd70a1f8..ee1c3e0c75 100644 --- a/.github/workflows/cron-licenses.yml +++ b/.github/workflows/cron-licenses.yml @@ -20,7 +20,7 @@ jobs: - run: make generate-gitignore timeout-minutes: 40 - name: push translations to repo - uses: appleboy/git-push-action@v1.0.0 + uses: appleboy/git-push-action@v1.2.0 with: author_email: "teabot@gitea.io" author_name: GiteaBot diff --git a/.github/workflows/cron-translations.yml b/.github/workflows/cron-translations.yml index d87ba8b20d..56a30fb5ba 100644 --- a/.github/workflows/cron-translations.yml +++ b/.github/workflows/cron-translations.yml @@ -29,7 +29,7 @@ jobs: - name: update locales run: ./build/update-locales.sh - name: push translations to repo - uses: appleboy/git-push-action@v1.0.0 + uses: appleboy/git-push-action@v1.2.0 with: author_email: "teabot@gitea.io" author_name: GiteaBot From c8b5a1ddf70d4bf02a7607e293b4c59eab97f921 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 12 Jan 2026 13:47:06 -0800 Subject: [PATCH 05/23] Fix cancel auto merge bug (#36341) --- routers/api/v1/repo/pull.go | 2 +- routers/web/repo/pull.go | 22 ++++++++++++++++++++++ tests/integration/git_general_test.go | 27 +++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 1 deletion(-) diff --git a/routers/api/v1/repo/pull.go b/routers/api/v1/repo/pull.go index b5bacd9669..f33867f4ed 100644 --- a/routers/api/v1/repo/pull.go +++ b/routers/api/v1/repo/pull.go @@ -1322,7 +1322,7 @@ func CancelScheduledAutoMerge(ctx *context.APIContext) { } if ctx.Doer.ID != autoMerge.DoerID { - allowed, err := access_model.IsUserRepoAdmin(ctx, ctx.Repo.Repository, ctx.Doer) + allowed, err := pull_service.IsUserAllowedToMerge(ctx, pull, ctx.Repo.Permission, ctx.Doer) if err != nil { ctx.APIErrorInternal(err) return diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go index ecc1bb0644..60f0ee6db8 100644 --- a/routers/web/repo/pull.go +++ b/routers/web/repo/pull.go @@ -1265,6 +1265,28 @@ func CancelAutoMergePullRequest(ctx *context.Context) { return } + exist, autoMerge, err := pull_model.GetScheduledMergeByPullID(ctx, issue.PullRequest.ID) + if err != nil { + ctx.ServerError("GetScheduledMergeByPullID", err) + return + } + if !exist { + ctx.NotFound(nil) + return + } + + if ctx.Doer.ID != autoMerge.DoerID { + allowed, err := pull_service.IsUserAllowedToMerge(ctx, issue.PullRequest, ctx.Repo.Permission, ctx.Doer) + if err != nil { + ctx.ServerError("IsUserAllowedToMerge", err) + return + } + if !allowed { + ctx.HTTPError(http.StatusForbidden, "user has no permission to cancel the scheduled auto merge") + return + } + } + if err := automerge.RemoveScheduledAutoMerge(ctx, ctx.Doer, issue.PullRequest); err != nil { if db.IsErrNotExist(err) { ctx.Flash.Error(ctx.Tr("repo.pulls.auto_merge_not_scheduled")) diff --git a/tests/integration/git_general_test.go b/tests/integration/git_general_test.go index b9fa200dd0..f789ae3747 100644 --- a/tests/integration/git_general_test.go +++ b/tests/integration/git_general_test.go @@ -701,6 +701,11 @@ func doAutoPRMerge(baseCtx *APITestContext, dstPath string) func(t *testing.T) { defer tests.PrintCurrentTest(t)() ctx := NewAPITestContext(t, baseCtx.Username, baseCtx.Reponame, auth_model.AccessTokenScopeWriteRepository) + collaboratorCtx := NewAPITestContext(t, "user5", baseCtx.Reponame, auth_model.AccessTokenScopeWriteRepository) + readOnlyCtx := NewAPITestContext(t, "user4", baseCtx.Reponame, auth_model.AccessTokenScopeWriteRepository) + + t.Run("AddAutoMergeCollaborator", doAPIAddCollaborator(*baseCtx, collaboratorCtx.Username, perm.AccessModeWrite)) + t.Run("AddReadOnlyAutoMergeCollaborator", doAPIAddCollaborator(*baseCtx, readOnlyCtx.Username, perm.AccessModeRead)) // automerge will merge immediately if the PR is mergeable and there is no "status check" because no status check also means "all checks passed" // so we must set up a status check to test the auto merge feature @@ -747,10 +752,32 @@ func doAutoPRMerge(baseCtx *APITestContext, dstPath string) func(t *testing.T) { ctx.ExpectedCode = http.StatusConflict t.Run("AutoMergePRTwice", doAPIAutoMergePullRequest(ctx, baseCtx.Username, baseCtx.Reponame, pr.Index)) + // Read-only collaborator still cannot cancel + readOnlyCtx.ExpectedCode = http.StatusForbidden + t.Run("CancelAutoMergePRByReadOnlyCollaboratorForbidden", doAPICancelAutoMergePullRequest(readOnlyCtx, baseCtx.Username, baseCtx.Reponame, pr.Index)) + readOnlyCtx.ExpectedCode = 0 + + // Collaborators with merge permissions can cancel a schedule made by someone else + collaboratorCtx.ExpectedCode = http.StatusNoContent + t.Run("CancelAutoMergePRByCollaborator", doAPICancelAutoMergePullRequest(collaboratorCtx, baseCtx.Username, baseCtx.Reponame, pr.Index)) + collaboratorCtx.ExpectedCode = 0 + + // Re-add auto merge request so the repo owner can cancel it as well + ctx.ExpectedCode = http.StatusCreated + t.Run("AutoMergePRAfterCollaboratorCancel", doAPIAutoMergePullRequest(ctx, baseCtx.Username, baseCtx.Reponame, pr.Index)) + // Cancel auto merge request ctx.ExpectedCode = http.StatusNoContent t.Run("CancelAutoMergePR", doAPICancelAutoMergePullRequest(ctx, baseCtx.Username, baseCtx.Reponame, pr.Index)) + // Collaborator can schedule but admins should still be able to cancel their schedule + collaboratorCtx.ExpectedCode = http.StatusCreated + t.Run("AutoMergePRByCollaborator", doAPIAutoMergePullRequest(collaboratorCtx, baseCtx.Username, baseCtx.Reponame, pr.Index)) + collaboratorCtx.ExpectedCode = 0 + + ctx.ExpectedCode = http.StatusNoContent + t.Run("CancelAutoMergePRByAdmin", doAPICancelAutoMergePullRequest(ctx, baseCtx.Username, baseCtx.Reponame, pr.Index)) + // Add auto merge request ctx.ExpectedCode = http.StatusCreated t.Run("AutoMergePR", doAPIAutoMergePullRequest(ctx, baseCtx.Username, baseCtx.Reponame, pr.Index)) From 7a23e247e6e5dbf8b80d8203cbf0b948207ebd67 Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Tue, 13 Jan 2026 06:17:42 +0800 Subject: [PATCH 06/23] Fix notifications pagination query parameters (#36351) Fix #36350 --- routers/web/user/notification.go | 3 +++ services/context/pagination.go | 10 +++++++++ services/context/pagination_test.go | 35 +++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+) create mode 100644 services/context/pagination_test.go diff --git a/routers/web/user/notification.go b/routers/web/user/notification.go index aaf9d435c0..cf61b0a2f2 100644 --- a/routers/web/user/notification.go +++ b/routers/web/user/notification.go @@ -15,6 +15,7 @@ import ( repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/modules/base" + "code.gitea.io/gitea/modules/container" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/setting" @@ -128,7 +129,9 @@ func prepareUserNotificationsData(ctx *context.Context) { ctx.Data["Notifications"] = notifications ctx.Data["Link"] = setting.AppSubURL + "/notifications" ctx.Data["SequenceNumber"] = ctx.FormString("sequence-number") + pager.AddParamFromRequest(ctx.Req) + pager.RemoveParam(container.SetOf("div-only", "sequence-number")) ctx.Data["Page"] = pager } diff --git a/services/context/pagination.go b/services/context/pagination.go index 2a9805db05..21efab8b12 100644 --- a/services/context/pagination.go +++ b/services/context/pagination.go @@ -8,8 +8,10 @@ import ( "html/template" "net/http" "net/url" + "slices" "strings" + "code.gitea.io/gitea/modules/container" "code.gitea.io/gitea/modules/paginator" ) @@ -49,6 +51,14 @@ func (p *Pagination) AddParamFromRequest(req *http.Request) { p.AddParamFromQuery(req.URL.Query()) } +func (p *Pagination) RemoveParam(keys container.Set[string]) { + p.urlParams = slices.DeleteFunc(p.urlParams, func(s string) bool { + k, _, _ := strings.Cut(s, "=") + k, _ = url.QueryUnescape(k) + return keys.Contains(k) + }) +} + // GetParams returns the configured URL params func (p *Pagination) GetParams() template.URL { return template.URL(strings.Join(p.urlParams, "&")) diff --git a/services/context/pagination_test.go b/services/context/pagination_test.go new file mode 100644 index 0000000000..78359caa09 --- /dev/null +++ b/services/context/pagination_test.go @@ -0,0 +1,35 @@ +// Copyright 2026 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package context + +import ( + "net/url" + "testing" + + "code.gitea.io/gitea/modules/container" + + "github.com/stretchr/testify/assert" +) + +func TestPagination(t *testing.T) { + p := NewPagination(1, 1, 1, 1) + params := url.Values{} + params.Add("k1", "11") + params.Add("k1", "12") + params.Add("k", "a") + params.Add("k", "b") + params.Add("k2", "21") + params.Add("k2", "22") + params.Add("foo", "bar") + + p.AddParamFromQuery(params) + v, _ := url.ParseQuery(string(p.GetParams())) + assert.Equal(t, params, v) + + p.RemoveParam(container.SetOf("k", "foo")) + params.Del("k") + params.Del("foo") + v, _ = url.ParseQuery(string(p.GetParams())) + assert.Equal(t, params, v) +} From 040fc9304673c0ffa42d910cb26ce141c85ccc22 Mon Sep 17 00:00:00 2001 From: TheFox0x7 Date: Mon, 12 Jan 2026 23:52:44 +0100 Subject: [PATCH 07/23] fill missing `has_code` in repository api (#36338) fixes: https://github.com/go-gitea/gitea/issues/36332 --------- Co-authored-by: Lunny Xiao Co-authored-by: Giteabot --- services/convert/repository.go | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/services/convert/repository.go b/services/convert/repository.go index a364591bb8..4e0a404bdc 100644 --- a/services/convert/repository.go +++ b/services/convert/repository.go @@ -127,20 +127,10 @@ func innerToRepo(ctx context.Context, repo *repo_model.Repository, permissionInR projectsMode = config.ProjectsMode } - hasReleases := false - if _, err := repo.GetUnit(ctx, unit_model.TypeReleases); err == nil { - hasReleases = true - } - - hasPackages := false - if _, err := repo.GetUnit(ctx, unit_model.TypePackages); err == nil { - hasPackages = true - } - - hasActions := false - if _, err := repo.GetUnit(ctx, unit_model.TypeActions); err == nil { - hasActions = true - } + hasCode := repo.UnitEnabled(ctx, unit_model.TypeCode) + hasReleases := repo.UnitEnabled(ctx, unit_model.TypeReleases) + hasPackages := repo.UnitEnabled(ctx, unit_model.TypePackages) + hasActions := repo.UnitEnabled(ctx, unit_model.TypeActions) if err := repo.LoadOwner(ctx); err != nil { return nil @@ -221,6 +211,7 @@ func innerToRepo(ctx context.Context, repo *repo_model.Repository, permissionInR Updated: repo.UpdatedUnix.AsTime(), ArchivedAt: repo.ArchivedUnix.AsTime(), Permissions: permission, + HasCode: hasCode, HasIssues: hasIssues, ExternalTracker: externalTracker, InternalTracker: internalTracker, From 2859b0602aa05b0fa81b3a41a07f90639849728b Mon Sep 17 00:00:00 2001 From: silverwind Date: Tue, 13 Jan 2026 05:06:58 +0100 Subject: [PATCH 08/23] Update JS deps (#36354) - Update all JS deps - Regenerate SVGs - Enable new lint rules and fix issues - Tested affected dependencies --- eslint.config.ts | 3 +- options/fileicon/material-icon-rules.json | 170 ++ options/fileicon/material-icon-svgs.json | 9 +- package.json | 38 +- pnpm-lock.yaml | 1489 +++++++---------- web_src/js/features/admin/common.ts | 2 +- .../js/features/comp/ComboMarkdownEditor.ts | 2 +- 7 files changed, 848 insertions(+), 865 deletions(-) diff --git a/eslint.config.ts b/eslint.config.ts index 253a7f4555..38797a4d1a 100644 --- a/eslint.config.ts +++ b/eslint.config.ts @@ -233,7 +233,7 @@ export default defineConfig([ '@typescript-eslint/no-unused-vars': [2, {vars: 'all', args: 'all', caughtErrors: 'all', ignoreRestSiblings: false, argsIgnorePattern: '^_', varsIgnorePattern: '^_', caughtErrorsIgnorePattern: '^_', destructuredArrayIgnorePattern: '^_'}], '@typescript-eslint/no-use-before-define': [2, {functions: false, classes: true, variables: true, allowNamedExports: true, typedefs: false, enums: false, ignoreTypeReferences: true}], '@typescript-eslint/no-useless-constructor': [0], - '@typescript-eslint/no-useless-default-assignment': [0], // https://github.com/typescript-eslint/typescript-eslint/issues/11847 + '@typescript-eslint/no-useless-default-assignment': [2], '@typescript-eslint/no-useless-empty-export': [0], '@typescript-eslint/no-wrapper-object-types': [2], '@typescript-eslint/non-nullable-type-assertion-style': [0], @@ -264,6 +264,7 @@ export default defineConfig([ '@typescript-eslint/restrict-template-expressions': [0], '@typescript-eslint/return-await': [0], '@typescript-eslint/strict-boolean-expressions': [0], + '@typescript-eslint/strict-void-return': [0], '@typescript-eslint/switch-exhaustiveness-check': [0], '@typescript-eslint/triple-slash-reference': [2], '@typescript-eslint/typedef': [0], diff --git a/options/fileicon/material-icon-rules.json b/options/fileicon/material-icon-rules.json index 6b17e5be67..c893cfac4e 100644 --- a/options/fileicon/material-icon-rules.json +++ b/options/fileicon/material-icon-rules.json @@ -460,6 +460,22 @@ ".blog": "folder-docs", "_blog": "folder-docs", "__blog__": "folder-docs", + "knowledge": "folder-docs", + ".knowledge": "folder-docs", + "_knowledge": "folder-docs", + "__knowledge__": "folder-docs", + "diary": "folder-docs", + ".diary": "folder-docs", + "_diary": "folder-docs", + "__diary__": "folder-docs", + "note": "folder-docs", + ".note": "folder-docs", + "_note": "folder-docs", + "__note__": "folder-docs", + "notes": "folder-docs", + ".notes": "folder-docs", + "_notes": "folder-docs", + "__notes__": "folder-docs", "github/workflows": "folder-gh-workflows", ".github/workflows": "folder-gh-workflows", "_github/workflows": "folder-gh-workflows", @@ -916,6 +932,14 @@ ".sql": "folder-database", "_sql": "folder-database", "__sql__": "folder-database", + "migrations": "folder-migrations", + ".migrations": "folder-migrations", + "_migrations": "folder-migrations", + "__migrations__": "folder-migrations", + "migration": "folder-migrations", + ".migration": "folder-migrations", + "_migration": "folder-migrations", + "__migration__": "folder-migrations", "log": "folder-log", ".log": "folder-log", "_log": "folder-log", @@ -1008,6 +1032,14 @@ ".recordings": "folder-audio", "_recordings": "folder-audio", "__recordings__": "folder-audio", + "playlist": "folder-audio", + ".playlist": "folder-audio", + "_playlist": "folder-audio", + "__playlist__": "folder-audio", + "playlists": "folder-audio", + ".playlists": "folder-audio", + "_playlists": "folder-audio", + "__playlists__": "folder-audio", "vid": "folder-video", ".vid": "folder-video", "_vid": "folder-video", @@ -1544,6 +1576,22 @@ ".backends": "folder-server", "_backends": "folder-server", "__backends__": "folder-server", + "inventory": "folder-server", + ".inventory": "folder-server", + "_inventory": "folder-server", + "__inventory__": "folder-server", + "inventories": "folder-server", + ".inventories": "folder-server", + "_inventories": "folder-server", + "__inventories__": "folder-server", + "infrastructure": "folder-server", + ".infrastructure": "folder-server", + "_infrastructure": "folder-server", + "__infrastructure__": "folder-server", + "infra": "folder-server", + ".infra": "folder-server", + "_infra": "folder-server", + "__infra__": "folder-server", "client": "folder-client", ".client": "folder-client", "_client": "folder-client", @@ -1992,6 +2040,14 @@ ".calculations": "folder-functions", "_calculations": "folder-functions", "__calculations__": "folder-functions", + "composable": "folder-functions", + ".composable": "folder-functions", + "_composable": "folder-functions", + "__composable__": "folder-functions", + "composables": "folder-functions", + ".composables": "folder-functions", + "_composables": "folder-functions", + "__composables__": "folder-functions", "generator": "folder-generator", ".generator": "folder-generator", "_generator": "folder-generator", @@ -2936,6 +2992,14 @@ ".projects": "folder-project", "_projects": "folder-project", "__projects__": "folder-project", + "proj": "folder-project", + ".proj": "folder-project", + "_proj": "folder-project", + "__proj__": "folder-project", + "projs": "folder-project", + ".projs": "folder-project", + "_projs": "folder-project", + "__projs__": "folder-project", "prompt": "folder-prompts", ".prompt": "folder-prompts", "_prompt": "folder-prompts", @@ -3447,6 +3511,14 @@ ".in": "folder-input", "_in": "folder-input", "__in__": "folder-input", + "salt": "folder-salt", + ".salt": "folder-salt", + "_salt": "folder-salt", + "__salt__": "folder-salt", + "saltstack": "folder-salt", + ".saltstack": "folder-salt", + "_saltstack": "folder-salt", + "__saltstack__": "folder-salt", "simulations": "folder-simulations", ".simulations": "folder-simulations", "_simulations": "folder-simulations", @@ -3961,6 +4033,22 @@ ".blog": "folder-docs-open", "_blog": "folder-docs-open", "__blog__": "folder-docs-open", + "knowledge": "folder-docs-open", + ".knowledge": "folder-docs-open", + "_knowledge": "folder-docs-open", + "__knowledge__": "folder-docs-open", + "diary": "folder-docs-open", + ".diary": "folder-docs-open", + "_diary": "folder-docs-open", + "__diary__": "folder-docs-open", + "note": "folder-docs-open", + ".note": "folder-docs-open", + "_note": "folder-docs-open", + "__note__": "folder-docs-open", + "notes": "folder-docs-open", + ".notes": "folder-docs-open", + "_notes": "folder-docs-open", + "__notes__": "folder-docs-open", "github/workflows": "folder-gh-workflows-open", ".github/workflows": "folder-gh-workflows-open", "_github/workflows": "folder-gh-workflows-open", @@ -4417,6 +4505,14 @@ ".sql": "folder-database-open", "_sql": "folder-database-open", "__sql__": "folder-database-open", + "migrations": "folder-migrations-open", + ".migrations": "folder-migrations-open", + "_migrations": "folder-migrations-open", + "__migrations__": "folder-migrations-open", + "migration": "folder-migrations-open", + ".migration": "folder-migrations-open", + "_migration": "folder-migrations-open", + "__migration__": "folder-migrations-open", "log": "folder-log-open", ".log": "folder-log-open", "_log": "folder-log-open", @@ -4509,6 +4605,14 @@ ".recordings": "folder-audio-open", "_recordings": "folder-audio-open", "__recordings__": "folder-audio-open", + "playlist": "folder-audio-open", + ".playlist": "folder-audio-open", + "_playlist": "folder-audio-open", + "__playlist__": "folder-audio-open", + "playlists": "folder-audio-open", + ".playlists": "folder-audio-open", + "_playlists": "folder-audio-open", + "__playlists__": "folder-audio-open", "vid": "folder-video-open", ".vid": "folder-video-open", "_vid": "folder-video-open", @@ -5045,6 +5149,22 @@ ".backends": "folder-server-open", "_backends": "folder-server-open", "__backends__": "folder-server-open", + "inventory": "folder-server-open", + ".inventory": "folder-server-open", + "_inventory": "folder-server-open", + "__inventory__": "folder-server-open", + "inventories": "folder-server-open", + ".inventories": "folder-server-open", + "_inventories": "folder-server-open", + "__inventories__": "folder-server-open", + "infrastructure": "folder-server-open", + ".infrastructure": "folder-server-open", + "_infrastructure": "folder-server-open", + "__infrastructure__": "folder-server-open", + "infra": "folder-server-open", + ".infra": "folder-server-open", + "_infra": "folder-server-open", + "__infra__": "folder-server-open", "client": "folder-client-open", ".client": "folder-client-open", "_client": "folder-client-open", @@ -5493,6 +5613,14 @@ ".calculations": "folder-functions-open", "_calculations": "folder-functions-open", "__calculations__": "folder-functions-open", + "composable": "folder-functions-open", + ".composable": "folder-functions-open", + "_composable": "folder-functions-open", + "__composable__": "folder-functions-open", + "composables": "folder-functions-open", + ".composables": "folder-functions-open", + "_composables": "folder-functions-open", + "__composables__": "folder-functions-open", "generator": "folder-generator-open", ".generator": "folder-generator-open", "_generator": "folder-generator-open", @@ -6437,6 +6565,14 @@ ".projects": "folder-project-open", "_projects": "folder-project-open", "__projects__": "folder-project-open", + "proj": "folder-project-open", + ".proj": "folder-project-open", + "_proj": "folder-project-open", + "__proj__": "folder-project-open", + "projs": "folder-project-open", + ".projs": "folder-project-open", + "_projs": "folder-project-open", + "__projs__": "folder-project-open", "prompt": "folder-prompts-open", ".prompt": "folder-prompts-open", "_prompt": "folder-prompts-open", @@ -6948,6 +7084,14 @@ ".in": "folder-input-open", "_in": "folder-input-open", "__in__": "folder-input-open", + "salt": "folder-salt-open", + ".salt": "folder-salt-open", + "_salt": "folder-salt-open", + "__salt__": "folder-salt-open", + "saltstack": "folder-salt-open", + ".saltstack": "folder-salt-open", + "_saltstack": "folder-salt-open", + "__saltstack__": "folder-salt-open", "simulations": "folder-simulations-open", ".simulations": "folder-simulations-open", "_simulations": "folder-simulations-open", @@ -7213,6 +7357,7 @@ "csproj": "visualstudio", "ruleset": "visualstudio", "sln": "visualstudio", + "slnf": "visualstudio", "slnx": "visualstudio", "suo": "visualstudio", "vb": "visualstudio", @@ -8162,6 +8307,7 @@ "toc": "toc", "cue": "cue", "lean": "lean", + "sls": "salt", "cljx": "clojure", "clojure": "clojure", "edn": "clojure", @@ -10150,6 +10296,30 @@ "esbuild.config.ts": "esbuild", "esbuild.config.mts": "esbuild", "esbuild.config.cts": "esbuild", + "esbuild.dev.js": "esbuild", + "esbuild.dev.mjs": "esbuild", + "esbuild.dev.cjs": "esbuild", + "esbuild.dev.ts": "esbuild", + "esbuild.dev.mts": "esbuild", + "esbuild.dev.cts": "esbuild", + "esbuild.stage.js": "esbuild", + "esbuild.stage.mjs": "esbuild", + "esbuild.stage.cjs": "esbuild", + "esbuild.stage.ts": "esbuild", + "esbuild.stage.mts": "esbuild", + "esbuild.stage.cts": "esbuild", + "esbuild.prod.js": "esbuild", + "esbuild.prod.mjs": "esbuild", + "esbuild.prod.cjs": "esbuild", + "esbuild.prod.ts": "esbuild", + "esbuild.prod.mts": "esbuild", + "esbuild.prod.cts": "esbuild", + "esbuild.test.js": "esbuild", + "esbuild.test.mjs": "esbuild", + "esbuild.test.cjs": "esbuild", + "esbuild.test.ts": "esbuild", + "esbuild.test.mts": "esbuild", + "esbuild.test.cts": "esbuild", "drizzle.config.ts": "drizzle", "drizzle.config.dev.ts": "drizzle", "drizzle.config.prod.ts": "drizzle", diff --git a/options/fileicon/material-icon-svgs.json b/options/fileicon/material-icon-svgs.json index f5254099ad..c0dc16e8a9 100644 --- a/options/fileicon/material-icon-svgs.json +++ b/options/fileicon/material-icon-svgs.json @@ -151,8 +151,8 @@ "database": "", "deepsource": "", "denizenscript": "", - "deno": "", - "deno_light": "", + "deno": "", + "deno_light": "", "dependabot": "", "dependencies-update": "", "dhall": "", @@ -495,6 +495,8 @@ "folder-metro": "", "folder-middleware-open": "", "folder-middleware": "", + "folder-migrations-open": "", + "folder-migrations": "", "folder-mjml-open": "", "folder-mjml": "", "folder-mobile-open": "", @@ -604,6 +606,8 @@ "folder-rules": "", "folder-rust-open": "", "folder-rust": "", + "folder-salt-open": "", + "folder-salt": "", "folder-sandbox-open": "", "folder-sandbox": "", "folder-sass-open": "", @@ -1024,6 +1028,7 @@ "ruff": "", "rust": "", "salesforce": "", + "salt": "", "san": "", "sas": "", "sass": "", diff --git a/package.json b/package.json index 7954e15046..3867a6c648 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "type": "module", - "packageManager": "pnpm@10.26.0", + "packageManager": "pnpm@10.28.0", "engines": { "node": ">= 22.6.0", "pnpm": ">= 10.0.0" @@ -8,7 +8,7 @@ "dependencies": { "@citation-js/core": "0.7.21", "@citation-js/plugin-bibtex": "0.7.21", - "@citation-js/plugin-csl": "0.7.21", + "@citation-js/plugin-csl": "0.7.22", "@citation-js/plugin-software-formats": "0.6.1", "@github/markdown-toolbar-element": "2.2.3", "@github/paste-markdown": "1.5.3", @@ -21,7 +21,7 @@ "@techknowlogick/license-checker-webpack-plugin": "0.3.0", "add-asset-webpack-plugin": "3.1.1", "ansi_up": "6.0.6", - "asciinema-player": "3.13.5", + "asciinema-player": "3.14.0", "chart.js": "4.5.1", "chartjs-adapter-dayjs-4": "1.0.4", "chartjs-plugin-zoom": "2.2.0", @@ -32,7 +32,7 @@ "dayjs": "1.11.19", "dropzone": "6.0.0-beta.2", "easymde": "2.20.0", - "esbuild-loader": "4.4.0", + "esbuild-loader": "4.4.2", "htmx.org": "2.0.8", "idiomorph": "0.7.4", "jquery": "3.7.1", @@ -41,7 +41,7 @@ "mini-css-extract-plugin": "2.9.4", "monaco-editor": "0.55.1", "monaco-editor-webpack-plugin": "7.1.1", - "online-3d-viewer": "0.17.0", + "online-3d-viewer": "0.18.0", "pdfobject": "2.3.1", "perfect-debounce": "2.0.0", "postcss": "8.5.6", @@ -56,11 +56,11 @@ "tributejs": "5.1.3", "uint8-to-base64": "0.2.1", "vanilla-colorful": "0.7.2", - "vue": "3.5.25", + "vue": "3.5.26", "vue-bar-graph": "2.2.0", "vue-chartjs": "5.3.3", "vue-loader": "17.4.2", - "webpack": "5.104.0", + "webpack": "5.104.1", "webpack-cli": "6.0.1", "wrap-ansi": "9.0.2" }, @@ -68,38 +68,38 @@ "@eslint-community/eslint-plugin-eslint-comments": "4.5.0", "@eslint/json": "0.14.0", "@playwright/test": "1.57.0", - "@stylistic/eslint-plugin": "5.6.1", + "@stylistic/eslint-plugin": "5.7.0", "@stylistic/stylelint-plugin": "4.0.0", "@types/codemirror": "5.60.17", "@types/dropzone": "5.7.9", "@types/jquery": "3.5.33", - "@types/katex": "0.16.7", + "@types/katex": "0.16.8", "@types/pdfobject": "2.2.5", "@types/sortablejs": "1.15.9", "@types/swagger-ui-dist": "3.30.6", "@types/throttle-debounce": "5.0.2", "@types/tinycolor2": "1.4.6", "@types/toastify-js": "1.12.4", - "@typescript-eslint/parser": "8.50.0", + "@typescript-eslint/parser": "8.53.0", "@vitejs/plugin-vue": "6.0.3", - "@vitest/eslint-plugin": "1.5.2", + "@vitest/eslint-plugin": "1.6.6", "eslint": "9.39.2", "eslint-import-resolver-typescript": "4.4.4", "eslint-plugin-array-func": "5.1.0", "eslint-plugin-github": "6.0.0", "eslint-plugin-import-x": "4.16.1", - "eslint-plugin-playwright": "2.4.0", + "eslint-plugin-playwright": "2.5.0", "eslint-plugin-regexp": "2.10.0", "eslint-plugin-sonarjs": "3.0.5", "eslint-plugin-unicorn": "62.0.0", "eslint-plugin-vue": "10.6.2", "eslint-plugin-vue-scoped-css": "2.12.0", "eslint-plugin-wc": "3.0.2", - "globals": "16.5.0", - "happy-dom": "20.0.11", + "globals": "17.0.0", + "happy-dom": "20.1.0", "jiti": "2.6.1", "markdownlint-cli": "0.47.0", - "material-icon-theme": "5.29.0", + "material-icon-theme": "5.30.0", "nolyfill": "1.0.44", "postcss-html": "1.8.0", "spectral-cli-bundle": "1.0.3", @@ -107,14 +107,14 @@ "stylelint-config-recommended": "17.0.0", "stylelint-declaration-block-no-ignored-properties": "2.8.0", "stylelint-declaration-strict-value": "1.10.11", - "stylelint-value-no-unknown-custom-properties": "6.0.1", + "stylelint-value-no-unknown-custom-properties": "6.1.0", "svgo": "4.0.0", "typescript": "5.9.3", - "typescript-eslint": "8.50.0", + "typescript-eslint": "8.53.0", "updates": "17.0.7", "vite-string-plugin": "1.4.9", - "vitest": "4.0.16", - "vue-tsc": "3.1.8" + "vitest": "4.0.17", + "vue-tsc": "3.2.2" }, "browserslist": [ "defaults" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 82d899b5fd..1b49f68721 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -33,8 +33,8 @@ importers: specifier: 0.7.21 version: 0.7.21(@citation-js/core@0.7.21) '@citation-js/plugin-csl': - specifier: 0.7.21 - version: 0.7.21(@citation-js/core@0.7.21) + specifier: 0.7.22 + version: 0.7.22(@citation-js/core@0.7.21) '@citation-js/plugin-software-formats': specifier: 0.6.1 version: 0.6.1 @@ -61,19 +61,19 @@ importers: version: 2.6.2 '@silverwind/vue3-calendar-heatmap': specifier: 2.1.1 - version: 2.1.1(tippy.js@6.3.7)(vue@3.5.25(typescript@5.9.3)) + version: 2.1.1(tippy.js@6.3.7)(vue@3.5.26(typescript@5.9.3)) '@techknowlogick/license-checker-webpack-plugin': specifier: 0.3.0 - version: 0.3.0(webpack@5.104.0) + version: 0.3.0(webpack@5.104.1) add-asset-webpack-plugin: specifier: 3.1.1 - version: 3.1.1(webpack@5.104.0) + version: 3.1.1(webpack@5.104.1) ansi_up: specifier: 6.0.6 version: 6.0.6 asciinema-player: - specifier: 3.13.5 - version: 3.13.5 + specifier: 3.14.0 + version: 3.14.0 chart.js: specifier: 4.5.1 version: 4.5.1 @@ -94,7 +94,7 @@ importers: version: 1.6.2 css-loader: specifier: 7.1.2 - version: 7.1.2(webpack@5.104.0) + version: 7.1.2(webpack@5.104.1) dayjs: specifier: 1.11.19 version: 1.11.19 @@ -105,8 +105,8 @@ importers: specifier: 2.20.0 version: 2.20.0 esbuild-loader: - specifier: 4.4.0 - version: 4.4.0(webpack@5.104.0) + specifier: 4.4.2 + version: 4.4.2(webpack@5.104.1) htmx.org: specifier: 2.0.8 version: 2.0.8 @@ -124,16 +124,16 @@ importers: version: 11.12.2 mini-css-extract-plugin: specifier: 2.9.4 - version: 2.9.4(webpack@5.104.0) + version: 2.9.4(webpack@5.104.1) monaco-editor: specifier: 0.55.1 version: 0.55.1 monaco-editor-webpack-plugin: specifier: 7.1.1 - version: 7.1.1(monaco-editor@0.55.1)(webpack@5.104.0) + version: 7.1.1(monaco-editor@0.55.1)(webpack@5.104.1) online-3d-viewer: - specifier: 0.17.0 - version: 0.17.0 + specifier: 0.18.0 + version: 0.18.0 pdfobject: specifier: 2.3.1 version: 2.3.1 @@ -145,7 +145,7 @@ importers: version: 8.5.6 postcss-loader: specifier: 8.2.0 - version: 8.2.0(postcss@8.5.6)(typescript@5.9.3)(webpack@5.104.0) + version: 8.2.0(postcss@8.5.6)(typescript@5.9.3)(webpack@5.104.1) sortablejs: specifier: 1.15.6 version: 1.15.6 @@ -177,23 +177,23 @@ importers: specifier: 0.7.2 version: 0.7.2 vue: - specifier: 3.5.25 - version: 3.5.25(typescript@5.9.3) + specifier: 3.5.26 + version: 3.5.26(typescript@5.9.3) vue-bar-graph: specifier: 2.2.0 version: 2.2.0(typescript@5.9.3) vue-chartjs: specifier: 5.3.3 - version: 5.3.3(chart.js@4.5.1)(vue@3.5.25(typescript@5.9.3)) + version: 5.3.3(chart.js@4.5.1)(vue@3.5.26(typescript@5.9.3)) vue-loader: specifier: 17.4.2 - version: 17.4.2(vue@3.5.25(typescript@5.9.3))(webpack@5.104.0) + version: 17.4.2(vue@3.5.26(typescript@5.9.3))(webpack@5.104.1) webpack: - specifier: 5.104.0 - version: 5.104.0(webpack-cli@6.0.1) + specifier: 5.104.1 + version: 5.104.1(webpack-cli@6.0.1) webpack-cli: specifier: 6.0.1 - version: 6.0.1(webpack@5.104.0) + version: 6.0.1(webpack@5.104.1) wrap-ansi: specifier: 9.0.2 version: 9.0.2 @@ -208,8 +208,8 @@ importers: specifier: 1.57.0 version: 1.57.0 '@stylistic/eslint-plugin': - specifier: 5.6.1 - version: 5.6.1(eslint@9.39.2(jiti@2.6.1)) + specifier: 5.7.0 + version: 5.7.0(eslint@9.39.2(jiti@2.6.1)) '@stylistic/stylelint-plugin': specifier: 4.0.0 version: 4.0.0(stylelint@16.26.1(typescript@5.9.3)) @@ -223,8 +223,8 @@ importers: specifier: 3.5.33 version: 3.5.33 '@types/katex': - specifier: 0.16.7 - version: 0.16.7 + specifier: 0.16.8 + version: 0.16.8 '@types/pdfobject': specifier: 2.2.5 version: 2.2.5 @@ -244,20 +244,20 @@ importers: specifier: 1.12.4 version: 1.12.4 '@typescript-eslint/parser': - specifier: 8.50.0 - version: 8.50.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + specifier: 8.53.0 + version: 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) '@vitejs/plugin-vue': specifier: 6.0.3 - version: 6.0.3(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(stylus@0.57.0)(terser@5.44.1)(yaml@2.8.2))(vue@3.5.25(typescript@5.9.3)) + version: 6.0.3(vite@7.3.1(@types/node@25.0.6)(jiti@2.6.1)(stylus@0.57.0)(terser@5.44.1)(yaml@2.8.2))(vue@3.5.26(typescript@5.9.3)) '@vitest/eslint-plugin': - specifier: 1.5.2 - version: 1.5.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)(vitest@4.0.16(@types/node@25.0.3)(happy-dom@20.0.11)(jiti@2.6.1)(stylus@0.57.0)(terser@5.44.1)(yaml@2.8.2)) + specifier: 1.6.6 + version: 1.6.6(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)(vitest@4.0.17(@types/node@25.0.6)(happy-dom@20.1.0)(jiti@2.6.1)(stylus@0.57.0)(terser@5.44.1)(yaml@2.8.2)) eslint: specifier: 9.39.2 version: 9.39.2(jiti@2.6.1) eslint-import-resolver-typescript: specifier: 4.4.4 - version: 4.4.4(eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.50.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.2(jiti@2.6.1)))(eslint-plugin-import@2.32.0)(eslint@9.39.2(jiti@2.6.1)) + version: 4.4.4(eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.2(jiti@2.6.1)))(eslint-plugin-import@2.32.0)(eslint@9.39.2(jiti@2.6.1)) eslint-plugin-array-func: specifier: 5.1.0 version: 5.1.0(eslint@9.39.2(jiti@2.6.1)) @@ -266,10 +266,10 @@ importers: version: 6.0.0(@types/eslint@9.6.1)(eslint-import-resolver-typescript@4.4.4)(eslint@9.39.2(jiti@2.6.1)) eslint-plugin-import-x: specifier: 4.16.1 - version: 4.16.1(@typescript-eslint/utils@8.50.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.2(jiti@2.6.1)) + version: 4.16.1(@typescript-eslint/utils@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.2(jiti@2.6.1)) eslint-plugin-playwright: - specifier: 2.4.0 - version: 2.4.0(eslint@9.39.2(jiti@2.6.1)) + specifier: 2.5.0 + version: 2.5.0(eslint@9.39.2(jiti@2.6.1)) eslint-plugin-regexp: specifier: 2.10.0 version: 2.10.0(eslint@9.39.2(jiti@2.6.1)) @@ -281,7 +281,7 @@ importers: version: 62.0.0(eslint@9.39.2(jiti@2.6.1)) eslint-plugin-vue: specifier: 10.6.2 - version: 10.6.2(@stylistic/eslint-plugin@5.6.1(eslint@9.39.2(jiti@2.6.1)))(@typescript-eslint/parser@8.50.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(vue-eslint-parser@10.2.0(eslint@9.39.2(jiti@2.6.1))) + version: 10.6.2(@stylistic/eslint-plugin@5.7.0(eslint@9.39.2(jiti@2.6.1)))(@typescript-eslint/parser@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(vue-eslint-parser@10.2.0(eslint@9.39.2(jiti@2.6.1))) eslint-plugin-vue-scoped-css: specifier: 2.12.0 version: 2.12.0(eslint@9.39.2(jiti@2.6.1))(vue-eslint-parser@10.2.0(eslint@9.39.2(jiti@2.6.1))) @@ -289,11 +289,11 @@ importers: specifier: 3.0.2 version: 3.0.2(eslint@9.39.2(jiti@2.6.1)) globals: - specifier: 16.5.0 - version: 16.5.0 + specifier: 17.0.0 + version: 17.0.0 happy-dom: - specifier: 20.0.11 - version: 20.0.11 + specifier: 20.1.0 + version: 20.1.0 jiti: specifier: 2.6.1 version: 2.6.1 @@ -301,8 +301,8 @@ importers: specifier: 0.47.0 version: 0.47.0 material-icon-theme: - specifier: 5.29.0 - version: 5.29.0 + specifier: 5.30.0 + version: 5.30.0 nolyfill: specifier: 1.0.44 version: 1.0.44 @@ -325,8 +325,8 @@ importers: specifier: 1.10.11 version: 1.10.11(stylelint@16.26.1(typescript@5.9.3)) stylelint-value-no-unknown-custom-properties: - specifier: 6.0.1 - version: 6.0.1(stylelint@16.26.1(typescript@5.9.3)) + specifier: 6.1.0 + version: 6.1.0(stylelint@16.26.1(typescript@5.9.3)) svgo: specifier: 4.0.0 version: 4.0.0 @@ -334,8 +334,8 @@ importers: specifier: 5.9.3 version: 5.9.3 typescript-eslint: - specifier: 8.50.0 - version: 8.50.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + specifier: 8.53.0 + version: 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) updates: specifier: 17.0.7 version: 17.0.7 @@ -343,11 +343,11 @@ importers: specifier: 1.4.9 version: 1.4.9 vitest: - specifier: 4.0.16 - version: 4.0.16(@types/node@25.0.3)(happy-dom@20.0.11)(jiti@2.6.1)(stylus@0.57.0)(terser@5.44.1)(yaml@2.8.2) + specifier: 4.0.17 + version: 4.0.17(@types/node@25.0.6)(happy-dom@20.1.0)(jiti@2.6.1)(stylus@0.57.0)(terser@5.44.1)(yaml@2.8.2) vue-tsc: - specifier: 3.1.8 - version: 3.1.8(typescript@5.9.3) + specifier: 3.2.2 + version: 3.2.2(typescript@5.9.3) packages: @@ -358,8 +358,8 @@ packages: '@antfu/install-pkg@1.1.0': resolution: {integrity: sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==} - '@babel/code-frame@7.27.1': - resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} + '@babel/code-frame@7.28.6': + resolution: {integrity: sha512-JYgintcMjRiCvS8mMECzaEn+m3PfoQiyqukOMCCVQtoJGYJw8j/8LBJEiqkHLkfwCcs74E3pbAUFNg7d9VNJ+Q==} engines: {node: '>=6.9.0'} '@babel/helper-string-parser@7.27.1': @@ -370,27 +370,27 @@ packages: resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} engines: {node: '>=6.9.0'} - '@babel/parser@7.28.5': - resolution: {integrity: sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==} + '@babel/parser@7.28.6': + resolution: {integrity: sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ==} engines: {node: '>=6.0.0'} hasBin: true - '@babel/runtime@7.28.4': - resolution: {integrity: sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==} + '@babel/runtime@7.28.6': + resolution: {integrity: sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==} engines: {node: '>=6.9.0'} - '@babel/types@7.28.5': - resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==} + '@babel/types@7.28.6': + resolution: {integrity: sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg==} engines: {node: '>=6.9.0'} '@braintree/sanitize-url@7.1.1': resolution: {integrity: sha512-i1L7noDNxtFyL5DmZafWy1wRVhGehQmzZaz1HiN5e7iylJMSZR7ekOV7NsIqa5qBldlLrsKv4HbgFUVlQrz8Mw==} - '@cacheable/memory@2.0.6': - resolution: {integrity: sha512-7e8SScMocHxcAb8YhtkbMhGG+EKLRIficb1F5sjvhSYsWTZGxvg4KIDp8kgxnV2PUJ3ddPe6J9QESjKvBWRDkg==} + '@cacheable/memory@2.0.7': + resolution: {integrity: sha512-RbxnxAMf89Tp1dLhXMS7ceft/PGsDl1Ip7T20z5nZ+pwIAsQ1p2izPjVG69oCLv/jfQ7HDPHTWK0c9rcAWXN3A==} - '@cacheable/utils@2.3.2': - resolution: {integrity: sha512-8kGE2P+HjfY8FglaOiW+y8qxcaQAfAhVML+i66XJR3YX5FtyDqn6Txctr3K2FrbxLKixRRYYBWMbuGciOhYNDg==} + '@cacheable/utils@2.3.3': + resolution: {integrity: sha512-JsXDL70gQ+1Vc2W/KUFfkAJzgb4puKwwKehNLuB+HrNKWf91O736kGfxn4KujXCCSuh6mRRL4XEB0PkAFjWS0A==} '@chevrotain/cst-dts-gen@11.0.3': resolution: {integrity: sha512-BvIKpRLeS/8UbfxXxgC33xOumsacaeCKAjAeLyOn7Pcp95HiRbrpl14S+9vaZLolnbssPIUuiUd8IvgkRyt6NQ==} @@ -429,8 +429,8 @@ packages: resolution: {integrity: sha512-tLjTgsfzNOdQWGn5mNc2NAaydHnlRucSERoyAXLN7u0BQBfp7j5zwdxCmxcQD/N7hH3fpDKMG+qDzbqpJuKyNA==} engines: {node: '>=14.0.0'} - '@citation-js/plugin-csl@0.7.21': - resolution: {integrity: sha512-23ySPYCWDiU1JqhvqTYLn6+C11LkeJxTfyPKKXCK2wan9iF9ODvY7JYNl/OJgtwvu485dKfDpqqptWv6i71Meg==} + '@citation-js/plugin-csl@0.7.22': + resolution: {integrity: sha512-/rGdtbeP3nS4uZDdEbQUHT8PrUcIs0da2t+sWMKYXoOhXQqfw3oJJ7p4tUD+R8lptyIR5Eq20/DFk/kQDdLpYg==} engines: {node: '>=16.0.0'} peerDependencies: '@citation-js/core': ^0.7.0 @@ -461,8 +461,8 @@ packages: peerDependencies: '@csstools/css-tokenizer': ^3.0.4 - '@csstools/css-syntax-patches-for-csstree@1.0.21': - resolution: {integrity: sha512-plP8N8zKfEZ26figX4Nvajx8DuzfuRpLTqglQ5d0chfnt35Qt3X+m6ASZ+rG0D0kxe/upDVNwSIVJP5n4FuNfw==} + '@csstools/css-syntax-patches-for-csstree@1.0.25': + resolution: {integrity: sha512-g0Kw9W3vjx5BEBAF8c5Fm2NcB/Fs8jJXh85aXqwEXiL+tqtOut07TWgyaGzAAfTM+gKckrrncyeGEZPcaRgm2Q==} engines: {node: '>=18'} '@csstools/css-tokenizer@3.0.4': @@ -489,321 +489,165 @@ packages: '@dual-bundle/import-meta-resolve@4.2.1': resolution: {integrity: sha512-id+7YRUgoUX6CgV0DtuhirQWodeeA7Lf4i2x71JS/vtA5pRb/hIGWlw+G6MeXvsM+MXrz0VAydTGElX1rAfgPg==} - '@emnapi/core@1.7.1': - resolution: {integrity: sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg==} + '@emnapi/core@1.8.1': + resolution: {integrity: sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg==} - '@emnapi/runtime@1.7.1': - resolution: {integrity: sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==} + '@emnapi/runtime@1.8.1': + resolution: {integrity: sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==} '@emnapi/wasi-threads@1.1.0': resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==} - '@esbuild/aix-ppc64@0.25.12': - resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [aix] - '@esbuild/aix-ppc64@0.27.2': resolution: {integrity: sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] - '@esbuild/android-arm64@0.25.12': - resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [android] - '@esbuild/android-arm64@0.27.2': resolution: {integrity: sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==} engines: {node: '>=18'} cpu: [arm64] os: [android] - '@esbuild/android-arm@0.25.12': - resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} - engines: {node: '>=18'} - cpu: [arm] - os: [android] - '@esbuild/android-arm@0.27.2': resolution: {integrity: sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==} engines: {node: '>=18'} cpu: [arm] os: [android] - '@esbuild/android-x64@0.25.12': - resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} - engines: {node: '>=18'} - cpu: [x64] - os: [android] - '@esbuild/android-x64@0.27.2': resolution: {integrity: sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==} engines: {node: '>=18'} cpu: [x64] os: [android] - '@esbuild/darwin-arm64@0.25.12': - resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [darwin] - '@esbuild/darwin-arm64@0.27.2': resolution: {integrity: sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] - '@esbuild/darwin-x64@0.25.12': - resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} - engines: {node: '>=18'} - cpu: [x64] - os: [darwin] - '@esbuild/darwin-x64@0.27.2': resolution: {integrity: sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==} engines: {node: '>=18'} cpu: [x64] os: [darwin] - '@esbuild/freebsd-arm64@0.25.12': - resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [freebsd] - '@esbuild/freebsd-arm64@0.27.2': resolution: {integrity: sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-x64@0.25.12': - resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [freebsd] - '@esbuild/freebsd-x64@0.27.2': resolution: {integrity: sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] - '@esbuild/linux-arm64@0.25.12': - resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} - engines: {node: '>=18'} - cpu: [arm64] - os: [linux] - '@esbuild/linux-arm64@0.27.2': resolution: {integrity: sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==} engines: {node: '>=18'} cpu: [arm64] os: [linux] - '@esbuild/linux-arm@0.25.12': - resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} - engines: {node: '>=18'} - cpu: [arm] - os: [linux] - '@esbuild/linux-arm@0.27.2': resolution: {integrity: sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==} engines: {node: '>=18'} cpu: [arm] os: [linux] - '@esbuild/linux-ia32@0.25.12': - resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} - engines: {node: '>=18'} - cpu: [ia32] - os: [linux] - '@esbuild/linux-ia32@0.27.2': resolution: {integrity: sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==} engines: {node: '>=18'} cpu: [ia32] os: [linux] - '@esbuild/linux-loong64@0.25.12': - resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} - engines: {node: '>=18'} - cpu: [loong64] - os: [linux] - '@esbuild/linux-loong64@0.27.2': resolution: {integrity: sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==} engines: {node: '>=18'} cpu: [loong64] os: [linux] - '@esbuild/linux-mips64el@0.25.12': - resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} - engines: {node: '>=18'} - cpu: [mips64el] - os: [linux] - '@esbuild/linux-mips64el@0.27.2': resolution: {integrity: sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] - '@esbuild/linux-ppc64@0.25.12': - resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [linux] - '@esbuild/linux-ppc64@0.27.2': resolution: {integrity: sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] - '@esbuild/linux-riscv64@0.25.12': - resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} - engines: {node: '>=18'} - cpu: [riscv64] - os: [linux] - '@esbuild/linux-riscv64@0.27.2': resolution: {integrity: sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] - '@esbuild/linux-s390x@0.25.12': - resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} - engines: {node: '>=18'} - cpu: [s390x] - os: [linux] - '@esbuild/linux-s390x@0.27.2': resolution: {integrity: sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==} engines: {node: '>=18'} cpu: [s390x] os: [linux] - '@esbuild/linux-x64@0.25.12': - resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} - engines: {node: '>=18'} - cpu: [x64] - os: [linux] - '@esbuild/linux-x64@0.27.2': resolution: {integrity: sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==} engines: {node: '>=18'} cpu: [x64] os: [linux] - '@esbuild/netbsd-arm64@0.25.12': - resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [netbsd] - '@esbuild/netbsd-arm64@0.27.2': resolution: {integrity: sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] - '@esbuild/netbsd-x64@0.25.12': - resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [netbsd] - '@esbuild/netbsd-x64@0.27.2': resolution: {integrity: sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] - '@esbuild/openbsd-arm64@0.25.12': - resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openbsd] - '@esbuild/openbsd-arm64@0.27.2': resolution: {integrity: sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-x64@0.25.12': - resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} - engines: {node: '>=18'} - cpu: [x64] - os: [openbsd] - '@esbuild/openbsd-x64@0.27.2': resolution: {integrity: sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] - '@esbuild/openharmony-arm64@0.25.12': - resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openharmony] - '@esbuild/openharmony-arm64@0.27.2': resolution: {integrity: sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] - '@esbuild/sunos-x64@0.25.12': - resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} - engines: {node: '>=18'} - cpu: [x64] - os: [sunos] - '@esbuild/sunos-x64@0.27.2': resolution: {integrity: sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==} engines: {node: '>=18'} cpu: [x64] os: [sunos] - '@esbuild/win32-arm64@0.25.12': - resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [win32] - '@esbuild/win32-arm64@0.27.2': resolution: {integrity: sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==} engines: {node: '>=18'} cpu: [arm64] os: [win32] - '@esbuild/win32-ia32@0.25.12': - resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} - engines: {node: '>=18'} - cpu: [ia32] - os: [win32] - '@esbuild/win32-ia32@0.27.2': resolution: {integrity: sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==} engines: {node: '>=18'} cpu: [ia32] os: [win32] - '@esbuild/win32-x64@0.25.12': - resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} - engines: {node: '>=18'} - cpu: [x64] - os: [win32] - '@esbuild/win32-x64@0.27.2': resolution: {integrity: sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==} engines: {node: '>=18'} @@ -816,8 +660,8 @@ packages: peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 - '@eslint-community/eslint-utils@4.9.0': - resolution: {integrity: sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==} + '@eslint-community/eslint-utils@4.9.1': + resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 @@ -1060,113 +904,128 @@ packages: '@rolldown/pluginutils@1.0.0-beta.53': resolution: {integrity: sha512-vENRlFU4YbrwVqNDZ7fLvy+JR1CRkyr01jhSiDpE1u6py3OMzQfztQU2jxykW3ALNxO4kSlqIDeYyD0Y9RcQeQ==} - '@rollup/rollup-android-arm-eabi@4.53.5': - resolution: {integrity: sha512-iDGS/h7D8t7tvZ1t6+WPK04KD0MwzLZrG0se1hzBjSi5fyxlsiggoJHwh18PCFNn7tG43OWb6pdZ6Y+rMlmyNQ==} + '@rollup/rollup-android-arm-eabi@4.55.1': + resolution: {integrity: sha512-9R0DM/ykwfGIlNu6+2U09ga0WXeZ9MRC2Ter8jnz8415VbuIykVuc6bhdrbORFZANDmTDvq26mJrEVTl8TdnDg==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.53.5': - resolution: {integrity: sha512-wrSAViWvZHBMMlWk6EJhvg8/rjxzyEhEdgfMMjREHEq11EtJ6IP6yfcCH57YAEca2Oe3FNCE9DSTgU70EIGmVw==} + '@rollup/rollup-android-arm64@4.55.1': + resolution: {integrity: sha512-eFZCb1YUqhTysgW3sj/55du5cG57S7UTNtdMjCW7LwVcj3dTTcowCsC8p7uBdzKsZYa8J7IDE8lhMI+HX1vQvg==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.53.5': - resolution: {integrity: sha512-S87zZPBmRO6u1YXQLwpveZm4JfPpAa6oHBX7/ghSiGH3rz/KDgAu1rKdGutV+WUI6tKDMbaBJomhnT30Y2t4VQ==} + '@rollup/rollup-darwin-arm64@4.55.1': + resolution: {integrity: sha512-p3grE2PHcQm2e8PSGZdzIhCKbMCw/xi9XvMPErPhwO17vxtvCN5FEA2mSLgmKlCjHGMQTP6phuQTYWUnKewwGg==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.53.5': - resolution: {integrity: sha512-YTbnsAaHo6VrAczISxgpTva8EkfQus0VPEVJCEaboHtZRIb6h6j0BNxRBOwnDciFTZLDPW5r+ZBmhL/+YpTZgA==} + '@rollup/rollup-darwin-x64@4.55.1': + resolution: {integrity: sha512-rDUjG25C9qoTm+e02Esi+aqTKSBYwVTaoS1wxcN47/Luqef57Vgp96xNANwt5npq9GDxsH7kXxNkJVEsWEOEaQ==} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.53.5': - resolution: {integrity: sha512-1T8eY2J8rKJWzaznV7zedfdhD1BqVs1iqILhmHDq/bqCUZsrMt+j8VCTHhP0vdfbHK3e1IQ7VYx3jlKqwlf+vw==} + '@rollup/rollup-freebsd-arm64@4.55.1': + resolution: {integrity: sha512-+JiU7Jbp5cdxekIgdte0jfcu5oqw4GCKr6i3PJTlXTCU5H5Fvtkpbs4XJHRmWNXF+hKmn4v7ogI5OQPaupJgOg==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.53.5': - resolution: {integrity: sha512-sHTiuXyBJApxRn+VFMaw1U+Qsz4kcNlxQ742snICYPrY+DDL8/ZbaC4DVIB7vgZmp3jiDaKA0WpBdP0aqPJoBQ==} + '@rollup/rollup-freebsd-x64@4.55.1': + resolution: {integrity: sha512-V5xC1tOVWtLLmr3YUk2f6EJK4qksksOYiz/TCsFHu/R+woubcLWdC9nZQmwjOAbmExBIVKsm1/wKmEy4z4u4Bw==} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.53.5': - resolution: {integrity: sha512-dV3T9MyAf0w8zPVLVBptVlzaXxka6xg1f16VAQmjg+4KMSTWDvhimI/Y6mp8oHwNrmnmVl9XxJ/w/mO4uIQONA==} + '@rollup/rollup-linux-arm-gnueabihf@4.55.1': + resolution: {integrity: sha512-Rn3n+FUk2J5VWx+ywrG/HGPTD9jXNbicRtTM11e/uorplArnXZYsVifnPPqNNP5BsO3roI4n8332ukpY/zN7rQ==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm-musleabihf@4.53.5': - resolution: {integrity: sha512-wIGYC1x/hyjP+KAu9+ewDI+fi5XSNiUi9Bvg6KGAh2TsNMA3tSEs+Sh6jJ/r4BV/bx/CyWu2ue9kDnIdRyafcQ==} + '@rollup/rollup-linux-arm-musleabihf@4.55.1': + resolution: {integrity: sha512-grPNWydeKtc1aEdrJDWk4opD7nFtQbMmV7769hiAaYyUKCT1faPRm2av8CX1YJsZ4TLAZcg9gTR1KvEzoLjXkg==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm64-gnu@4.53.5': - resolution: {integrity: sha512-Y+qVA0D9d0y2FRNiG9oM3Hut/DgODZbU9I8pLLPwAsU0tUKZ49cyV1tzmB/qRbSzGvY8lpgGkJuMyuhH7Ma+Vg==} + '@rollup/rollup-linux-arm64-gnu@4.55.1': + resolution: {integrity: sha512-a59mwd1k6x8tXKcUxSyISiquLwB5pX+fJW9TkWU46lCqD/GRDe9uDN31jrMmVP3feI3mhAdvcCClhV8V5MhJFQ==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-arm64-musl@4.53.5': - resolution: {integrity: sha512-juaC4bEgJsyFVfqhtGLz8mbopaWD+WeSOYr5E16y+1of6KQjc0BpwZLuxkClqY1i8sco+MdyoXPNiCkQou09+g==} + '@rollup/rollup-linux-arm64-musl@4.55.1': + resolution: {integrity: sha512-puS1MEgWX5GsHSoiAsF0TYrpomdvkaXm0CofIMG5uVkP6IBV+ZO9xhC5YEN49nsgYo1DuuMquF9+7EDBVYu4uA==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-loong64-gnu@4.53.5': - resolution: {integrity: sha512-rIEC0hZ17A42iXtHX+EPJVL/CakHo+tT7W0pbzdAGuWOt2jxDFh7A/lRhsNHBcqL4T36+UiAgwO8pbmn3dE8wA==} + '@rollup/rollup-linux-loong64-gnu@4.55.1': + resolution: {integrity: sha512-r3Wv40in+lTsULSb6nnoudVbARdOwb2u5fpeoOAZjFLznp6tDU8kd+GTHmJoqZ9lt6/Sys33KdIHUaQihFcu7g==} cpu: [loong64] os: [linux] - '@rollup/rollup-linux-ppc64-gnu@4.53.5': - resolution: {integrity: sha512-T7l409NhUE552RcAOcmJHj3xyZ2h7vMWzcwQI0hvn5tqHh3oSoclf9WgTl+0QqffWFG8MEVZZP1/OBglKZx52Q==} + '@rollup/rollup-linux-loong64-musl@4.55.1': + resolution: {integrity: sha512-MR8c0+UxAlB22Fq4R+aQSPBayvYa3+9DrwG/i1TKQXFYEaoW3B5b/rkSRIypcZDdWjWnpcvxbNaAJDcSbJU3Lw==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-ppc64-gnu@4.55.1': + resolution: {integrity: sha512-3KhoECe1BRlSYpMTeVrD4sh2Pw2xgt4jzNSZIIPLFEsnQn9gAnZagW9+VqDqAHgm1Xc77LzJOo2LdigS5qZ+gw==} cpu: [ppc64] os: [linux] - '@rollup/rollup-linux-riscv64-gnu@4.53.5': - resolution: {integrity: sha512-7OK5/GhxbnrMcxIFoYfhV/TkknarkYC1hqUw1wU2xUN3TVRLNT5FmBv4KkheSG2xZ6IEbRAhTooTV2+R5Tk0lQ==} + '@rollup/rollup-linux-ppc64-musl@4.55.1': + resolution: {integrity: sha512-ziR1OuZx0vdYZZ30vueNZTg73alF59DicYrPViG0NEgDVN8/Jl87zkAPu4u6VjZST2llgEUjaiNl9JM6HH1Vdw==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.55.1': + resolution: {integrity: sha512-uW0Y12ih2XJRERZ4jAfKamTyIHVMPQnTZcQjme2HMVDAHY4amf5u414OqNYC+x+LzRdRcnIG1YodLrrtA8xsxw==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-riscv64-musl@4.53.5': - resolution: {integrity: sha512-GwuDBE/PsXaTa76lO5eLJTyr2k8QkPipAyOrs4V/KJufHCZBJ495VCGJol35grx9xryk4V+2zd3Ri+3v7NPh+w==} + '@rollup/rollup-linux-riscv64-musl@4.55.1': + resolution: {integrity: sha512-u9yZ0jUkOED1BFrqu3BwMQoixvGHGZ+JhJNkNKY/hyoEgOwlqKb62qu+7UjbPSHYjiVy8kKJHvXKv5coH4wDeg==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-s390x-gnu@4.53.5': - resolution: {integrity: sha512-IAE1Ziyr1qNfnmiQLHBURAD+eh/zH1pIeJjeShleII7Vj8kyEm2PF77o+lf3WTHDpNJcu4IXJxNO0Zluro8bOw==} + '@rollup/rollup-linux-s390x-gnu@4.55.1': + resolution: {integrity: sha512-/0PenBCmqM4ZUd0190j7J0UsQ/1nsi735iPRakO8iPciE7BQ495Y6msPzaOmvx0/pn+eJVVlZrNrSh4WSYLxNg==} cpu: [s390x] os: [linux] - '@rollup/rollup-linux-x64-gnu@4.53.5': - resolution: {integrity: sha512-Pg6E+oP7GvZ4XwgRJBuSXZjcqpIW3yCBhK4BcsANvb47qMvAbCjR6E+1a/U2WXz1JJxp9/4Dno3/iSJLcm5auw==} + '@rollup/rollup-linux-x64-gnu@4.55.1': + resolution: {integrity: sha512-a8G4wiQxQG2BAvo+gU6XrReRRqj+pLS2NGXKm8io19goR+K8lw269eTrPkSdDTALwMmJp4th2Uh0D8J9bEV1vg==} cpu: [x64] os: [linux] - '@rollup/rollup-linux-x64-musl@4.53.5': - resolution: {integrity: sha512-txGtluxDKTxaMDzUduGP0wdfng24y1rygUMnmlUJ88fzCCULCLn7oE5kb2+tRB+MWq1QDZT6ObT5RrR8HFRKqg==} + '@rollup/rollup-linux-x64-musl@4.55.1': + resolution: {integrity: sha512-bD+zjpFrMpP/hqkfEcnjXWHMw5BIghGisOKPj+2NaNDuVT+8Ds4mPf3XcPHuat1tz89WRL+1wbcxKY3WSbiT7w==} cpu: [x64] os: [linux] - '@rollup/rollup-openharmony-arm64@4.53.5': - resolution: {integrity: sha512-3DFiLPnTxiOQV993fMc+KO8zXHTcIjgaInrqlG8zDp1TlhYl6WgrOHuJkJQ6M8zHEcntSJsUp1XFZSY8C1DYbg==} + '@rollup/rollup-openbsd-x64@4.55.1': + resolution: {integrity: sha512-eLXw0dOiqE4QmvikfQ6yjgkg/xDM+MdU9YJuP4ySTibXU0oAvnEWXt7UDJmD4UkYialMfOGFPJnIHSe/kdzPxg==} + cpu: [x64] + os: [openbsd] + + '@rollup/rollup-openharmony-arm64@4.55.1': + resolution: {integrity: sha512-xzm44KgEP11te3S2HCSyYf5zIzWmx3n8HDCc7EE59+lTcswEWNpvMLfd9uJvVX8LCg9QWG67Xt75AuHn4vgsXw==} cpu: [arm64] os: [openharmony] - '@rollup/rollup-win32-arm64-msvc@4.53.5': - resolution: {integrity: sha512-nggc/wPpNTgjGg75hu+Q/3i32R00Lq1B6N1DO7MCU340MRKL3WZJMjA9U4K4gzy3dkZPXm9E1Nc81FItBVGRlA==} + '@rollup/rollup-win32-arm64-msvc@4.55.1': + resolution: {integrity: sha512-yR6Bl3tMC/gBok5cz/Qi0xYnVbIxGx5Fcf/ca0eB6/6JwOY+SRUcJfI0OpeTpPls7f194as62thCt/2BjxYN8g==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.53.5': - resolution: {integrity: sha512-U/54pTbdQpPLBdEzCT6NBCFAfSZMvmjr0twhnD9f4EIvlm9wy3jjQ38yQj1AGznrNO65EWQMgm/QUjuIVrYF9w==} + '@rollup/rollup-win32-ia32-msvc@4.55.1': + resolution: {integrity: sha512-3fZBidchE0eY0oFZBnekYCfg+5wAB0mbpCBuofh5mZuzIU/4jIVkbESmd2dOsFNS78b53CYv3OAtwqkZZmU5nA==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-gnu@4.53.5': - resolution: {integrity: sha512-2NqKgZSuLH9SXBBV2dWNRCZmocgSOx8OJSdpRaEcRlIfX8YrKxUT6z0F1NpvDVhOsl190UFTRh2F2WDWWCYp3A==} + '@rollup/rollup-win32-x64-gnu@4.55.1': + resolution: {integrity: sha512-xGGY5pXj69IxKb4yv/POoocPy/qmEGhimy/FoTpTSVju3FYXUQQMFCaZZXJVidsmGxRioZAwpThl/4zX41gRKg==} cpu: [x64] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.53.5': - resolution: {integrity: sha512-JRpZUhCfhZ4keB5v0fe02gQJy05GqboPOaxvjugW04RLSYYoB/9t2lx2u/tMs/Na/1NXfY8QYjgRljRpN+MjTQ==} + '@rollup/rollup-win32-x64-msvc@4.55.1': + resolution: {integrity: sha512-SPEpaL6DX4rmcXtnhdrQYgzQ5W2uW3SCJch88lB2zImhJRhIIK44fkUrgIV/Q8yUNfw5oyZ5vkeQsZLhCb06lw==} cpu: [x64] os: [win32] @@ -1204,8 +1063,8 @@ packages: '@standard-schema/spec@1.1.0': resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} - '@stylistic/eslint-plugin@5.6.1': - resolution: {integrity: sha512-JCs+MqoXfXrRPGbGmho/zGS/jMcn3ieKl/A8YImqib76C8kjgZwq5uUFzc30lJkMvcchuRn6/v8IApLxli3Jyw==} + '@stylistic/eslint-plugin@5.7.0': + resolution: {integrity: sha512-PsSugIf9ip1H/mWKj4bi/BlEoerxXAda9ByRFsYuwsmr6af9NxJL0AaiNXs8Le7R21QR5KMiD/KdxZZ71LjAxQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: '>=9.0.0' @@ -1305,8 +1164,8 @@ packages: '@types/d3-selection@3.0.11': resolution: {integrity: sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==} - '@types/d3-shape@3.1.7': - resolution: {integrity: sha512-VLvUQ33C+3J+8p+Daf+nYSOsjB4GXp19/S/aGo60m9h1v6XaxjiT82lKVWJCfzhtuZ3yD7i/TPeC/fuKLLOSmg==} + '@types/d3-shape@3.1.8': + resolution: {integrity: sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w==} '@types/d3-time-format@4.0.3': resolution: {integrity: sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==} @@ -1359,8 +1218,8 @@ packages: '@types/json5@0.0.29': resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} - '@types/katex@0.16.7': - resolution: {integrity: sha512-HMwFiRujE5PjrgwHQ25+bsLJgowjGjm5Z8FVSf0N6PwgJrwxH0QxzHYDcKsTfV3wva0vzrpqMTJS2jXPr5BMEQ==} + '@types/katex@0.16.8': + resolution: {integrity: sha512-trgaNyfU+Xh2Tc+ABIb44a5AYUpicB3uwirOioeOkNPPbmgRNtcWyDeeFRzjPZENO9Vq8gvVqfhaaXWLlevVwg==} '@types/marked@4.3.2': resolution: {integrity: sha512-a79Yc3TOk6dGdituy8hmTTJXjOkZ7zsFYV10L337ttq/rec8lRMDBpV7fL3uLx6TgbFCa5DU/h8FmIBQPSbU0w==} @@ -1368,11 +1227,11 @@ packages: '@types/ms@2.1.0': resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} - '@types/node@20.19.27': - resolution: {integrity: sha512-N2clP5pJhB2YnZJ3PIHFk5RkygRX5WO/5f0WC08tp0wd+sv0rsJk3MqWn3CbNmT2J505a5336jaQj4ph1AdMug==} + '@types/node@20.19.28': + resolution: {integrity: sha512-VyKBr25BuFDzBFCK5sUM6ZXiWfqgCTwTAOK8qzGV/m9FCirXYDlmczJ+d5dXBAQALGCdRRdbteKYfJ84NGEusw==} - '@types/node@25.0.3': - resolution: {integrity: sha512-W609buLVRVmeW693xKfzHeIV6nJGGz98uCPfeXI1ELMLXVeKYZ9m15fAMSaUPBHYLGFsVRcMmSCksQOrZV9BYA==} + '@types/node@25.0.6': + resolution: {integrity: sha512-NNu0sjyNxpoiW3YuVFfNz7mxSQ+S4X2G28uqg2s+CzoqoQjLPsWSbsFFyztIAqt2vb8kfEAsJNepMGPTxFDx3Q==} '@types/pdfobject@2.2.5': resolution: {integrity: sha512-7gD5tqc/RUDq0PyoLemL0vEHxBYi+zY0WVaFAx/Y0jBsXFgot1vB9No1GhDZGwRGJMCIZbgAb74QG9MTyTNU/g==} @@ -1407,63 +1266,66 @@ packages: '@types/whatwg-mimetype@3.0.2': resolution: {integrity: sha512-c2AKvDT8ToxLIOUlN51gTiHXflsfIFisS4pO7pDPoKouJCESkhZnEy623gwP9laCy5lnLDAw1vAzu2vM2YLOrA==} - '@typescript-eslint/eslint-plugin@8.50.0': - resolution: {integrity: sha512-O7QnmOXYKVtPrfYzMolrCTfkezCJS9+ljLdKW/+DCvRsc3UAz+sbH6Xcsv7p30+0OwUbeWfUDAQE0vpabZ3QLg==} + '@types/ws@8.18.1': + resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==} + + '@typescript-eslint/eslint-plugin@8.53.0': + resolution: {integrity: sha512-eEXsVvLPu8Z4PkFibtuFJLJOTAV/nPdgtSjkGoPpddpFk3/ym2oy97jynY6ic2m6+nc5M8SE1e9v/mHKsulcJg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.50.0 + '@typescript-eslint/parser': ^8.53.0 eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/parser@8.50.0': - resolution: {integrity: sha512-6/cmF2piao+f6wSxUsJLZjck7OQsYyRtcOZS02k7XINSNlz93v6emM8WutDQSXnroG2xwYlEVHJI+cPA7CPM3Q==} + '@typescript-eslint/parser@8.53.0': + resolution: {integrity: sha512-npiaib8XzbjtzS2N4HlqPvlpxpmZ14FjSJrteZpPxGUaYPlvhzlzUZ4mZyABo0EFrOWnvyd0Xxroq//hKhtAWg==} 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.50.0': - resolution: {integrity: sha512-Cg/nQcL1BcoTijEWyx4mkVC56r8dj44bFDvBdygifuS20f3OZCHmFbjF34DPSi07kwlFvqfv/xOLnJ5DquxSGQ==} + '@typescript-eslint/project-service@8.53.0': + resolution: {integrity: sha512-Bl6Gdr7NqkqIP5yP9z1JU///Nmes4Eose6L1HwpuVHwScgDPPuEWbUVhvlZmb8hy0vX9syLk5EGNL700WcBlbg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/scope-manager@8.50.0': - resolution: {integrity: sha512-xCwfuCZjhIqy7+HKxBLrDVT5q/iq7XBVBXLn57RTIIpelLtEIZHXAF/Upa3+gaCpeV1NNS5Z9A+ID6jn50VD4A==} + '@typescript-eslint/scope-manager@8.53.0': + resolution: {integrity: sha512-kWNj3l01eOGSdVBnfAF2K1BTh06WS0Yet6JUgb9Cmkqaz3Jlu0fdVUjj9UI8gPidBWSMqDIglmEXifSgDT/D0g==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/tsconfig-utils@8.50.0': - resolution: {integrity: sha512-vxd3G/ybKTSlm31MOA96gqvrRGv9RJ7LGtZCn2Vrc5htA0zCDvcMqUkifcjrWNNKXHUU3WCkYOzzVSFBd0wa2w==} + '@typescript-eslint/tsconfig-utils@8.53.0': + resolution: {integrity: sha512-K6Sc0R5GIG6dNoPdOooQ+KtvT5KCKAvTcY8h2rIuul19vxH5OTQk7ArKkd4yTzkw66WnNY0kPPzzcmWA+XRmiA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/type-utils@8.50.0': - resolution: {integrity: sha512-7OciHT2lKCewR0mFoBrvZJ4AXTMe/sYOe87289WAViOocEmDjjv8MvIOT2XESuKj9jp8u3SZYUSh89QA4S1kQw==} + '@typescript-eslint/type-utils@8.53.0': + resolution: {integrity: sha512-BBAUhlx7g4SmcLhn8cnbxoxtmS7hcq39xKCgiutL3oNx1TaIp+cny51s8ewnKMpVUKQUGb41RAUWZ9kxYdovuw==} 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.50.0': - resolution: {integrity: sha512-iX1mgmGrXdANhhITbpp2QQM2fGehBse9LbTf0sidWK6yg/NE+uhV5dfU1g6EYPlcReYmkE9QLPq/2irKAmtS9w==} + '@typescript-eslint/types@8.53.0': + resolution: {integrity: sha512-Bmh9KX31Vlxa13+PqPvt4RzKRN1XORYSLlAE+sO1i28NkisGbTtSLFVB3l7PWdHtR3E0mVMuC7JilWJ99m2HxQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@8.50.0': - resolution: {integrity: sha512-W7SVAGBR/IX7zm1t70Yujpbk+zdPq/u4soeFSknWFdXIFuWsBGBOUu/Tn/I6KHSKvSh91OiMuaSnYp3mtPt5IQ==} + '@typescript-eslint/typescript-estree@8.53.0': + resolution: {integrity: sha512-pw0c0Gdo7Z4xOG987u3nJ8akL9093yEEKv8QTJ+Bhkghj1xyj8cgPaavlr9rq8h7+s6plUJ4QJYw2gCZodqmGw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/utils@8.50.0': - resolution: {integrity: sha512-87KgUXET09CRjGCi2Ejxy3PULXna63/bMYv72tCAlDJC3Yqwln0HiFJ3VJMst2+mEtNtZu5oFvX4qJGjKsnAgg==} + '@typescript-eslint/utils@8.53.0': + resolution: {integrity: sha512-XDY4mXTez3Z1iRDI5mbRhH4DFSt46oaIFsLg+Zn97+sYrXACziXSQcSelMybnVZ5pa1P6xYkPr5cMJyunM1ZDA==} 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.50.0': - resolution: {integrity: sha512-Xzmnb58+Db78gT/CCj/PVCvK+zxbnsw6F+O1oheYszJbBSdEjVhQi3C/Xttzxgi/GLmpvOggRs1RFpiJ8+c34Q==} + '@typescript-eslint/visitor-keys@8.53.0': + resolution: {integrity: sha512-LZ2NqIHFhvFwxG0qZeLL9DvdNAHPGCY5dIRwBhyYeU+LfLhcStE1ImjsuTG/WaVh3XysGaeLW8Rqq7cGkPCFvw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@unrs/resolver-binding-android-arm-eabi@1.11.1': @@ -1568,8 +1430,8 @@ packages: vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 vue: ^3.2.25 - '@vitest/eslint-plugin@1.5.2': - resolution: {integrity: sha512-2t1F2iecXB/b1Ox4U137lhD3chihEE3dRVtu3qMD35tc6UqUjg1VGRJoS1AkFKwpT8zv8OQInzPQO06hrRkeqw==} + '@vitest/eslint-plugin@1.6.6': + resolution: {integrity: sha512-bwgQxQWRtnTVzsUHK824tBmHzjV0iTx3tZaiQIYDjX3SA7TsQS8CuDVqxXrRY3FaOUMgbGavesCxI9MOfFLm7Q==} engines: {node: '>=18'} peerDependencies: eslint: '>=8.57.0' @@ -1581,11 +1443,11 @@ packages: vitest: optional: true - '@vitest/expect@4.0.16': - resolution: {integrity: sha512-eshqULT2It7McaJkQGLkPjPjNph+uevROGuIMJdG3V+0BSR2w9u6J9Lwu+E8cK5TETlfou8GRijhafIMhXsimA==} + '@vitest/expect@4.0.17': + resolution: {integrity: sha512-mEoqP3RqhKlbmUmntNDDCJeTDavDR+fVYkSOw8qRwJFaW/0/5zA9zFeTrHqNtcmwh6j26yMmwx2PqUDPzt5ZAQ==} - '@vitest/mocker@4.0.16': - resolution: {integrity: sha512-yb6k4AZxJTB+q9ycAvsoxGn+j/po0UaPgajllBgt1PzoMAAmJGYFdDk0uCcRcxb3BrME34I6u8gHZTQlkqSZpg==} + '@vitest/mocker@4.0.17': + resolution: {integrity: sha512-+ZtQhLA3lDh1tI2wxe3yMsGzbp7uuJSWBM1iTIKCbppWTSBN09PUC+L+fyNlQApQoR+Ps8twt2pbSSXg2fQVEQ==} peerDependencies: msw: ^2.4.9 vite: ^6.0.0 || ^7.0.0-0 @@ -1595,66 +1457,61 @@ packages: vite: optional: true - '@vitest/pretty-format@4.0.16': - resolution: {integrity: sha512-eNCYNsSty9xJKi/UdVD8Ou16alu7AYiS2fCPRs0b1OdhJiV89buAXQLpTbe+X8V9L6qrs9CqyvU7OaAopJYPsA==} + '@vitest/pretty-format@4.0.17': + resolution: {integrity: sha512-Ah3VAYmjcEdHg6+MwFE17qyLqBHZ+ni2ScKCiW2XrlSBV4H3Z7vYfPfz7CWQ33gyu76oc0Ai36+kgLU3rfF4nw==} - '@vitest/runner@4.0.16': - resolution: {integrity: sha512-VWEDm5Wv9xEo80ctjORcTQRJ539EGPB3Pb9ApvVRAY1U/WkHXmmYISqU5E79uCwcW7xYUV38gwZD+RV755fu3Q==} + '@vitest/runner@4.0.17': + resolution: {integrity: sha512-JmuQyf8aMWoo/LmNFppdpkfRVHJcsgzkbCA+/Bk7VfNH7RE6Ut2qxegeyx2j3ojtJtKIbIGy3h+KxGfYfk28YQ==} - '@vitest/snapshot@4.0.16': - resolution: {integrity: sha512-sf6NcrYhYBsSYefxnry+DR8n3UV4xWZwWxYbCJUt2YdvtqzSPR7VfGrY0zsv090DAbjFZsi7ZaMi1KnSRyK1XA==} + '@vitest/snapshot@4.0.17': + resolution: {integrity: sha512-npPelD7oyL+YQM2gbIYvlavlMVWUfNNGZPcu0aEUQXt7FXTuqhmgiYupPnAanhKvyP6Srs2pIbWo30K0RbDtRQ==} - '@vitest/spy@4.0.16': - resolution: {integrity: sha512-4jIOWjKP0ZUaEmJm00E0cOBLU+5WE0BpeNr3XN6TEF05ltro6NJqHWxXD0kA8/Zc8Nh23AT8WQxwNG+WeROupw==} + '@vitest/spy@4.0.17': + resolution: {integrity: sha512-I1bQo8QaP6tZlTomQNWKJE6ym4SHf3oLS7ceNjozxxgzavRAgZDc06T7kD8gb9bXKEgcLNt00Z+kZO6KaJ62Ew==} - '@vitest/utils@4.0.16': - resolution: {integrity: sha512-h8z9yYhV3e1LEfaQ3zdypIrnAg/9hguReGZoS7Gl0aBG5xgA410zBqECqmaF/+RkTggRsfnzc1XaAHA6bmUufA==} + '@vitest/utils@4.0.17': + resolution: {integrity: sha512-RG6iy+IzQpa9SB8HAFHJ9Y+pTzI+h8553MrciN9eC6TFBErqrQaTas4vG+MVj8S4uKk8uTT2p0vgZPnTdxd96w==} - '@volar/language-core@2.4.26': - resolution: {integrity: sha512-hH0SMitMxnB43OZpyF1IFPS9bgb2I3bpCh76m2WEK7BE0A0EzpYsRp0CCH2xNKshr7kacU5TQBLYn4zj7CG60A==} + '@volar/language-core@2.4.27': + resolution: {integrity: sha512-DjmjBWZ4tJKxfNC1F6HyYERNHPYS7L7OPFyCrestykNdUZMFYzI9WTyvwPcaNaHlrEUwESHYsfEw3isInncZxQ==} - '@volar/source-map@2.4.26': - resolution: {integrity: sha512-JJw0Tt/kSFsIRmgTQF4JSt81AUSI1aEye5Zl65EeZ8H35JHnTvFGmpDOBn5iOxd48fyGE+ZvZBp5FcgAy/1Qhw==} + '@volar/source-map@2.4.27': + resolution: {integrity: sha512-ynlcBReMgOZj2i6po+qVswtDUeeBRCTgDurjMGShbm8WYZgJ0PA4RmtebBJ0BCYol1qPv3GQF6jK7C9qoVc7lg==} - '@volar/typescript@2.4.26': - resolution: {integrity: sha512-N87ecLD48Sp6zV9zID/5yuS1+5foj0DfuYGdQ6KHj/IbKvyKv1zNX6VCmnKYwtmHadEO6mFc2EKISiu3RDPAvA==} + '@volar/typescript@2.4.27': + resolution: {integrity: sha512-eWaYCcl/uAPInSK2Lze6IqVWaBu/itVqR5InXcHXFyles4zO++Mglt3oxdgj75BDcv1Knr9Y93nowS8U3wqhxg==} - '@vue/compiler-core@3.5.25': - resolution: {integrity: sha512-vay5/oQJdsNHmliWoZfHPoVZZRmnSWhug0BYT34njkYTPqClh3DNWLkZNJBVSjsNMrg0CCrBfoKkjZQPM/QVUw==} + '@vue/compiler-core@3.5.26': + resolution: {integrity: sha512-vXyI5GMfuoBCnv5ucIT7jhHKl55Y477yxP6fc4eUswjP8FG3FFVFd41eNDArR+Uk3QKn2Z85NavjaxLxOC19/w==} - '@vue/compiler-dom@3.5.25': - resolution: {integrity: sha512-4We0OAcMZsKgYoGlMjzYvaoErltdFI2/25wqanuTu+S4gismOTRTBPi4IASOjxWdzIwrYSjnqONfKvuqkXzE2Q==} + '@vue/compiler-dom@3.5.26': + resolution: {integrity: sha512-y1Tcd3eXs834QjswshSilCBnKGeQjQXB6PqFn/1nxcQw4pmG42G8lwz+FZPAZAby6gZeHSt/8LMPfZ4Rb+Bd/A==} - '@vue/compiler-sfc@3.5.25': - resolution: {integrity: sha512-PUgKp2rn8fFsI++lF2sO7gwO2d9Yj57Utr5yEsDf3GNaQcowCLKL7sf+LvVFvtJDXUp/03+dC6f2+LCv5aK1ag==} + '@vue/compiler-sfc@3.5.26': + resolution: {integrity: sha512-egp69qDTSEZcf4bGOSsprUr4xI73wfrY5oRs6GSgXFTiHrWj4Y3X5Ydtip9QMqiCMCPVwLglB9GBxXtTadJ3mA==} - '@vue/compiler-ssr@3.5.25': - resolution: {integrity: sha512-ritPSKLBcParnsKYi+GNtbdbrIE1mtuFEJ4U1sWeuOMlIziK5GtOL85t5RhsNy4uWIXPgk+OUdpnXiTdzn8o3A==} + '@vue/compiler-ssr@3.5.26': + resolution: {integrity: sha512-lZT9/Y0nSIRUPVvapFJEVDbEXruZh2IYHMk2zTtEgJSlP5gVOqeWXH54xDKAaFS4rTnDeDBQUYDtxKyoW9FwDw==} - '@vue/language-core@3.1.8': - resolution: {integrity: sha512-PfwAW7BLopqaJbneChNL6cUOTL3GL+0l8paYP5shhgY5toBNidWnMXWM+qDwL7MC9+zDtzCF2enT8r6VPu64iw==} + '@vue/language-core@3.2.2': + resolution: {integrity: sha512-5DAuhxsxBN9kbriklh3Q5AMaJhyOCNiQJvCskN9/30XOpdLiqZU9Q+WvjArP17ubdGEyZtBzlIeG5nIjEbNOrQ==} + + '@vue/reactivity@3.5.26': + resolution: {integrity: sha512-9EnYB1/DIiUYYnzlnUBgwU32NNvLp/nhxLXeWRhHUEeWNTn1ECxX8aGO7RTXeX6PPcxe3LLuNBFoJbV4QZ+CFQ==} + + '@vue/runtime-core@3.5.26': + resolution: {integrity: sha512-xJWM9KH1kd201w5DvMDOwDHYhrdPTrAatn56oB/LRG4plEQeZRQLw0Bpwih9KYoqmzaxF0OKSn6swzYi84e1/Q==} + + '@vue/runtime-dom@3.5.26': + resolution: {integrity: sha512-XLLd/+4sPC2ZkN/6+V4O4gjJu6kSDbHAChvsyWgm1oGbdSO3efvGYnm25yCjtFm/K7rrSDvSfPDgN1pHgS4VNQ==} + + '@vue/server-renderer@3.5.26': + resolution: {integrity: sha512-TYKLXmrwWKSodyVuO1WAubucd+1XlLg4set0YoV+Hu8Lo79mp/YMwWV5mC5FgtsDxX3qo1ONrxFaTP1OQgy1uA==} peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + vue: 3.5.26 - '@vue/reactivity@3.5.25': - resolution: {integrity: sha512-5xfAypCQepv4Jog1U4zn8cZIcbKKFka3AgWHEFQeK65OW+Ys4XybP6z2kKgws4YB43KGpqp5D/K3go2UPPunLA==} - - '@vue/runtime-core@3.5.25': - resolution: {integrity: sha512-Z751v203YWwYzy460bzsYQISDfPjHTl+6Zzwo/a3CsAf+0ccEjQ8c+0CdX1WsumRTHeywvyUFtW6KvNukT/smA==} - - '@vue/runtime-dom@3.5.25': - resolution: {integrity: sha512-a4WrkYFbb19i9pjkz38zJBg8wa/rboNERq3+hRRb0dHiJh13c+6kAbgqCPfMaJ2gg4weWD3APZswASOfmKwamA==} - - '@vue/server-renderer@3.5.25': - resolution: {integrity: sha512-UJaXR54vMG61i8XNIzTSf2Q7MOqZHpp8+x3XLGtE3+fL+nQd+k7O5+X3D/uWrnQXOdMw5VPih+Uremcw+u1woQ==} - peerDependencies: - vue: 3.5.25 - - '@vue/shared@3.5.25': - resolution: {integrity: sha512-AbOPdQQnAnzs58H2FrrDxYj/TJfmeS2jdfEEhgiKINy+bnOANmVizIEgq1r+C5zsbs6l1CCQxtcj71rwNQ4jWg==} + '@vue/shared@3.5.26': + resolution: {integrity: sha512-7Z6/y3uFI5PRoKeorTOSXKcDj0MSasfNNltcslbFrPpcw6aXRUALq4IfJlaTRspiWIUOEZbrpM+iQGmCOiWe4A==} '@webassemblyjs/ast@1.14.1': resolution: {integrity: sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==} @@ -1776,8 +1633,8 @@ packages: ajv@8.17.1: resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} - alien-signals@3.1.1: - resolution: {integrity: sha512-ogkIWbVrLwKtHY6oOAXaYkAxP+cTH7V5FZ5+Tm4NZFd8VDZ6uNMDrfzqctTZ42eTMCSR3ne3otpcxmqSnFfPYA==} + alien-signals@3.1.2: + resolution: {integrity: sha512-d9dYqZTS90WLiU0I5c6DHj/HcKkF8ZyGN3G5x8wSbslulz70KOxaqCT0hQCo9KOyhVqzqGojvNdJXoTumZOtcw==} ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} @@ -1823,8 +1680,8 @@ packages: resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} engines: {node: '>=8'} - asciinema-player@3.13.5: - resolution: {integrity: sha512-mgpJc9g6I+k4Tz5qVUNd0H+GoYlhiUwvlay6vD6IXiuiWOWhBOjxbvqQ1bcI/HPTrOYxhTyxZuzHIXM36Tw60Q==} + asciinema-player@3.14.0: + resolution: {integrity: sha512-44m3CpNavn8i7DSr/AeeV+rJpHpcqc/OCildCs9FAu5gnXB6XNBdbhfg6mHMG4uU3R1rxFNA3ZRTt8FMhHC48Q==} assertion-error@2.0.1: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} @@ -1842,8 +1699,8 @@ packages: engines: {node: '>= 4.5.0'} hasBin: true - axe-core@4.11.0: - resolution: {integrity: sha512-ilYanEU8vxxBexpJd8cWM4ElSQq4QctCLKih0TSfjIfCQTeyH/6zVrmIJfLPrKTKJRbiG+cfnZbQIjAlJmF1jQ==} + axe-core@4.11.1: + resolution: {integrity: sha512-BASOg+YwO2C+346x3LZOeoovTIoTrRqEsqMa6fmfAV0P+U9mFr9NsyOEpiYvFjbc64NMrSswhV50WdXzdb/Z5A==} engines: {node: '>=4'} axobject-query@4.1.0: @@ -1859,8 +1716,8 @@ packages: base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - baseline-browser-mapping@2.9.9: - resolution: {integrity: sha512-V8fbOCSeOFvlDj7LLChUcqbZrdKD9RU/VR260piF1790vT0mfLSwGc/Qzxv3IqiTukOpNtItePa0HBpMAj7MDg==} + baseline-browser-mapping@2.9.14: + resolution: {integrity: sha512-B0xUquLkiGLgHhpPBqvl7GWegWBUNuujQ6kXd/r1U38ElPT6Ok8KZ8e+FpUGEc2ZoRQUzq/aUnaKFc/svWUGSg==} hasBin: true big.js@5.2.2: @@ -1917,11 +1774,11 @@ packages: resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} engines: {node: '>= 6'} - caniuse-lite@1.0.30001760: - resolution: {integrity: sha512-7AAMPcueWELt1p3mi13HR/LHH0TJLT11cnwDJEs3xA4+CK/PLKeO9Kl1oru24htkyUKtkGCvAx4ohB0Ttry8Dw==} + caniuse-lite@1.0.30001764: + resolution: {integrity: sha512-9JGuzl2M+vPL+pz70gtMF9sHdMFbY9FJaQBi186cHKH3pSzDvzoUJUPV6fqiKIMyXbud9ZLg4F3Yza1vJ1+93g==} - chai@6.2.1: - resolution: {integrity: sha512-p4Z49OGG5W/WBCPSS/dH3jQ73kD6tiMmUM+bckNK6Jr5JHMG3k9bg/BvKR8lKmtVBKmOiuVaV2ws8s9oSbwysg==} + chai@6.2.2: + resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} engines: {node: '>=18'} chalk@4.1.2: @@ -2399,6 +2256,10 @@ packages: resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} engines: {node: '>=0.12'} + entities@7.0.0: + resolution: {integrity: sha512-FDWG5cmEYf2Z00IkYRhbFrwIwvdFKH07uV8dvNy0omp/Qb1xcyCWp2UDtcwJF4QZZvk0sLudP6/hAu42TaqVhQ==} + engines: {node: '>=0.12'} + env-paths@2.2.1: resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} engines: {node: '>=6'} @@ -2417,16 +2278,11 @@ packages: es-module-lexer@2.0.0: resolution: {integrity: sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==} - esbuild-loader@4.4.0: - resolution: {integrity: sha512-4J+hXTpTtEdzUNLoY8ReqDNJx2NoldfiljRCiKbeYUuZmVaiJeDqFgyAzz8uOopaekwRoCcqBFyEroGQLFVZ1g==} + esbuild-loader@4.4.2: + resolution: {integrity: sha512-8LdoT9sC7fzfvhxhsIAiWhzLJr9yT3ggmckXxsgvM07wgrRxhuT98XhLn3E7VczU5W5AFsPKv9DdWcZIubbWkQ==} peerDependencies: webpack: ^4.40.0 || ^5.0.0 - esbuild@0.25.12: - resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} - engines: {node: '>=18'} - hasBin: true - esbuild@0.27.2: resolution: {integrity: sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==} engines: {node: '>=18'} @@ -2568,8 +2424,8 @@ packages: resolution: {integrity: sha512-brcKcxGnISN2CcVhXJ/kEQlNa0MEfGRtwKtWA16SkqXHKitaKIMrfemJKLKX1YqDU5C/5JY3PvZXd5jEW04e0Q==} engines: {node: '>=5.0.0'} - eslint-plugin-playwright@2.4.0: - resolution: {integrity: sha512-MWNXfXlLfwXAjj4Z80PvCCFCXgCYy5OCHan57Z/beGrjkJ3maG1GanuGX8Ck6T6fagplBx2ZdkifxSfByftaTQ==} + eslint-plugin-playwright@2.5.0: + resolution: {integrity: sha512-1ckFw7Abdz+l23wtw5Tg4GTK3Y+MgEQQNjEr7FTJP3wwmIOj8DkbJ6G655aPc09c0Kfn/NoGA4xpMZzeSO4NWw==} engines: {node: '>=16.9.0'} peerDependencies: eslint: '>=8.40.0' @@ -2651,6 +2507,10 @@ packages: resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + eslint-visitor-keys@5.0.0: + resolution: {integrity: sha512-A0XeIi7CXU7nPlfHS9loMYEKxUaONu/hTEzHTGba9Huu94Cq1hPivf+DE5erJozZOky0LfvXAyrV/tcswpLI0Q==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + eslint@9.39.2: resolution: {integrity: sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -2665,8 +2525,12 @@ packages: resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - esquery@1.6.0: - resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} + espree@11.0.0: + resolution: {integrity: sha512-+gMeWRrIh/NsG+3NaLeWHuyeyk70p2tbvZIWBYcqQ4/7Xvars6GYTZNhF1sIeLcc6Wb11He5ffz3hsHyXFrw5A==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + esquery@1.7.0: + resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} engines: {node: '>=0.10'} esrecurse@4.3.0: @@ -2725,8 +2589,8 @@ packages: resolution: {integrity: sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==} engines: {node: '>= 4.9.1'} - fastq@1.19.1: - resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==} + fastq@1.20.1: + resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} fdir@6.5.0: resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} @@ -2834,6 +2698,10 @@ packages: resolution: {integrity: sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==} engines: {node: '>=18'} + globals@17.0.0: + resolution: {integrity: sha512-gv5BeD2EssA793rlFWVPMMCqefTlpusw6/2TbAVMy0FzcG8wKJn4O+NqJ4+XWmmwrayJgw5TzrmWjFgmz1XPqw==} + engines: {node: '>=18'} + globby@11.1.0: resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} engines: {node: '>=10'} @@ -2851,8 +2719,8 @@ packages: resolution: {integrity: sha512-tSQXBXS/MWQOn/RKckawJ61vvsDpCom87JgxiYdGwHdOa0ht0vzUWDlfioofFCRU0L+6NGDt6XzbgoJvZkMeRQ==} engines: {node: '>=0.8.0'} - happy-dom@20.0.11: - resolution: {integrity: sha512-QsCdAUHAmiDeKeaNojb1OHOPF7NjcWPBR7obdu3NwH2a/oyQaLg5d0aaCy/9My6CdPChYF07dvz5chaXBGaD4g==} + happy-dom@20.1.0: + resolution: {integrity: sha512-ebvqjBqzenBk2LjzNEAzoj7yhw7rW/R2/wVevMu6Mrq3MXtcI/RUz4+ozpcOcqVLEWPqLfg2v9EAU7fFXZUUJw==} engines: {node: '>=20.0.0'} has-flag@4.0.0: @@ -2862,12 +2730,12 @@ packages: hash-sum@2.0.0: resolution: {integrity: sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg==} - hashery@1.3.0: - resolution: {integrity: sha512-fWltioiy5zsSAs9ouEnvhsVJeAXRybGCNNv0lvzpzNOSDbULXRy7ivFWwCCv4I5Am6kSo75hmbsCduOoc2/K4w==} + hashery@1.4.0: + resolution: {integrity: sha512-Wn2i1In6XFxl8Az55kkgnFRiAlIAushzh26PTjL2AKtQcEfXrcLa7Hn5QOWGZEf3LU057P9TwwZjFyxfS1VuvQ==} engines: {node: '>=20'} - hookified@1.14.0: - resolution: {integrity: sha512-pi1ynXIMFx/uIIwpWJ/5CEtOHLGtnUB0WhGeeYT+fKcQ+WCQbm3/rrkAXnpfph++PgepNqPdTC2WTj8A6k6zoQ==} + hookified@1.15.0: + resolution: {integrity: sha512-51w+ZZGt7Zw5q7rM3nC4t3aLn/xvKDETsXqMczndvwyVQhAHfUmUuFBRFcos8Iyebtk7OAE9dL26wFNzZVVOkw==} html-tags@3.3.1: resolution: {integrity: sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==} @@ -3222,8 +3090,8 @@ packages: engines: {node: '>= 12'} hasBin: true - material-icon-theme@5.29.0: - resolution: {integrity: sha512-Kr6D+NgLCWYJjsTjGuIOoKUFG/uomUpLREhyV/9g4qWJMNfm7b1BYYMglRIdQg1IiY7WKqyTws8Ufsad6oFLUA==} + material-icon-theme@5.30.0: + resolution: {integrity: sha512-GAB9vZGEVBQWD7NfZpx6mzkV47IJ6MaSFRLTXIhk9eCKrHbT5BlCwkeieu1Db/hDJHrQ/n+RdMvGtZa70FCGCQ==} engines: {vscode: ^1.55.0} mathml-tag-names@2.1.3: @@ -3449,8 +3317,8 @@ packages: once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} - online-3d-viewer@0.17.0: - resolution: {integrity: sha512-CTymQf5hozDHCqgypWYTmwq6+moVyWSDZdCkSovGklipP1oQy7YCEupLvkmJjex27Sxeeyq2Q9GH3+cxKUwpvg==} + online-3d-viewer@0.18.0: + resolution: {integrity: sha512-y7ZlV/zkakNUyjqcXz6XecA7vXgLEUnaAey9tyx8o6/wcdV64RfjXAQOjGXGY2JOZoDi4Cg1ic9icSWMWAvRQA==} optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} @@ -3685,8 +3553,8 @@ packages: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} - prettier-linter-helpers@1.0.0: - resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==} + prettier-linter-helpers@1.0.1: + resolution: {integrity: sha512-SxToR7P8Y2lWmv/kTzVLC1t/GDI2WGjMwNhLLE9qtH8Q13C+aEmuRlzDst4Up4s0Wc8sF2M+J57iB3cMLqftfg==} engines: {node: '>=6.0.0'} prettier@3.7.4: @@ -3774,8 +3642,8 @@ packages: robust-predicates@3.0.2: resolution: {integrity: sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==} - rollup@4.53.5: - resolution: {integrity: sha512-iTNAbFSlRpcHeeWu73ywU/8KuU/LZmNCSxp6fjQkJBD3ivUb8tpDrXhIxEzA05HlYMEwmtaUnb3RP+YNv162OQ==} + rollup@4.55.1: + resolution: {integrity: sha512-wDv/Ht1BNHB4upNbK74s9usvl7hObDnvVzknxqY/E/O3X6rW1U1rV1aENEfJ54eFZDTNo7zv1f5N4edCluH7+A==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -3795,8 +3663,9 @@ packages: sax@1.2.4: resolution: {integrity: sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==} - sax@1.4.3: - resolution: {integrity: sha512-yqYn1JhPczigF94DMS+shiDMjDowYO6y9+wB/4WgO0Y19jWYk0lQ4tuG5KI7kj4FTp1wxPj5IFfcrz/s1c3jjQ==} + sax@1.4.4: + resolution: {integrity: sha512-1n3r/tGXO6b6VXMdFT54SHzT9ytu9yr7TaELowdYpMqY/Ao7EnlQGmAQ1+RatX7Tkkdm6hONI2owqNx2aZj5Sw==} + engines: {node: '>=11.0.0'} schema-utils@4.3.3: resolution: {integrity: sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==} @@ -3987,8 +3856,8 @@ packages: peerDependencies: stylelint: '>=7 <=16' - stylelint-value-no-unknown-custom-properties@6.0.1: - resolution: {integrity: sha512-N60PTdaTknB35j6D4FhW0GL2LlBRV++bRpXMMldWMQZ240yFQaoltzlLY4lXXs7Z0J5mNUYZQ/gjyVtU2DhCMA==} + stylelint-value-no-unknown-custom-properties@6.1.0: + resolution: {integrity: sha512-fzc1ckeQZAlksMRzmWuyLywSRfaF9ys04qNg8+kTstUnZT0z8ajdMLjiPKtlcm4Nc5oDZE8tPVAcfFJB6E/1/A==} engines: {node: '>=18.12.0'} peerDependencies: stylelint: '>=16' @@ -4136,8 +4005,8 @@ packages: tributejs@5.1.3: resolution: {integrity: sha512-B5CXihaVzXw+1UHhNFyAwUTMDk1EfoLP5Tj1VhD9yybZ1I8DZJEv8tZ1l0RJo0t0tk9ZhR8eG5tEsaCvRigmdQ==} - ts-api-utils@2.1.0: - resolution: {integrity: sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==} + ts-api-utils@2.4.0: + resolution: {integrity: sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==} engines: {node: '>=18.12'} peerDependencies: typescript: '>=4.8.4' @@ -4159,8 +4028,8 @@ packages: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} - typescript-eslint@8.50.0: - resolution: {integrity: sha512-Q1/6yNUmCpH94fbgMUMg2/BSAr/6U7GBk61kZTv1/asghQOWOjTlp9K8mixS5NcJmm2creY+UFfGeW/+OcA64A==} + typescript-eslint@8.53.0: + resolution: {integrity: sha512-xHURCQNxZ1dsWn0sdOaOfCSQG0HKeqSj9OexIxrz6ypU6wHYOdX2I3D2b8s8wFSsSOYJb+6q283cLiLlkEsBYw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 @@ -4177,8 +4046,8 @@ packages: uc.micro@2.1.0: resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==} - ufo@1.6.1: - resolution: {integrity: sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==} + ufo@1.6.2: + resolution: {integrity: sha512-heMioaxBcG9+Znsda5Q8sQbWnLJSl98AFDXTO80wELWEzX3hordXsTdxrIfMQoO9IY1MEnoGoPjpoKpMj+Yx0Q==} uint8-to-base64@0.2.1: resolution: {integrity: sha512-uO/84GaoDUfiAxpa8EksjVLE77A9Kc7ZTziN4zRpq4de9yLaLcZn3jx1/sVjyupsywcVX6RKWbqLe7gUNyzH+Q==} @@ -4219,8 +4088,8 @@ packages: vite-string-plugin@1.4.9: resolution: {integrity: sha512-mO7PVkMs8+FuTK9ZjBBCRSjabC9cobvUEbN2EjWtGJo6nu35SbW99bYesOh5Ho39ug/KSbT4VwM4GPC26Xk/mQ==} - vite@7.3.0: - resolution: {integrity: sha512-dZwN5L1VlUBewiP6H9s2+B3e3Jg96D0vzN+Ry73sOefebhYr9f94wwkMNN/9ouoU8pV1BqA1d1zGk8928cx0rg==} + vite@7.3.1: + resolution: {integrity: sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: @@ -4259,18 +4128,18 @@ packages: yaml: optional: true - vitest@4.0.16: - resolution: {integrity: sha512-E4t7DJ9pESL6E3I8nFjPa4xGUd3PmiWDLsDztS2qXSJWfHtbQnwAWylaBvSNY48I3vr8PTqIZlyK8TE3V3CA4Q==} + vitest@4.0.17: + resolution: {integrity: sha512-FQMeF0DJdWY0iOnbv466n/0BudNdKj1l5jYgl5JVTwjSsZSlqyXFt/9+1sEyhR6CLowbZpV7O1sCHrzBhucKKg==} engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} hasBin: true peerDependencies: '@edge-runtime/vm': '*' '@opentelemetry/api': ^1.9.0 '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 - '@vitest/browser-playwright': 4.0.16 - '@vitest/browser-preview': 4.0.16 - '@vitest/browser-webdriverio': 4.0.16 - '@vitest/ui': 4.0.16 + '@vitest/browser-playwright': 4.0.17 + '@vitest/browser-preview': 4.0.17 + '@vitest/browser-webdriverio': 4.0.17 + '@vitest/ui': 4.0.17 happy-dom: '*' jsdom: '*' peerDependenciesMeta: @@ -4343,22 +4212,22 @@ packages: vue: optional: true - vue-tsc@3.1.8: - resolution: {integrity: sha512-deKgwx6exIHeZwF601P1ktZKNF0bepaSN4jBU3AsbldPx9gylUc1JDxYppl82yxgkAgaz0Y0LCLOi+cXe9HMYA==} + vue-tsc@3.2.2: + resolution: {integrity: sha512-r9YSia/VgGwmbbfC06hDdAatH634XJ9nVl6Zrnz1iK4ucp8Wu78kawplXnIDa3MSu1XdQQePTHLXYwPDWn+nyQ==} hasBin: true peerDependencies: typescript: '>=5.0.0' - vue@3.5.25: - resolution: {integrity: sha512-YLVdgv2K13WJ6n+kD5owehKtEXwdwXuj2TTyJMsO7pSeKw2bfRNZGjhB7YzrpbMYj5b5QsUebHpOqR3R3ziy/g==} + vue@3.5.26: + resolution: {integrity: sha512-SJ/NTccVyAoNUJmkM9KUqPcYlY+u8OVL1X5EW9RIs3ch5H2uERxyyIUI4MRxVCSOiEcupX9xNGde1tL9ZKpimA==} peerDependencies: typescript: '*' peerDependenciesMeta: typescript: optional: true - watchpack@2.4.4: - resolution: {integrity: sha512-c5EGNOiyxxV5qmTtAB7rbiXxi1ooX1pQKMLX/MIabJjRA0SJBQOjKF+KSVfHkr9U1cADPon0mRiVe/riyaiDUA==} + watchpack@2.5.0: + resolution: {integrity: sha512-e6vZvY6xboSwLz2GD36c16+O/2Z6fKvIf4pOXptw2rY9MVwE/TXc6RGqxD3I3x0a28lwBY7DE+76uTPSsBrrCA==} engines: {node: '>=10.13.0'} webidl-conversions@3.0.1: @@ -4389,8 +4258,8 @@ packages: resolution: {integrity: sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==} engines: {node: '>=10.13.0'} - webpack@5.104.0: - resolution: {integrity: sha512-5DeICTX8BVgNp6afSPYXAFjskIgWGlygQH58bcozPOXgo2r/6xx39Y1+cULZ3gTxUYQP88jmwLj2anu4Xaq84g==} + webpack@5.104.1: + resolution: {integrity: sha512-Qphch25abbMNtekmEGJmeRUhLDbe+QfiWTiqpKYkpCOWY64v9eyl+KRRLmqOFA2AvKPpc9DC6+u2n76tQLBoaA==} engines: {node: '>=10.13.0'} hasBin: true peerDependencies: @@ -4442,6 +4311,18 @@ packages: resolution: {integrity: sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + ws@8.19.0: + resolution: {integrity: sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + xml-lexer@0.2.2: resolution: {integrity: sha512-G0i98epIwiUEiKmMcavmVdhtymW+pCAohMRgybyIME9ygfVu8QheIi+YoQh3ngiThsT0SQzJT4R0sKDEv8Ou0w==} @@ -4470,7 +4351,7 @@ snapshots: package-manager-detector: 1.6.0 tinyexec: 1.0.2 - '@babel/code-frame@7.27.1': + '@babel/code-frame@7.28.6': dependencies: '@babel/helper-validator-identifier': 7.28.5 js-tokens: 4.0.0 @@ -4480,29 +4361,29 @@ snapshots: '@babel/helper-validator-identifier@7.28.5': {} - '@babel/parser@7.28.5': + '@babel/parser@7.28.6': dependencies: - '@babel/types': 7.28.5 + '@babel/types': 7.28.6 - '@babel/runtime@7.28.4': {} + '@babel/runtime@7.28.6': {} - '@babel/types@7.28.5': + '@babel/types@7.28.6': dependencies: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.28.5 '@braintree/sanitize-url@7.1.1': {} - '@cacheable/memory@2.0.6': + '@cacheable/memory@2.0.7': dependencies: - '@cacheable/utils': 2.3.2 + '@cacheable/utils': 2.3.3 '@keyv/bigmap': 1.3.0(keyv@5.5.5) - hookified: 1.14.0 + hookified: 1.15.0 keyv: 5.5.5 - '@cacheable/utils@2.3.2': + '@cacheable/utils@2.3.3': dependencies: - hashery: 1.3.0 + hashery: 1.4.0 keyv: 5.5.5 '@chevrotain/cst-dts-gen@11.0.3': @@ -4547,7 +4428,7 @@ snapshots: '@citation-js/date': 0.5.1 '@citation-js/plugin-yaml': 0.6.1 - '@citation-js/plugin-csl@0.7.21(@citation-js/core@0.7.21)': + '@citation-js/plugin-csl@0.7.22(@citation-js/core@0.7.21)': dependencies: '@citation-js/core': 0.7.21 '@citation-js/date': 0.5.1 @@ -4584,7 +4465,7 @@ snapshots: dependencies: '@csstools/css-tokenizer': 3.0.4 - '@csstools/css-syntax-patches-for-csstree@1.0.21': {} + '@csstools/css-syntax-patches-for-csstree@1.0.25': {} '@csstools/css-tokenizer@3.0.4': {} @@ -4601,13 +4482,13 @@ snapshots: '@dual-bundle/import-meta-resolve@4.2.1': {} - '@emnapi/core@1.7.1': + '@emnapi/core@1.8.1': dependencies: '@emnapi/wasi-threads': 1.1.0 tslib: 2.8.1 optional: true - '@emnapi/runtime@1.7.1': + '@emnapi/runtime@1.8.1': dependencies: tslib: 2.8.1 optional: true @@ -4617,159 +4498,81 @@ snapshots: tslib: 2.8.1 optional: true - '@esbuild/aix-ppc64@0.25.12': - optional: true - '@esbuild/aix-ppc64@0.27.2': optional: true - '@esbuild/android-arm64@0.25.12': - optional: true - '@esbuild/android-arm64@0.27.2': optional: true - '@esbuild/android-arm@0.25.12': - optional: true - '@esbuild/android-arm@0.27.2': optional: true - '@esbuild/android-x64@0.25.12': - optional: true - '@esbuild/android-x64@0.27.2': optional: true - '@esbuild/darwin-arm64@0.25.12': - optional: true - '@esbuild/darwin-arm64@0.27.2': optional: true - '@esbuild/darwin-x64@0.25.12': - optional: true - '@esbuild/darwin-x64@0.27.2': optional: true - '@esbuild/freebsd-arm64@0.25.12': - optional: true - '@esbuild/freebsd-arm64@0.27.2': optional: true - '@esbuild/freebsd-x64@0.25.12': - optional: true - '@esbuild/freebsd-x64@0.27.2': optional: true - '@esbuild/linux-arm64@0.25.12': - optional: true - '@esbuild/linux-arm64@0.27.2': optional: true - '@esbuild/linux-arm@0.25.12': - optional: true - '@esbuild/linux-arm@0.27.2': optional: true - '@esbuild/linux-ia32@0.25.12': - optional: true - '@esbuild/linux-ia32@0.27.2': optional: true - '@esbuild/linux-loong64@0.25.12': - optional: true - '@esbuild/linux-loong64@0.27.2': optional: true - '@esbuild/linux-mips64el@0.25.12': - optional: true - '@esbuild/linux-mips64el@0.27.2': optional: true - '@esbuild/linux-ppc64@0.25.12': - optional: true - '@esbuild/linux-ppc64@0.27.2': optional: true - '@esbuild/linux-riscv64@0.25.12': - optional: true - '@esbuild/linux-riscv64@0.27.2': optional: true - '@esbuild/linux-s390x@0.25.12': - optional: true - '@esbuild/linux-s390x@0.27.2': optional: true - '@esbuild/linux-x64@0.25.12': - optional: true - '@esbuild/linux-x64@0.27.2': optional: true - '@esbuild/netbsd-arm64@0.25.12': - optional: true - '@esbuild/netbsd-arm64@0.27.2': optional: true - '@esbuild/netbsd-x64@0.25.12': - optional: true - '@esbuild/netbsd-x64@0.27.2': optional: true - '@esbuild/openbsd-arm64@0.25.12': - optional: true - '@esbuild/openbsd-arm64@0.27.2': optional: true - '@esbuild/openbsd-x64@0.25.12': - optional: true - '@esbuild/openbsd-x64@0.27.2': optional: true - '@esbuild/openharmony-arm64@0.25.12': - optional: true - '@esbuild/openharmony-arm64@0.27.2': optional: true - '@esbuild/sunos-x64@0.25.12': - optional: true - '@esbuild/sunos-x64@0.27.2': optional: true - '@esbuild/win32-arm64@0.25.12': - optional: true - '@esbuild/win32-arm64@0.27.2': optional: true - '@esbuild/win32-ia32@0.25.12': - optional: true - '@esbuild/win32-ia32@0.27.2': optional: true - '@esbuild/win32-x64@0.25.12': - optional: true - '@esbuild/win32-x64@0.27.2': optional: true @@ -4779,7 +4582,7 @@ snapshots: eslint: 9.39.2(jiti@2.6.1) ignore: 5.3.2 - '@eslint-community/eslint-utils@4.9.0(eslint@9.39.2(jiti@2.6.1))': + '@eslint-community/eslint-utils@4.9.1(eslint@9.39.2(jiti@2.6.1))': dependencies: eslint: 9.39.2(jiti@2.6.1) eslint-visitor-keys: 3.4.3 @@ -4903,8 +4706,8 @@ snapshots: '@keyv/bigmap@1.3.0(keyv@5.5.5)': dependencies: - hashery: 1.3.0 - hookified: 1.14.0 + hashery: 1.4.0 + hookified: 1.15.0 keyv: 5.5.5 '@keyv/serialize@1.1.1': {} @@ -4923,8 +4726,8 @@ snapshots: '@napi-rs/wasm-runtime@0.2.12': dependencies: - '@emnapi/core': 1.7.1 - '@emnapi/runtime': 1.7.1 + '@emnapi/core': 1.8.1 + '@emnapi/runtime': 1.8.1 '@tybys/wasm-util': 0.10.1 optional: true @@ -4938,7 +4741,7 @@ snapshots: '@nodelib/fs.walk@1.2.8': dependencies: '@nodelib/fs.scandir': 2.1.5 - fastq: 1.19.1 + fastq: 1.20.1 '@nolyfill/array-includes@1.0.44': dependencies: @@ -5008,80 +4811,89 @@ snapshots: '@rolldown/pluginutils@1.0.0-beta.53': {} - '@rollup/rollup-android-arm-eabi@4.53.5': + '@rollup/rollup-android-arm-eabi@4.55.1': optional: true - '@rollup/rollup-android-arm64@4.53.5': + '@rollup/rollup-android-arm64@4.55.1': optional: true - '@rollup/rollup-darwin-arm64@4.53.5': + '@rollup/rollup-darwin-arm64@4.55.1': optional: true - '@rollup/rollup-darwin-x64@4.53.5': + '@rollup/rollup-darwin-x64@4.55.1': optional: true - '@rollup/rollup-freebsd-arm64@4.53.5': + '@rollup/rollup-freebsd-arm64@4.55.1': optional: true - '@rollup/rollup-freebsd-x64@4.53.5': + '@rollup/rollup-freebsd-x64@4.55.1': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.53.5': + '@rollup/rollup-linux-arm-gnueabihf@4.55.1': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.53.5': + '@rollup/rollup-linux-arm-musleabihf@4.55.1': optional: true - '@rollup/rollup-linux-arm64-gnu@4.53.5': + '@rollup/rollup-linux-arm64-gnu@4.55.1': optional: true - '@rollup/rollup-linux-arm64-musl@4.53.5': + '@rollup/rollup-linux-arm64-musl@4.55.1': optional: true - '@rollup/rollup-linux-loong64-gnu@4.53.5': + '@rollup/rollup-linux-loong64-gnu@4.55.1': optional: true - '@rollup/rollup-linux-ppc64-gnu@4.53.5': + '@rollup/rollup-linux-loong64-musl@4.55.1': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.53.5': + '@rollup/rollup-linux-ppc64-gnu@4.55.1': optional: true - '@rollup/rollup-linux-riscv64-musl@4.53.5': + '@rollup/rollup-linux-ppc64-musl@4.55.1': optional: true - '@rollup/rollup-linux-s390x-gnu@4.53.5': + '@rollup/rollup-linux-riscv64-gnu@4.55.1': optional: true - '@rollup/rollup-linux-x64-gnu@4.53.5': + '@rollup/rollup-linux-riscv64-musl@4.55.1': optional: true - '@rollup/rollup-linux-x64-musl@4.53.5': + '@rollup/rollup-linux-s390x-gnu@4.55.1': optional: true - '@rollup/rollup-openharmony-arm64@4.53.5': + '@rollup/rollup-linux-x64-gnu@4.55.1': optional: true - '@rollup/rollup-win32-arm64-msvc@4.53.5': + '@rollup/rollup-linux-x64-musl@4.55.1': optional: true - '@rollup/rollup-win32-ia32-msvc@4.53.5': + '@rollup/rollup-openbsd-x64@4.55.1': optional: true - '@rollup/rollup-win32-x64-gnu@4.53.5': + '@rollup/rollup-openharmony-arm64@4.55.1': optional: true - '@rollup/rollup-win32-x64-msvc@4.53.5': + '@rollup/rollup-win32-arm64-msvc@4.55.1': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.55.1': + optional: true + + '@rollup/rollup-win32-x64-gnu@4.55.1': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.55.1': optional: true '@rtsao/scc@1.1.0': {} '@scarf/scarf@1.4.0': {} - '@silverwind/vue3-calendar-heatmap@2.1.1(tippy.js@6.3.7)(vue@3.5.25(typescript@5.9.3))': + '@silverwind/vue3-calendar-heatmap@2.1.1(tippy.js@6.3.7)(vue@3.5.26(typescript@5.9.3))': dependencies: tippy.js: 6.3.7 - vue: 3.5.25(typescript@5.9.3) + vue: 3.5.26(typescript@5.9.3) '@simonwep/pickr@1.9.0': dependencies: @@ -5103,13 +4915,13 @@ snapshots: '@standard-schema/spec@1.1.0': {} - '@stylistic/eslint-plugin@5.6.1(eslint@9.39.2(jiti@2.6.1))': + '@stylistic/eslint-plugin@5.7.0(eslint@9.39.2(jiti@2.6.1))': dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.2(jiti@2.6.1)) - '@typescript-eslint/types': 8.50.0 + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)) + '@typescript-eslint/types': 8.53.0 eslint: 9.39.2(jiti@2.6.1) - eslint-visitor-keys: 4.2.1 - espree: 10.4.0 + eslint-visitor-keys: 5.0.0 + espree: 11.0.0 estraverse: 5.3.0 picomatch: 4.0.3 @@ -5126,7 +4938,7 @@ snapshots: '@swc/helpers@0.2.14': {} - '@techknowlogick/license-checker-webpack-plugin@0.3.0(webpack@5.104.0)': + '@techknowlogick/license-checker-webpack-plugin@0.3.0(webpack@5.104.1)': dependencies: glob: 7.2.3 lodash: 4.17.21 @@ -5135,7 +4947,7 @@ snapshots: spdx-expression-validate: 2.0.0 spdx-satisfies: 5.0.1 superstruct: 0.10.13 - webpack: 5.104.0(webpack-cli@6.0.1) + webpack: 5.104.1(webpack-cli@6.0.1) webpack-sources: 1.4.3 wrap-ansi: 6.2.0 @@ -5218,7 +5030,7 @@ snapshots: '@types/d3-selection@3.0.11': {} - '@types/d3-shape@3.1.7': + '@types/d3-shape@3.1.8': dependencies: '@types/d3-path': 3.1.1 @@ -5263,7 +5075,7 @@ snapshots: '@types/d3-scale': 4.0.9 '@types/d3-scale-chromatic': 3.1.0 '@types/d3-selection': 3.0.11 - '@types/d3-shape': 3.1.7 + '@types/d3-shape': 3.1.8 '@types/d3-time': 3.0.4 '@types/d3-time-format': 4.0.3 '@types/d3-timer': 3.0.2 @@ -5304,17 +5116,17 @@ snapshots: '@types/json5@0.0.29': {} - '@types/katex@0.16.7': {} + '@types/katex@0.16.8': {} '@types/marked@4.3.2': {} '@types/ms@2.1.0': {} - '@types/node@20.19.27': + '@types/node@20.19.28': dependencies: undici-types: 6.21.0 - '@types/node@25.0.3': + '@types/node@25.0.6': dependencies: undici-types: 7.16.0 @@ -5343,95 +5155,99 @@ snapshots: '@types/whatwg-mimetype@3.0.2': {} - '@typescript-eslint/eslint-plugin@8.50.0(@typescript-eslint/parser@8.50.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': + '@types/ws@8.18.1': + dependencies: + '@types/node': 20.19.28 + + '@typescript-eslint/eslint-plugin@8.53.0(@typescript-eslint/parser@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.50.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.50.0 - '@typescript-eslint/type-utils': 8.50.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/utils': 8.50.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.50.0 + '@typescript-eslint/parser': 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.53.0 + '@typescript-eslint/type-utils': 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/utils': 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.53.0 eslint: 9.39.2(jiti@2.6.1) ignore: 7.0.5 natural-compare: 1.4.0 - ts-api-utils: 2.1.0(typescript@5.9.3) + ts-api-utils: 2.4.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.50.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/parser@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': dependencies: - '@typescript-eslint/scope-manager': 8.50.0 - '@typescript-eslint/types': 8.50.0 - '@typescript-eslint/typescript-estree': 8.50.0(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.50.0 + '@typescript-eslint/scope-manager': 8.53.0 + '@typescript-eslint/types': 8.53.0 + '@typescript-eslint/typescript-estree': 8.53.0(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.53.0 debug: 4.4.3 eslint: 9.39.2(jiti@2.6.1) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.50.0(typescript@5.9.3)': + '@typescript-eslint/project-service@8.53.0(typescript@5.9.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.50.0(typescript@5.9.3) - '@typescript-eslint/types': 8.50.0 + '@typescript-eslint/tsconfig-utils': 8.53.0(typescript@5.9.3) + '@typescript-eslint/types': 8.53.0 debug: 4.4.3 typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@8.50.0': + '@typescript-eslint/scope-manager@8.53.0': dependencies: - '@typescript-eslint/types': 8.50.0 - '@typescript-eslint/visitor-keys': 8.50.0 + '@typescript-eslint/types': 8.53.0 + '@typescript-eslint/visitor-keys': 8.53.0 - '@typescript-eslint/tsconfig-utils@8.50.0(typescript@5.9.3)': + '@typescript-eslint/tsconfig-utils@8.53.0(typescript@5.9.3)': dependencies: typescript: 5.9.3 - '@typescript-eslint/type-utils@8.50.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/type-utils@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': dependencies: - '@typescript-eslint/types': 8.50.0 - '@typescript-eslint/typescript-estree': 8.50.0(typescript@5.9.3) - '@typescript-eslint/utils': 8.50.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/types': 8.53.0 + '@typescript-eslint/typescript-estree': 8.53.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) debug: 4.4.3 eslint: 9.39.2(jiti@2.6.1) - ts-api-utils: 2.1.0(typescript@5.9.3) + ts-api-utils: 2.4.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/types@8.50.0': {} + '@typescript-eslint/types@8.53.0': {} - '@typescript-eslint/typescript-estree@8.50.0(typescript@5.9.3)': + '@typescript-eslint/typescript-estree@8.53.0(typescript@5.9.3)': dependencies: - '@typescript-eslint/project-service': 8.50.0(typescript@5.9.3) - '@typescript-eslint/tsconfig-utils': 8.50.0(typescript@5.9.3) - '@typescript-eslint/types': 8.50.0 - '@typescript-eslint/visitor-keys': 8.50.0 + '@typescript-eslint/project-service': 8.53.0(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.53.0(typescript@5.9.3) + '@typescript-eslint/types': 8.53.0 + '@typescript-eslint/visitor-keys': 8.53.0 debug: 4.4.3 minimatch: 9.0.5 semver: 7.7.3 tinyglobby: 0.2.15 - ts-api-utils: 2.1.0(typescript@5.9.3) + ts-api-utils: 2.4.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.50.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/utils@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.2(jiti@2.6.1)) - '@typescript-eslint/scope-manager': 8.50.0 - '@typescript-eslint/types': 8.50.0 - '@typescript-eslint/typescript-estree': 8.50.0(typescript@5.9.3) + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)) + '@typescript-eslint/scope-manager': 8.53.0 + '@typescript-eslint/types': 8.53.0 + '@typescript-eslint/typescript-estree': 8.53.0(typescript@5.9.3) eslint: 9.39.2(jiti@2.6.1) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@8.50.0': + '@typescript-eslint/visitor-keys@8.53.0': dependencies: - '@typescript-eslint/types': 8.50.0 + '@typescript-eslint/types': 8.53.0 eslint-visitor-keys: 4.2.1 '@unrs/resolver-binding-android-arm-eabi@1.11.1': @@ -5493,139 +5309,137 @@ snapshots: '@unrs/resolver-binding-win32-x64-msvc@1.11.1': optional: true - '@vitejs/plugin-vue@6.0.3(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(stylus@0.57.0)(terser@5.44.1)(yaml@2.8.2))(vue@3.5.25(typescript@5.9.3))': + '@vitejs/plugin-vue@6.0.3(vite@7.3.1(@types/node@25.0.6)(jiti@2.6.1)(stylus@0.57.0)(terser@5.44.1)(yaml@2.8.2))(vue@3.5.26(typescript@5.9.3))': dependencies: '@rolldown/pluginutils': 1.0.0-beta.53 - vite: 7.3.0(@types/node@25.0.3)(jiti@2.6.1)(stylus@0.57.0)(terser@5.44.1)(yaml@2.8.2) - vue: 3.5.25(typescript@5.9.3) + vite: 7.3.1(@types/node@25.0.6)(jiti@2.6.1)(stylus@0.57.0)(terser@5.44.1)(yaml@2.8.2) + vue: 3.5.26(typescript@5.9.3) - '@vitest/eslint-plugin@1.5.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)(vitest@4.0.16(@types/node@25.0.3)(happy-dom@20.0.11)(jiti@2.6.1)(stylus@0.57.0)(terser@5.44.1)(yaml@2.8.2))': + '@vitest/eslint-plugin@1.6.6(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)(vitest@4.0.17(@types/node@25.0.6)(happy-dom@20.1.0)(jiti@2.6.1)(stylus@0.57.0)(terser@5.44.1)(yaml@2.8.2))': dependencies: - '@typescript-eslint/scope-manager': 8.50.0 - '@typescript-eslint/utils': 8.50.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.53.0 + '@typescript-eslint/utils': 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) eslint: 9.39.2(jiti@2.6.1) optionalDependencies: typescript: 5.9.3 - vitest: 4.0.16(@types/node@25.0.3)(happy-dom@20.0.11)(jiti@2.6.1)(stylus@0.57.0)(terser@5.44.1)(yaml@2.8.2) + vitest: 4.0.17(@types/node@25.0.6)(happy-dom@20.1.0)(jiti@2.6.1)(stylus@0.57.0)(terser@5.44.1)(yaml@2.8.2) transitivePeerDependencies: - supports-color - '@vitest/expect@4.0.16': + '@vitest/expect@4.0.17': dependencies: '@standard-schema/spec': 1.1.0 '@types/chai': 5.2.3 - '@vitest/spy': 4.0.16 - '@vitest/utils': 4.0.16 - chai: 6.2.1 + '@vitest/spy': 4.0.17 + '@vitest/utils': 4.0.17 + chai: 6.2.2 tinyrainbow: 3.0.3 - '@vitest/mocker@4.0.16(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(stylus@0.57.0)(terser@5.44.1)(yaml@2.8.2))': + '@vitest/mocker@4.0.17(vite@7.3.1(@types/node@25.0.6)(jiti@2.6.1)(stylus@0.57.0)(terser@5.44.1)(yaml@2.8.2))': dependencies: - '@vitest/spy': 4.0.16 + '@vitest/spy': 4.0.17 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 7.3.0(@types/node@25.0.3)(jiti@2.6.1)(stylus@0.57.0)(terser@5.44.1)(yaml@2.8.2) + vite: 7.3.1(@types/node@25.0.6)(jiti@2.6.1)(stylus@0.57.0)(terser@5.44.1)(yaml@2.8.2) - '@vitest/pretty-format@4.0.16': + '@vitest/pretty-format@4.0.17': dependencies: tinyrainbow: 3.0.3 - '@vitest/runner@4.0.16': + '@vitest/runner@4.0.17': dependencies: - '@vitest/utils': 4.0.16 + '@vitest/utils': 4.0.17 pathe: 2.0.3 - '@vitest/snapshot@4.0.16': + '@vitest/snapshot@4.0.17': dependencies: - '@vitest/pretty-format': 4.0.16 + '@vitest/pretty-format': 4.0.17 magic-string: 0.30.21 pathe: 2.0.3 - '@vitest/spy@4.0.16': {} + '@vitest/spy@4.0.17': {} - '@vitest/utils@4.0.16': + '@vitest/utils@4.0.17': dependencies: - '@vitest/pretty-format': 4.0.16 + '@vitest/pretty-format': 4.0.17 tinyrainbow: 3.0.3 - '@volar/language-core@2.4.26': + '@volar/language-core@2.4.27': dependencies: - '@volar/source-map': 2.4.26 + '@volar/source-map': 2.4.27 - '@volar/source-map@2.4.26': {} + '@volar/source-map@2.4.27': {} - '@volar/typescript@2.4.26': + '@volar/typescript@2.4.27': dependencies: - '@volar/language-core': 2.4.26 + '@volar/language-core': 2.4.27 path-browserify: 1.0.1 vscode-uri: 3.1.0 - '@vue/compiler-core@3.5.25': + '@vue/compiler-core@3.5.26': dependencies: - '@babel/parser': 7.28.5 - '@vue/shared': 3.5.25 - entities: 4.5.0 + '@babel/parser': 7.28.6 + '@vue/shared': 3.5.26 + entities: 7.0.0 estree-walker: 2.0.2 source-map-js: 1.2.1 - '@vue/compiler-dom@3.5.25': + '@vue/compiler-dom@3.5.26': dependencies: - '@vue/compiler-core': 3.5.25 - '@vue/shared': 3.5.25 + '@vue/compiler-core': 3.5.26 + '@vue/shared': 3.5.26 - '@vue/compiler-sfc@3.5.25': + '@vue/compiler-sfc@3.5.26': dependencies: - '@babel/parser': 7.28.5 - '@vue/compiler-core': 3.5.25 - '@vue/compiler-dom': 3.5.25 - '@vue/compiler-ssr': 3.5.25 - '@vue/shared': 3.5.25 + '@babel/parser': 7.28.6 + '@vue/compiler-core': 3.5.26 + '@vue/compiler-dom': 3.5.26 + '@vue/compiler-ssr': 3.5.26 + '@vue/shared': 3.5.26 estree-walker: 2.0.2 magic-string: 0.30.21 postcss: 8.5.6 source-map-js: 1.2.1 - '@vue/compiler-ssr@3.5.25': + '@vue/compiler-ssr@3.5.26': dependencies: - '@vue/compiler-dom': 3.5.25 - '@vue/shared': 3.5.25 + '@vue/compiler-dom': 3.5.26 + '@vue/shared': 3.5.26 - '@vue/language-core@3.1.8(typescript@5.9.3)': + '@vue/language-core@3.2.2': dependencies: - '@volar/language-core': 2.4.26 - '@vue/compiler-dom': 3.5.25 - '@vue/shared': 3.5.25 - alien-signals: 3.1.1 + '@volar/language-core': 2.4.27 + '@vue/compiler-dom': 3.5.26 + '@vue/shared': 3.5.26 + alien-signals: 3.1.2 muggle-string: 0.4.1 path-browserify: 1.0.1 picomatch: 4.0.3 - optionalDependencies: - typescript: 5.9.3 - '@vue/reactivity@3.5.25': + '@vue/reactivity@3.5.26': dependencies: - '@vue/shared': 3.5.25 + '@vue/shared': 3.5.26 - '@vue/runtime-core@3.5.25': + '@vue/runtime-core@3.5.26': dependencies: - '@vue/reactivity': 3.5.25 - '@vue/shared': 3.5.25 + '@vue/reactivity': 3.5.26 + '@vue/shared': 3.5.26 - '@vue/runtime-dom@3.5.25': + '@vue/runtime-dom@3.5.26': dependencies: - '@vue/reactivity': 3.5.25 - '@vue/runtime-core': 3.5.25 - '@vue/shared': 3.5.25 + '@vue/reactivity': 3.5.26 + '@vue/runtime-core': 3.5.26 + '@vue/shared': 3.5.26 csstype: 3.2.3 - '@vue/server-renderer@3.5.25(vue@3.5.25(typescript@5.9.3))': + '@vue/server-renderer@3.5.26(vue@3.5.26(typescript@5.9.3))': dependencies: - '@vue/compiler-ssr': 3.5.25 - '@vue/shared': 3.5.25 - vue: 3.5.25(typescript@5.9.3) + '@vue/compiler-ssr': 3.5.26 + '@vue/shared': 3.5.26 + vue: 3.5.26(typescript@5.9.3) - '@vue/shared@3.5.25': {} + '@vue/shared@3.5.26': {} '@webassemblyjs/ast@1.14.1': dependencies: @@ -5703,20 +5517,20 @@ snapshots: '@webassemblyjs/ast': 1.14.1 '@xtuc/long': 4.2.2 - '@webpack-cli/configtest@3.0.1(webpack-cli@6.0.1)(webpack@5.104.0)': + '@webpack-cli/configtest@3.0.1(webpack-cli@6.0.1)(webpack@5.104.1)': dependencies: - webpack: 5.104.0(webpack-cli@6.0.1) - webpack-cli: 6.0.1(webpack@5.104.0) + webpack: 5.104.1(webpack-cli@6.0.1) + webpack-cli: 6.0.1(webpack@5.104.1) - '@webpack-cli/info@3.0.1(webpack-cli@6.0.1)(webpack@5.104.0)': + '@webpack-cli/info@3.0.1(webpack-cli@6.0.1)(webpack@5.104.1)': dependencies: - webpack: 5.104.0(webpack-cli@6.0.1) - webpack-cli: 6.0.1(webpack@5.104.0) + webpack: 5.104.1(webpack-cli@6.0.1) + webpack-cli: 6.0.1(webpack@5.104.1) - '@webpack-cli/serve@3.0.1(webpack-cli@6.0.1)(webpack@5.104.0)': + '@webpack-cli/serve@3.0.1(webpack-cli@6.0.1)(webpack@5.104.1)': dependencies: - webpack: 5.104.0(webpack-cli@6.0.1) - webpack-cli: 6.0.1(webpack@5.104.0) + webpack: 5.104.1(webpack-cli@6.0.1) + webpack-cli: 6.0.1(webpack@5.104.1) '@xtuc/ieee754@1.2.0': {} @@ -5732,9 +5546,9 @@ snapshots: acorn@8.15.0: {} - add-asset-webpack-plugin@3.1.1(webpack@5.104.0): + add-asset-webpack-plugin@3.1.1(webpack@5.104.1): optionalDependencies: - webpack: 5.104.0(webpack-cli@6.0.1) + webpack: 5.104.1(webpack-cli@6.0.1) ajv-formats@2.1.1(ajv@8.17.1): optionalDependencies: @@ -5759,7 +5573,7 @@ snapshots: json-schema-traverse: 1.0.0 require-from-string: 2.0.2 - alien-signals@3.1.1: {} + alien-signals@3.1.2: {} ansi-regex@5.0.1: {} @@ -5790,9 +5604,9 @@ snapshots: array-union@2.1.0: {} - asciinema-player@3.13.5: + asciinema-player@3.14.0: dependencies: - '@babel/runtime': 7.28.4 + '@babel/runtime': 7.28.6 solid-js: 1.9.10 solid-transition-group: 0.2.3(solid-js@1.9.10) @@ -5804,7 +5618,7 @@ snapshots: atob@2.1.2: {} - axe-core@4.11.0: {} + axe-core@4.11.1: {} axobject-query@4.1.0: {} @@ -5814,7 +5628,7 @@ snapshots: base64-js@1.5.1: {} - baseline-browser-mapping@2.9.9: {} + baseline-browser-mapping@2.9.14: {} big.js@5.2.2: {} @@ -5837,8 +5651,8 @@ snapshots: browserslist@4.28.1: dependencies: - baseline-browser-mapping: 2.9.9 - caniuse-lite: 1.0.30001760 + baseline-browser-mapping: 2.9.14 + caniuse-lite: 1.0.30001764 electron-to-chromium: 1.5.267 node-releases: 2.0.27 update-browserslist-db: 1.2.3(browserslist@4.28.1) @@ -5858,9 +5672,9 @@ snapshots: cacheable@2.3.1: dependencies: - '@cacheable/memory': 2.0.6 - '@cacheable/utils': 2.3.2 - hookified: 1.14.0 + '@cacheable/memory': 2.0.7 + '@cacheable/utils': 2.3.3 + hookified: 1.15.0 keyv: 5.5.5 qified: 0.5.3 @@ -5868,9 +5682,9 @@ snapshots: camelcase-css@2.0.1: {} - caniuse-lite@1.0.30001760: {} + caniuse-lite@1.0.30001764: {} - chai@6.2.1: {} + chai@6.2.2: {} chalk@4.1.2: dependencies: @@ -6017,7 +5831,7 @@ snapshots: css-functions-list@3.2.3: {} - css-loader@7.1.2(webpack@5.104.0): + css-loader@7.1.2(webpack@5.104.1): dependencies: icss-utils: 5.1.0(postcss@8.5.6) postcss: 8.5.6 @@ -6028,7 +5842,7 @@ snapshots: postcss-value-parser: 4.2.0 semver: 7.7.3 optionalDependencies: - webpack: 5.104.0(webpack-cli@6.0.1) + webpack: 5.104.1(webpack-cli@6.0.1) css-select@5.2.2: dependencies: @@ -6355,6 +6169,8 @@ snapshots: entities@4.5.0: {} + entities@7.0.0: {} + env-paths@2.2.1: {} envinfo@7.21.0: {} @@ -6367,43 +6183,14 @@ snapshots: es-module-lexer@2.0.0: {} - esbuild-loader@4.4.0(webpack@5.104.0): + esbuild-loader@4.4.2(webpack@5.104.1): dependencies: - esbuild: 0.25.12 + esbuild: 0.27.2 get-tsconfig: 4.13.0 loader-utils: 2.0.4 - webpack: 5.104.0(webpack-cli@6.0.1) + webpack: 5.104.1(webpack-cli@6.0.1) webpack-sources: 1.4.3 - esbuild@0.25.12: - optionalDependencies: - '@esbuild/aix-ppc64': 0.25.12 - '@esbuild/android-arm': 0.25.12 - '@esbuild/android-arm64': 0.25.12 - '@esbuild/android-x64': 0.25.12 - '@esbuild/darwin-arm64': 0.25.12 - '@esbuild/darwin-x64': 0.25.12 - '@esbuild/freebsd-arm64': 0.25.12 - '@esbuild/freebsd-x64': 0.25.12 - '@esbuild/linux-arm': 0.25.12 - '@esbuild/linux-arm64': 0.25.12 - '@esbuild/linux-ia32': 0.25.12 - '@esbuild/linux-loong64': 0.25.12 - '@esbuild/linux-mips64el': 0.25.12 - '@esbuild/linux-ppc64': 0.25.12 - '@esbuild/linux-riscv64': 0.25.12 - '@esbuild/linux-s390x': 0.25.12 - '@esbuild/linux-x64': 0.25.12 - '@esbuild/netbsd-arm64': 0.25.12 - '@esbuild/netbsd-x64': 0.25.12 - '@esbuild/openbsd-arm64': 0.25.12 - '@esbuild/openbsd-x64': 0.25.12 - '@esbuild/openharmony-arm64': 0.25.12 - '@esbuild/sunos-x64': 0.25.12 - '@esbuild/win32-arm64': 0.25.12 - '@esbuild/win32-ia32': 0.25.12 - '@esbuild/win32-x64': 0.25.12 - esbuild@0.27.2: optionalDependencies: '@esbuild/aix-ppc64': 0.27.2 @@ -6463,7 +6250,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@4.4.4(eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.50.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.2(jiti@2.6.1)))(eslint-plugin-import@2.32.0)(eslint@9.39.2(jiti@2.6.1)): + eslint-import-resolver-typescript@4.4.4(eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.2(jiti@2.6.1)))(eslint-plugin-import@2.32.0)(eslint@9.39.2(jiti@2.6.1)): dependencies: debug: 4.4.3 eslint: 9.39.2(jiti@2.6.1) @@ -6474,19 +6261,19 @@ snapshots: tinyglobby: 0.2.15 unrs-resolver: 1.11.1 optionalDependencies: - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.50.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@4.4.4)(eslint@9.39.2(jiti@2.6.1)) - eslint-plugin-import-x: 4.16.1(@typescript-eslint/utils@8.50.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.2(jiti@2.6.1)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@4.4.4)(eslint@9.39.2(jiti@2.6.1)) + eslint-plugin-import-x: 4.16.1(@typescript-eslint/utils@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.2(jiti@2.6.1)) transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.1(@typescript-eslint/parser@8.50.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@4.4.4)(eslint@9.39.2(jiti@2.6.1)): + eslint-module-utils@2.12.1(@typescript-eslint/parser@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@4.4.4)(eslint@9.39.2(jiti@2.6.1)): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 8.50.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/parser': 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) eslint: 9.39.2(jiti@2.6.1) 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.50.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.2(jiti@2.6.1)))(eslint-plugin-import@2.32.0)(eslint@9.39.2(jiti@2.6.1)) + eslint-import-resolver-typescript: 4.4.4(eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.2(jiti@2.6.1)))(eslint-plugin-import@2.32.0)(eslint@9.39.2(jiti@2.6.1)) transitivePeerDependencies: - supports-color @@ -6519,8 +6306,8 @@ snapshots: '@eslint/eslintrc': 3.3.3 '@eslint/js': 9.39.2 '@github/browserslist-config': 1.0.0 - '@typescript-eslint/eslint-plugin': 8.50.0(@typescript-eslint/parser@8.50.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/parser': 8.50.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/eslint-plugin': 8.53.0(@typescript-eslint/parser@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/parser': 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) aria-query: 5.3.2 eslint: 9.39.2(jiti@2.6.1) eslint-config-prettier: 10.1.8(eslint@9.39.2(jiti@2.6.1)) @@ -6528,7 +6315,7 @@ snapshots: eslint-plugin-eslint-comments: 3.2.0(eslint@9.39.2(jiti@2.6.1)) eslint-plugin-filenames: 1.3.2(eslint@9.39.2(jiti@2.6.1)) eslint-plugin-i18n-text: 1.0.1(eslint@9.39.2(jiti@2.6.1)) - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.50.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@4.4.4)(eslint@9.39.2(jiti@2.6.1)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@4.4.4)(eslint@9.39.2(jiti@2.6.1)) eslint-plugin-jsx-a11y: 6.10.2(eslint@9.39.2(jiti@2.6.1)) 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@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1))(prettier@3.7.4) @@ -6538,7 +6325,7 @@ snapshots: prettier: 3.7.4 svg-element-attributes: 1.3.1 typescript: 5.9.3 - typescript-eslint: 8.50.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + typescript-eslint: 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) transitivePeerDependencies: - '@types/eslint' - eslint-import-resolver-typescript @@ -6549,9 +6336,9 @@ snapshots: dependencies: eslint: 9.39.2(jiti@2.6.1) - eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.50.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.2(jiti@2.6.1)): + eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.2(jiti@2.6.1)): dependencies: - '@typescript-eslint/types': 8.50.0 + '@typescript-eslint/types': 8.53.0 comment-parser: 1.4.1 debug: 4.4.3 eslint: 9.39.2(jiti@2.6.1) @@ -6562,12 +6349,12 @@ snapshots: stable-hash-x: 0.2.0 unrs-resolver: 1.11.1 optionalDependencies: - '@typescript-eslint/utils': 8.50.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/utils': 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) eslint-import-resolver-node: 0.3.9 transitivePeerDependencies: - supports-color - eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.50.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@4.4.4)(eslint@9.39.2(jiti@2.6.1)): + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@4.4.4)(eslint@9.39.2(jiti@2.6.1)): dependencies: '@rtsao/scc': 1.1.0 array-includes: '@nolyfill/array-includes@1.0.44' @@ -6578,7 +6365,7 @@ snapshots: doctrine: 2.1.0 eslint: 9.39.2(jiti@2.6.1) eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.50.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@4.4.4)(eslint@9.39.2(jiti@2.6.1)) + eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@4.4.4)(eslint@9.39.2(jiti@2.6.1)) hasown: '@nolyfill/hasown@1.0.44' is-core-module: '@nolyfill/is-core-module@1.0.39' is-glob: 4.0.3 @@ -6590,7 +6377,7 @@ snapshots: string.prototype.trimend: '@nolyfill/string.prototype.trimend@1.0.44' tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 8.50.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/parser': 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack @@ -6602,7 +6389,7 @@ snapshots: array-includes: '@nolyfill/array-includes@1.0.44' array.prototype.flatmap: '@nolyfill/array.prototype.flatmap@1.0.44' ast-types-flow: 0.0.8 - axe-core: 4.11.0 + axe-core: 4.11.1 axobject-query: 4.1.0 damerau-levenshtein: 1.0.8 emoji-regex: 9.2.2 @@ -6617,7 +6404,7 @@ snapshots: eslint-plugin-no-only-tests@3.3.0: {} - eslint-plugin-playwright@2.4.0(eslint@9.39.2(jiti@2.6.1)): + eslint-plugin-playwright@2.5.0(eslint@9.39.2(jiti@2.6.1)): dependencies: eslint: 9.39.2(jiti@2.6.1) globals: 16.5.0 @@ -6626,7 +6413,7 @@ snapshots: dependencies: eslint: 9.39.2(jiti@2.6.1) prettier: 3.7.4 - prettier-linter-helpers: 1.0.0 + prettier-linter-helpers: 1.0.1 synckit: 0.11.11 optionalDependencies: '@types/eslint': 9.6.1 @@ -6634,7 +6421,7 @@ snapshots: eslint-plugin-regexp@2.10.0(eslint@9.39.2(jiti@2.6.1)): dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.2(jiti@2.6.1)) + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)) '@eslint-community/regexpp': 4.12.2 comment-parser: 1.4.1 eslint: 9.39.2(jiti@2.6.1) @@ -6660,14 +6447,14 @@ snapshots: eslint-plugin-unicorn@62.0.0(eslint@9.39.2(jiti@2.6.1)): dependencies: '@babel/helper-validator-identifier': 7.28.5 - '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.2(jiti@2.6.1)) + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)) '@eslint/plugin-kit': 0.4.1 change-case: 5.4.4 ci-info: 4.3.1 clean-regexp: 1.0.0 core-js-compat: 3.47.0 eslint: 9.39.2(jiti@2.6.1) - esquery: 1.6.0 + esquery: 1.7.0 find-up-simple: 1.0.1 globals: 16.5.0 indent-string: 5.0.0 @@ -6681,7 +6468,7 @@ snapshots: eslint-plugin-vue-scoped-css@2.12.0(eslint@9.39.2(jiti@2.6.1))(vue-eslint-parser@10.2.0(eslint@9.39.2(jiti@2.6.1))): dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.2(jiti@2.6.1)) + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)) eslint: 9.39.2(jiti@2.6.1) eslint-compat-utils: 0.6.5(eslint@9.39.2(jiti@2.6.1)) lodash: 4.17.21 @@ -6694,9 +6481,9 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-plugin-vue@10.6.2(@stylistic/eslint-plugin@5.6.1(eslint@9.39.2(jiti@2.6.1)))(@typescript-eslint/parser@8.50.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(vue-eslint-parser@10.2.0(eslint@9.39.2(jiti@2.6.1))): + eslint-plugin-vue@10.6.2(@stylistic/eslint-plugin@5.7.0(eslint@9.39.2(jiti@2.6.1)))(@typescript-eslint/parser@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(vue-eslint-parser@10.2.0(eslint@9.39.2(jiti@2.6.1))): dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.2(jiti@2.6.1)) + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)) eslint: 9.39.2(jiti@2.6.1) natural-compare: 1.4.0 nth-check: 2.1.1 @@ -6705,8 +6492,8 @@ snapshots: vue-eslint-parser: 10.2.0(eslint@9.39.2(jiti@2.6.1)) xml-name-validator: 4.0.0 optionalDependencies: - '@stylistic/eslint-plugin': 5.6.1(eslint@9.39.2(jiti@2.6.1)) - '@typescript-eslint/parser': 8.50.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@stylistic/eslint-plugin': 5.7.0(eslint@9.39.2(jiti@2.6.1)) + '@typescript-eslint/parser': 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) eslint-plugin-wc@3.0.2(eslint@9.39.2(jiti@2.6.1)): dependencies: @@ -6730,9 +6517,11 @@ snapshots: eslint-visitor-keys@4.2.1: {} + eslint-visitor-keys@5.0.0: {} + eslint@9.39.2(jiti@2.6.1): dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.2(jiti@2.6.1)) + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)) '@eslint-community/regexpp': 4.12.2 '@eslint/config-array': 0.21.1 '@eslint/config-helpers': 0.4.2 @@ -6752,7 +6541,7 @@ snapshots: eslint-scope: 8.4.0 eslint-visitor-keys: 4.2.1 espree: 10.4.0 - esquery: 1.6.0 + esquery: 1.7.0 esutils: 2.0.3 fast-deep-equal: 3.1.3 file-entry-cache: 8.0.0 @@ -6777,7 +6566,13 @@ snapshots: acorn-jsx: 5.3.2(acorn@8.15.0) eslint-visitor-keys: 4.2.1 - esquery@1.6.0: + espree@11.0.0: + dependencies: + acorn: 8.15.0 + acorn-jsx: 5.3.2(acorn@8.15.0) + eslint-visitor-keys: 5.0.0 + + esquery@1.7.0: dependencies: estraverse: 5.3.0 @@ -6823,7 +6618,7 @@ snapshots: fastest-levenshtein@1.0.16: {} - fastq@1.19.1: + fastq@1.20.1: dependencies: reusify: 1.1.0 @@ -6872,7 +6667,7 @@ snapshots: dependencies: cacheable: 2.3.1 flatted: 3.3.3 - hookified: 1.14.0 + hookified: 1.15.0 flat@5.0.2: {} @@ -6927,6 +6722,8 @@ snapshots: globals@16.5.0: {} + globals@17.0.0: {} + globby@11.1.0: dependencies: array-union: 2.1.0 @@ -6944,21 +6741,26 @@ snapshots: hammerjs@2.0.8: {} - happy-dom@20.0.11: + happy-dom@20.1.0: dependencies: - '@types/node': 20.19.27 + '@types/node': 20.19.28 '@types/whatwg-mimetype': 3.0.2 + '@types/ws': 8.18.1 whatwg-mimetype: 3.0.0 + ws: 8.19.0 + transitivePeerDependencies: + - bufferutil + - utf-8-validate has-flag@4.0.0: {} hash-sum@2.0.0: {} - hashery@1.3.0: + hashery@1.4.0: dependencies: - hookified: 1.14.0 + hookified: 1.15.0 - hookified@1.14.0: {} + hookified@1.15.0: {} html-tags@3.3.1: {} @@ -7073,7 +6875,7 @@ snapshots: jest-worker@27.5.1: dependencies: - '@types/node': 25.0.3 + '@types/node': 25.0.6 merge-stream: 2.0.0 supports-color: 8.1.1 @@ -7267,7 +7069,7 @@ snapshots: marked@4.3.0: {} - material-icon-theme@5.29.0: + material-icon-theme@5.30.0: dependencies: chroma-js: 3.2.0 events: 3.3.0 @@ -7368,7 +7170,7 @@ snapshots: micromark-extension-math@3.1.0: dependencies: - '@types/katex': 0.16.7 + '@types/katex': 0.16.8 devlop: 1.1.0 katex: 0.16.27 micromark-factory-space: 2.0.1 @@ -7494,11 +7296,11 @@ snapshots: dependencies: mime-db: 1.52.0 - mini-css-extract-plugin@2.9.4(webpack@5.104.0): + mini-css-extract-plugin@2.9.4(webpack@5.104.1): dependencies: schema-utils: 4.3.3 tapable: 2.3.0 - webpack: 5.104.0(webpack-cli@6.0.1) + webpack: 5.104.1(webpack-cli@6.0.1) minimatch@10.1.1: dependencies: @@ -7519,13 +7321,13 @@ snapshots: acorn: 8.15.0 pathe: 2.0.3 pkg-types: 1.3.1 - ufo: 1.6.1 + ufo: 1.6.2 - monaco-editor-webpack-plugin@7.1.1(monaco-editor@0.55.1)(webpack@5.104.0): + monaco-editor-webpack-plugin@7.1.1(monaco-editor@0.55.1)(webpack@5.104.1): dependencies: loader-utils: 2.0.4 monaco-editor: 0.55.1 - webpack: 5.104.0(webpack-cli@6.0.1) + webpack: 5.104.1(webpack-cli@6.0.1) monaco-editor@0.55.1: dependencies: @@ -7582,7 +7384,7 @@ snapshots: dependencies: wrappy: 1.0.2 - online-3d-viewer@0.17.0: + online-3d-viewer@0.18.0: dependencies: '@simonwep/pickr': 1.9.0 fflate: 0.8.2 @@ -7633,7 +7435,7 @@ snapshots: parse-json@5.2.0: dependencies: - '@babel/code-frame': 7.27.1 + '@babel/code-frame': 7.28.6 error-ex: 1.3.4 json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 @@ -7721,14 +7523,14 @@ snapshots: optionalDependencies: postcss: 8.5.6 - postcss-loader@8.2.0(postcss@8.5.6)(typescript@5.9.3)(webpack@5.104.0): + postcss-loader@8.2.0(postcss@8.5.6)(typescript@5.9.3)(webpack@5.104.1): dependencies: cosmiconfig: 9.0.0(typescript@5.9.3) jiti: 2.6.1 postcss: 8.5.6 semver: 7.7.3 optionalDependencies: - webpack: 5.104.0(webpack-cli@6.0.1) + webpack: 5.104.1(webpack-cli@6.0.1) transitivePeerDependencies: - typescript @@ -7802,7 +7604,7 @@ snapshots: prelude-ls@1.2.1: {} - prettier-linter-helpers@1.0.0: + prettier-linter-helpers@1.0.1: dependencies: fast-diff: 1.3.0 @@ -7814,7 +7616,7 @@ snapshots: qified@0.5.3: dependencies: - hookified: 1.14.0 + hookified: 1.15.0 queue-microtask@1.2.3: {} @@ -7873,32 +7675,35 @@ snapshots: robust-predicates@3.0.2: {} - rollup@4.53.5: + rollup@4.55.1: dependencies: '@types/estree': 1.0.8 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.53.5 - '@rollup/rollup-android-arm64': 4.53.5 - '@rollup/rollup-darwin-arm64': 4.53.5 - '@rollup/rollup-darwin-x64': 4.53.5 - '@rollup/rollup-freebsd-arm64': 4.53.5 - '@rollup/rollup-freebsd-x64': 4.53.5 - '@rollup/rollup-linux-arm-gnueabihf': 4.53.5 - '@rollup/rollup-linux-arm-musleabihf': 4.53.5 - '@rollup/rollup-linux-arm64-gnu': 4.53.5 - '@rollup/rollup-linux-arm64-musl': 4.53.5 - '@rollup/rollup-linux-loong64-gnu': 4.53.5 - '@rollup/rollup-linux-ppc64-gnu': 4.53.5 - '@rollup/rollup-linux-riscv64-gnu': 4.53.5 - '@rollup/rollup-linux-riscv64-musl': 4.53.5 - '@rollup/rollup-linux-s390x-gnu': 4.53.5 - '@rollup/rollup-linux-x64-gnu': 4.53.5 - '@rollup/rollup-linux-x64-musl': 4.53.5 - '@rollup/rollup-openharmony-arm64': 4.53.5 - '@rollup/rollup-win32-arm64-msvc': 4.53.5 - '@rollup/rollup-win32-ia32-msvc': 4.53.5 - '@rollup/rollup-win32-x64-gnu': 4.53.5 - '@rollup/rollup-win32-x64-msvc': 4.53.5 + '@rollup/rollup-android-arm-eabi': 4.55.1 + '@rollup/rollup-android-arm64': 4.55.1 + '@rollup/rollup-darwin-arm64': 4.55.1 + '@rollup/rollup-darwin-x64': 4.55.1 + '@rollup/rollup-freebsd-arm64': 4.55.1 + '@rollup/rollup-freebsd-x64': 4.55.1 + '@rollup/rollup-linux-arm-gnueabihf': 4.55.1 + '@rollup/rollup-linux-arm-musleabihf': 4.55.1 + '@rollup/rollup-linux-arm64-gnu': 4.55.1 + '@rollup/rollup-linux-arm64-musl': 4.55.1 + '@rollup/rollup-linux-loong64-gnu': 4.55.1 + '@rollup/rollup-linux-loong64-musl': 4.55.1 + '@rollup/rollup-linux-ppc64-gnu': 4.55.1 + '@rollup/rollup-linux-ppc64-musl': 4.55.1 + '@rollup/rollup-linux-riscv64-gnu': 4.55.1 + '@rollup/rollup-linux-riscv64-musl': 4.55.1 + '@rollup/rollup-linux-s390x-gnu': 4.55.1 + '@rollup/rollup-linux-x64-gnu': 4.55.1 + '@rollup/rollup-linux-x64-musl': 4.55.1 + '@rollup/rollup-openbsd-x64': 4.55.1 + '@rollup/rollup-openharmony-arm64': 4.55.1 + '@rollup/rollup-win32-arm64-msvc': 4.55.1 + '@rollup/rollup-win32-ia32-msvc': 4.55.1 + '@rollup/rollup-win32-x64-gnu': 4.55.1 + '@rollup/rollup-win32-x64-msvc': 4.55.1 fsevents: 2.3.3 roughjs@4.6.6: @@ -7923,7 +7728,7 @@ snapshots: sax@1.2.4: {} - sax@1.4.3: {} + sax@1.4.4: {} schema-utils@4.3.3: dependencies: @@ -8092,7 +7897,7 @@ snapshots: dependencies: stylelint: 16.26.1(typescript@5.9.3) - stylelint-value-no-unknown-custom-properties@6.0.1(stylelint@16.26.1(typescript@5.9.3)): + stylelint-value-no-unknown-custom-properties@6.1.0(stylelint@16.26.1(typescript@5.9.3)): dependencies: postcss-value-parser: 4.2.0 resolve: 1.22.11 @@ -8101,7 +7906,7 @@ snapshots: stylelint@16.26.1(typescript@5.9.3): dependencies: '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) - '@csstools/css-syntax-patches-for-csstree': 1.0.21 + '@csstools/css-syntax-patches-for-csstree': 1.0.25 '@csstools/css-tokenizer': 3.0.4 '@csstools/media-query-list-parser': 4.0.3(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) '@csstools/selector-specificity': 5.0.0(postcss-selector-parser@7.1.1) @@ -8195,7 +8000,7 @@ snapshots: css-what: 6.2.2 csso: 5.0.5 picocolors: 1.1.1 - sax: 1.4.3 + sax: 1.4.4 svgson@5.3.1: dependencies: @@ -8254,14 +8059,14 @@ snapshots: tapable@2.3.0: {} - terser-webpack-plugin@5.3.16(webpack@5.104.0): + terser-webpack-plugin@5.3.16(webpack@5.104.1): dependencies: '@jridgewell/trace-mapping': 0.3.31 jest-worker: 27.5.1 schema-utils: 4.3.3 serialize-javascript: 6.0.2 terser: 5.44.1 - webpack: 5.104.0(webpack-cli@6.0.1) + webpack: 5.104.1(webpack-cli@6.0.1) terser@5.44.1: dependencies: @@ -8309,7 +8114,7 @@ snapshots: tributejs@5.1.3: {} - ts-api-utils@2.1.0(typescript@5.9.3): + ts-api-utils@2.4.0(typescript@5.9.3): dependencies: typescript: 5.9.3 @@ -8331,12 +8136,12 @@ snapshots: dependencies: prelude-ls: 1.2.1 - typescript-eslint@8.50.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3): + typescript-eslint@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.50.0(@typescript-eslint/parser@8.50.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/parser': 8.50.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/typescript-estree': 8.50.0(typescript@5.9.3) - '@typescript-eslint/utils': 8.50.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/eslint-plugin': 8.53.0(@typescript-eslint/parser@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/parser': 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/typescript-estree': 8.53.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) eslint: 9.39.2(jiti@2.6.1) typescript: 5.9.3 transitivePeerDependencies: @@ -8348,7 +8153,7 @@ snapshots: uc.micro@2.1.0: {} - ufo@1.6.1: {} + ufo@1.6.2: {} uint8-to-base64@0.2.1: {} @@ -8400,31 +8205,31 @@ snapshots: vite-string-plugin@1.4.9: {} - vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(stylus@0.57.0)(terser@5.44.1)(yaml@2.8.2): + vite@7.3.1(@types/node@25.0.6)(jiti@2.6.1)(stylus@0.57.0)(terser@5.44.1)(yaml@2.8.2): dependencies: esbuild: 0.27.2 fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 postcss: 8.5.6 - rollup: 4.53.5 + rollup: 4.55.1 tinyglobby: 0.2.15 optionalDependencies: - '@types/node': 25.0.3 + '@types/node': 25.0.6 fsevents: 2.3.3 jiti: 2.6.1 stylus: 0.57.0 terser: 5.44.1 yaml: 2.8.2 - vitest@4.0.16(@types/node@25.0.3)(happy-dom@20.0.11)(jiti@2.6.1)(stylus@0.57.0)(terser@5.44.1)(yaml@2.8.2): + vitest@4.0.17(@types/node@25.0.6)(happy-dom@20.1.0)(jiti@2.6.1)(stylus@0.57.0)(terser@5.44.1)(yaml@2.8.2): dependencies: - '@vitest/expect': 4.0.16 - '@vitest/mocker': 4.0.16(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(stylus@0.57.0)(terser@5.44.1)(yaml@2.8.2)) - '@vitest/pretty-format': 4.0.16 - '@vitest/runner': 4.0.16 - '@vitest/snapshot': 4.0.16 - '@vitest/spy': 4.0.16 - '@vitest/utils': 4.0.16 + '@vitest/expect': 4.0.17 + '@vitest/mocker': 4.0.17(vite@7.3.1(@types/node@25.0.6)(jiti@2.6.1)(stylus@0.57.0)(terser@5.44.1)(yaml@2.8.2)) + '@vitest/pretty-format': 4.0.17 + '@vitest/runner': 4.0.17 + '@vitest/snapshot': 4.0.17 + '@vitest/spy': 4.0.17 + '@vitest/utils': 4.0.17 es-module-lexer: 1.7.0 expect-type: 1.3.0 magic-string: 0.30.21 @@ -8436,11 +8241,11 @@ snapshots: tinyexec: 1.0.2 tinyglobby: 0.2.15 tinyrainbow: 3.0.3 - vite: 7.3.0(@types/node@25.0.3)(jiti@2.6.1)(stylus@0.57.0)(terser@5.44.1)(yaml@2.8.2) + vite: 7.3.1(@types/node@25.0.6)(jiti@2.6.1)(stylus@0.57.0)(terser@5.44.1)(yaml@2.8.2) why-is-node-running: 2.3.0 optionalDependencies: - '@types/node': 25.0.3 - happy-dom: 20.0.11 + '@types/node': 25.0.6 + happy-dom: 20.1.0 transitivePeerDependencies: - jiti - less @@ -8475,14 +8280,14 @@ snapshots: vue-bar-graph@2.2.0(typescript@5.9.3): dependencies: - vue: 3.5.25(typescript@5.9.3) + vue: 3.5.26(typescript@5.9.3) transitivePeerDependencies: - typescript - vue-chartjs@5.3.3(chart.js@4.5.1)(vue@3.5.25(typescript@5.9.3)): + vue-chartjs@5.3.3(chart.js@4.5.1)(vue@3.5.26(typescript@5.9.3)): dependencies: chart.js: 4.5.1 - vue: 3.5.25(typescript@5.9.3) + vue: 3.5.26(typescript@5.9.3) vue-eslint-parser@10.2.0(eslint@9.39.2(jiti@2.6.1)): dependencies: @@ -8491,49 +8296,49 @@ snapshots: eslint-scope: 8.4.0 eslint-visitor-keys: 4.2.1 espree: 10.4.0 - esquery: 1.6.0 + esquery: 1.7.0 semver: 7.7.3 transitivePeerDependencies: - supports-color - vue-loader@17.4.2(vue@3.5.25(typescript@5.9.3))(webpack@5.104.0): + vue-loader@17.4.2(vue@3.5.26(typescript@5.9.3))(webpack@5.104.1): dependencies: chalk: 4.1.2 hash-sum: 2.0.0 - watchpack: 2.4.4 - webpack: 5.104.0(webpack-cli@6.0.1) + watchpack: 2.5.0 + webpack: 5.104.1(webpack-cli@6.0.1) optionalDependencies: - vue: 3.5.25(typescript@5.9.3) + vue: 3.5.26(typescript@5.9.3) - vue-tsc@3.1.8(typescript@5.9.3): + vue-tsc@3.2.2(typescript@5.9.3): dependencies: - '@volar/typescript': 2.4.26 - '@vue/language-core': 3.1.8(typescript@5.9.3) + '@volar/typescript': 2.4.27 + '@vue/language-core': 3.2.2 typescript: 5.9.3 - vue@3.5.25(typescript@5.9.3): + vue@3.5.26(typescript@5.9.3): dependencies: - '@vue/compiler-dom': 3.5.25 - '@vue/compiler-sfc': 3.5.25 - '@vue/runtime-dom': 3.5.25 - '@vue/server-renderer': 3.5.25(vue@3.5.25(typescript@5.9.3)) - '@vue/shared': 3.5.25 + '@vue/compiler-dom': 3.5.26 + '@vue/compiler-sfc': 3.5.26 + '@vue/runtime-dom': 3.5.26 + '@vue/server-renderer': 3.5.26(vue@3.5.26(typescript@5.9.3)) + '@vue/shared': 3.5.26 optionalDependencies: typescript: 5.9.3 - watchpack@2.4.4: + watchpack@2.5.0: dependencies: glob-to-regexp: 0.4.1 graceful-fs: 4.2.11 webidl-conversions@3.0.1: {} - webpack-cli@6.0.1(webpack@5.104.0): + webpack-cli@6.0.1(webpack@5.104.1): dependencies: '@discoveryjs/json-ext': 0.6.3 - '@webpack-cli/configtest': 3.0.1(webpack-cli@6.0.1)(webpack@5.104.0) - '@webpack-cli/info': 3.0.1(webpack-cli@6.0.1)(webpack@5.104.0) - '@webpack-cli/serve': 3.0.1(webpack-cli@6.0.1)(webpack@5.104.0) + '@webpack-cli/configtest': 3.0.1(webpack-cli@6.0.1)(webpack@5.104.1) + '@webpack-cli/info': 3.0.1(webpack-cli@6.0.1)(webpack@5.104.1) + '@webpack-cli/serve': 3.0.1(webpack-cli@6.0.1)(webpack@5.104.1) colorette: 2.0.20 commander: 12.1.0 cross-spawn: 7.0.6 @@ -8542,7 +8347,7 @@ snapshots: import-local: 3.2.0 interpret: 3.1.1 rechoir: 0.8.0 - webpack: 5.104.0(webpack-cli@6.0.1) + webpack: 5.104.1(webpack-cli@6.0.1) webpack-merge: 6.0.1 webpack-merge@6.0.1: @@ -8558,7 +8363,7 @@ snapshots: webpack-sources@3.3.3: {} - webpack@5.104.0(webpack-cli@6.0.1): + webpack@5.104.1(webpack-cli@6.0.1): dependencies: '@types/eslint-scope': 3.7.7 '@types/estree': 1.0.8 @@ -8582,11 +8387,11 @@ snapshots: neo-async: 2.6.2 schema-utils: 4.3.3 tapable: 2.3.0 - terser-webpack-plugin: 5.3.16(webpack@5.104.0) - watchpack: 2.4.4 + terser-webpack-plugin: 5.3.16(webpack@5.104.1) + watchpack: 2.5.0 webpack-sources: 3.3.3 optionalDependencies: - webpack-cli: 6.0.1(webpack@5.104.0) + webpack-cli: 6.0.1(webpack@5.104.1) transitivePeerDependencies: - '@swc/core' - esbuild @@ -8635,6 +8440,8 @@ snapshots: imurmurhash: 0.1.4 signal-exit: 4.1.0 + ws@8.19.0: {} + xml-lexer@0.2.2: dependencies: eventemitter3: 2.0.3 diff --git a/web_src/js/features/admin/common.ts b/web_src/js/features/admin/common.ts index c019b80671..512acb792f 100644 --- a/web_src/js/features/admin/common.ts +++ b/web_src/js/features/admin/common.ts @@ -122,7 +122,7 @@ function initAdminAuthentication() { document.querySelector(`#oauth2_${custom}`)!.value = document.querySelector(`#${provider}_${custom}`)!.value; } const customInput = document.querySelector(`#${provider}_${custom}`); - if (customInput && customInput.getAttribute('data-available') === 'true') { + if (customInput?.getAttribute('data-available') === 'true') { for (const input of document.querySelectorAll(`.oauth2_${custom} input`)) { input.setAttribute('required', 'required'); } diff --git a/web_src/js/features/comp/ComboMarkdownEditor.ts b/web_src/js/features/comp/ComboMarkdownEditor.ts index 234a96b2af..46096ecac1 100644 --- a/web_src/js/features/comp/ComboMarkdownEditor.ts +++ b/web_src/js/features/comp/ComboMarkdownEditor.ts @@ -369,7 +369,7 @@ export class ComboMarkdownEditor { hideElem(this.textareaMarkdownToolbar); } - value(v: any = undefined) { + value(v?: any) { if (v === undefined) { if (this.easyMDE) { return this.easyMDE.value(); From e95c30eb809215db3ecf13a587598050f01a9e33 Mon Sep 17 00:00:00 2001 From: DHANUSH VANARASA <24215a0505@bvrit.ac.in> Date: Tue, 13 Jan 2026 17:43:57 +0530 Subject: [PATCH 09/23] Docs: minor punctuation improvement in CONTRIBUTING.md (#36291) --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9d696bf6b1..52e4aefb6b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -80,7 +80,7 @@ The more detailed and specific you are, the faster we can fix the issue. \ It is really helpful if you can reproduce your problem on a site running on the latest commits, i.e. , as perhaps your problem has already been fixed on a current version. \ Please follow the guidelines described in [How to Report Bugs Effectively](http://www.chiark.greenend.org.uk/~sgtatham/bugs.html) for your report. -Please be kind, remember that Gitea comes at no cost to you, and you're getting free help. +Please be kind—remember that Gitea comes at no cost to you, and you're getting free help. ### Types of issues From ed5720af2ac94d74f822721c05b42b6148ff9c22 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Tue, 13 Jan 2026 04:44:29 -0800 Subject: [PATCH 10/23] Fix openid setting check (#36346) --- models/user/openid.go | 12 +++++-- models/user/openid_test.go | 17 +++++++-- .../web/user/setting/security/main_test.go | 14 ++++++++ routers/web/user/setting/security/openid.go | 16 +++++++-- .../web/user/setting/security/openid_test.go | 36 +++++++++++++++++++ 5 files changed, 87 insertions(+), 8 deletions(-) create mode 100644 routers/web/user/setting/security/main_test.go create mode 100644 routers/web/user/setting/security/openid_test.go diff --git a/models/user/openid.go b/models/user/openid.go index 420c67ca18..5baa48c824 100644 --- a/models/user/openid.go +++ b/models/user/openid.go @@ -102,7 +102,13 @@ func DeleteUserOpenID(ctx context.Context, openid *UserOpenID) (err error) { } // ToggleUserOpenIDVisibility toggles visibility of an openid address of given user. -func ToggleUserOpenIDVisibility(ctx context.Context, id int64) (err error) { - _, err = db.GetEngine(ctx).Exec("update `user_open_id` set `show` = not `show` where `id` = ?", id) - return err +func ToggleUserOpenIDVisibility(ctx context.Context, id int64, user *User) error { + affected, err := db.GetEngine(ctx).Exec("update `user_open_id` set `show` = not `show` where `id` = ? AND uid = ?", id, user.ID) + if err != nil { + return err + } + if n, _ := affected.RowsAffected(); n != 1 { + return util.NewNotExistErrorf("OpenID is unknown") + } + return nil } diff --git a/models/user/openid_test.go b/models/user/openid_test.go index fa260e7a9e..6d2260324f 100644 --- a/models/user/openid_test.go +++ b/models/user/openid_test.go @@ -8,6 +8,7 @@ import ( "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/util" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -33,12 +34,14 @@ func TestGetUserOpenIDs(t *testing.T) { func TestToggleUserOpenIDVisibility(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) + user, err := user_model.GetUserByID(t.Context(), int64(2)) + require.NoError(t, err) oids, err := user_model.GetUserOpenIDs(t.Context(), int64(2)) require.NoError(t, err) require.Len(t, oids, 1) assert.True(t, oids[0].Show) - err = user_model.ToggleUserOpenIDVisibility(t.Context(), oids[0].ID) + err = user_model.ToggleUserOpenIDVisibility(t.Context(), oids[0].ID, user) require.NoError(t, err) oids, err = user_model.GetUserOpenIDs(t.Context(), int64(2)) @@ -46,7 +49,7 @@ func TestToggleUserOpenIDVisibility(t *testing.T) { require.Len(t, oids, 1) assert.False(t, oids[0].Show) - err = user_model.ToggleUserOpenIDVisibility(t.Context(), oids[0].ID) + err = user_model.ToggleUserOpenIDVisibility(t.Context(), oids[0].ID, user) require.NoError(t, err) oids, err = user_model.GetUserOpenIDs(t.Context(), int64(2)) @@ -55,3 +58,13 @@ func TestToggleUserOpenIDVisibility(t *testing.T) { assert.True(t, oids[0].Show) } } + +func TestToggleUserOpenIDVisibilityRequiresOwnership(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + unauthorizedUser, err := user_model.GetUserByID(t.Context(), int64(2)) + require.NoError(t, err) + + err = user_model.ToggleUserOpenIDVisibility(t.Context(), int64(1), unauthorizedUser) + require.Error(t, err) + assert.ErrorIs(t, err, util.ErrNotExist) +} diff --git a/routers/web/user/setting/security/main_test.go b/routers/web/user/setting/security/main_test.go new file mode 100644 index 0000000000..2a27cd6dbf --- /dev/null +++ b/routers/web/user/setting/security/main_test.go @@ -0,0 +1,14 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package security + +import ( + "testing" + + "code.gitea.io/gitea/models/unittest" +) + +func TestMain(m *testing.M) { + unittest.MainTest(m) +} diff --git a/routers/web/user/setting/security/openid.go b/routers/web/user/setting/security/openid.go index a23a98dd25..78db7650fe 100644 --- a/routers/web/user/setting/security/openid.go +++ b/routers/web/user/setting/security/openid.go @@ -4,12 +4,14 @@ package security import ( + "errors" "net/http" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/auth/openid" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/forms" @@ -116,7 +118,11 @@ func DeleteOpenID(ctx *context.Context) { } if err := user_model.DeleteUserOpenID(ctx, &user_model.UserOpenID{ID: ctx.FormInt64("id"), UID: ctx.Doer.ID}); err != nil { - ctx.ServerError("DeleteUserOpenID", err) + if errors.Is(err, util.ErrNotExist) { + ctx.HTTPError(http.StatusNotFound) + } else { + ctx.ServerError("DeleteUserOpenID", err) + } return } log.Trace("OpenID address deleted: %s", ctx.Doer.Name) @@ -132,8 +138,12 @@ func ToggleOpenIDVisibility(ctx *context.Context) { return } - if err := user_model.ToggleUserOpenIDVisibility(ctx, ctx.FormInt64("id")); err != nil { - ctx.ServerError("ToggleUserOpenIDVisibility", err) + if err := user_model.ToggleUserOpenIDVisibility(ctx, ctx.FormInt64("id"), ctx.Doer); err != nil { + if errors.Is(err, util.ErrNotExist) { + ctx.HTTPError(http.StatusNotFound) + } else { + ctx.ServerError("ToggleUserOpenIDVisibility", err) + } return } diff --git a/routers/web/user/setting/security/openid_test.go b/routers/web/user/setting/security/openid_test.go new file mode 100644 index 0000000000..860639ea1c --- /dev/null +++ b/routers/web/user/setting/security/openid_test.go @@ -0,0 +1,36 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package security + +import ( + "net/http" + "testing" + + "code.gitea.io/gitea/models/unittest" + "code.gitea.io/gitea/services/contexttest" + + "github.com/stretchr/testify/assert" +) + +func TestDeleteOpenIDReturnsNotFoundForOtherUsersAddress(t *testing.T) { + unittest.PrepareTestEnv(t) + ctx, _ := contexttest.MockContext(t, "POST /user/settings/security") + contexttest.LoadUser(t, ctx, 2) + ctx.SetFormString("id", "1") + + DeleteOpenID(ctx) + + assert.Equal(t, http.StatusNotFound, ctx.Resp.WrittenStatus()) +} + +func TestToggleOpenIDVisibilityReturnsNotFoundForOtherUsersAddress(t *testing.T) { + unittest.PrepareTestEnv(t) + ctx, _ := contexttest.MockContext(t, "POST /user/settings/security") + contexttest.LoadUser(t, ctx, 2) + ctx.SetFormString("id", "1") + + ToggleOpenIDVisibility(ctx) + + assert.Equal(t, http.StatusNotFound, ctx.Resp.WrittenStatus()) +} From 95ea2df00a70176c516b12f3cfee8c84a310280f Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Tue, 13 Jan 2026 05:13:39 -0800 Subject: [PATCH 11/23] Add more check for stopwatch read or list (#36340) --- models/issues/stopwatch.go | 13 ++++++ modules/eventsource/manager_run.go | 9 +++- routers/api/v1/repo/issue_stopwatch.go | 2 +- routers/web/user/stop_watch.go | 2 +- services/convert/issue.go | 23 +++++++++- services/convert/issue_test.go | 28 ++++++++++++ services/org/team_test.go | 31 +++++++++++++ services/repository/collaboration.go | 5 +++ services/repository/collaboration_test.go | 54 ++++++++++++++++++++++- 9 files changed, 160 insertions(+), 7 deletions(-) diff --git a/models/issues/stopwatch.go b/models/issues/stopwatch.go index 761b8f91a0..f119951b09 100644 --- a/models/issues/stopwatch.go +++ b/models/issues/stopwatch.go @@ -12,6 +12,8 @@ import ( user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/util" + + "xorm.io/builder" ) // Stopwatch represents a stopwatch for time tracking. @@ -232,3 +234,14 @@ func CancelStopwatch(ctx context.Context, user *user_model.User, issue *Issue) ( }) return ok, err } + +// RemoveStopwatchesByRepoID removes all stopwatches for a user in a specific repository +// this function should be called before removing all the issues of the repository +func RemoveStopwatchesByRepoID(ctx context.Context, userID, repoID int64) error { + _, err := db.GetEngine(ctx). + Where("`stopwatch`.user_id = ?", userID). + And(builder.In("`stopwatch`.issue_id", + builder.Select("id").From("issue").Where(builder.Eq{"repo_id": repoID}))). + Delete(new(Stopwatch)) + return err +} diff --git a/modules/eventsource/manager_run.go b/modules/eventsource/manager_run.go index f66dc78c7e..4a42224dda 100644 --- a/modules/eventsource/manager_run.go +++ b/modules/eventsource/manager_run.go @@ -9,6 +9,7 @@ import ( activities_model "code.gitea.io/gitea/models/activities" issues_model "code.gitea.io/gitea/models/issues" + user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/graceful" "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/log" @@ -91,7 +92,13 @@ loop: } for _, userStopwatches := range usersStopwatches { - apiSWs, err := convert.ToStopWatches(ctx, userStopwatches.StopWatches) + u, err := user_model.GetUserByID(ctx, userStopwatches.UserID) + if err != nil { + log.Error("Unable to get user %d: %v", userStopwatches.UserID, err) + continue + } + + apiSWs, err := convert.ToStopWatches(ctx, u, userStopwatches.StopWatches) if err != nil { if !issues_model.IsErrIssueNotExist(err) { log.Error("Unable to APIFormat stopwatches: %v", err) diff --git a/routers/api/v1/repo/issue_stopwatch.go b/routers/api/v1/repo/issue_stopwatch.go index 0f28b9757d..f9fbff091d 100644 --- a/routers/api/v1/repo/issue_stopwatch.go +++ b/routers/api/v1/repo/issue_stopwatch.go @@ -224,7 +224,7 @@ func GetStopwatches(ctx *context.APIContext) { return } - apiSWs, err := convert.ToStopWatches(ctx, sws) + apiSWs, err := convert.ToStopWatches(ctx, ctx.Doer, sws) if err != nil { ctx.APIErrorInternal(err) return diff --git a/routers/web/user/stop_watch.go b/routers/web/user/stop_watch.go index 1d1cc61cc9..4bd8841573 100644 --- a/routers/web/user/stop_watch.go +++ b/routers/web/user/stop_watch.go @@ -29,7 +29,7 @@ func GetStopwatches(ctx *context.Context) { return } - apiSWs, err := convert.ToStopWatches(ctx, sws) + apiSWs, err := convert.ToStopWatches(ctx, ctx.Doer, sws) if err != nil { ctx.HTTPError(http.StatusInternalServerError, err.Error()) return diff --git a/services/convert/issue.go b/services/convert/issue.go index e26412bcca..b396dd0737 100644 --- a/services/convert/issue.go +++ b/services/convert/issue.go @@ -10,6 +10,7 @@ import ( "strings" issues_model "code.gitea.io/gitea/models/issues" + access_model "code.gitea.io/gitea/models/perm/access" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/label" @@ -163,11 +164,12 @@ func ToTrackedTime(ctx context.Context, doer *user_model.User, t *issues_model.T } // ToStopWatches convert Stopwatch list to api.StopWatches -func ToStopWatches(ctx context.Context, sws []*issues_model.Stopwatch) (api.StopWatches, error) { +func ToStopWatches(ctx context.Context, doer *user_model.User, sws []*issues_model.Stopwatch) (api.StopWatches, error) { result := api.StopWatches(make([]api.StopWatch, 0, len(sws))) issueCache := make(map[int64]*issues_model.Issue) repoCache := make(map[int64]*repo_model.Repository) + permCache := make(map[int64]access_model.Permission) var ( issue *issues_model.Issue repo *repo_model.Repository @@ -182,13 +184,30 @@ func ToStopWatches(ctx context.Context, sws []*issues_model.Stopwatch) (api.Stop if err != nil { return nil, err } + issueCache[sw.IssueID] = issue } repo, ok = repoCache[issue.RepoID] if !ok { repo, err = repo_model.GetRepositoryByID(ctx, issue.RepoID) if err != nil { - return nil, err + log.Error("GetRepositoryByID(%d): %v", issue.RepoID, err) + continue } + repoCache[issue.RepoID] = repo + } + + // ADD: Check user permissions + perm, ok := permCache[repo.ID] + if !ok { + perm, err = access_model.GetUserRepoPermission(ctx, repo, doer) + if err != nil { + continue + } + permCache[repo.ID] = perm + } + + if !perm.CanReadIssuesOrPulls(issue.IsPull) { + continue } result = append(result, api.StopWatch{ diff --git a/services/convert/issue_test.go b/services/convert/issue_test.go index 4d780f3f00..a12a69288a 100644 --- a/services/convert/issue_test.go +++ b/services/convert/issue_test.go @@ -8,9 +8,11 @@ import ( "testing" "time" + "code.gitea.io/gitea/models/db" issues_model "code.gitea.io/gitea/models/issues" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" + user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/timeutil" @@ -55,3 +57,29 @@ func TestMilestone_APIFormat(t *testing.T) { Deadline: milestone.DeadlineUnix.AsTimePtr(), }, *ToAPIMilestone(milestone)) } + +func TestToStopWatchesRespectsPermissions(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + + ctx := t.Context() + publicSW := unittest.AssertExistsAndLoadBean(t, &issues_model.Stopwatch{ID: 1}) + privateIssue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{RepoID: 3}) + privateSW := &issues_model.Stopwatch{IssueID: privateIssue.ID, UserID: 5} + assert.NoError(t, db.Insert(ctx, privateSW)) + assert.NotZero(t, privateSW.ID) + + regularUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}) + adminUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) + + sws := []*issues_model.Stopwatch{publicSW, privateSW} + + visible, err := ToStopWatches(ctx, regularUser, sws) + assert.NoError(t, err) + assert.Len(t, visible, 1) + assert.Equal(t, "repo1", visible[0].RepoName) + + visibleAdmin, err := ToStopWatches(ctx, adminUser, sws) + assert.NoError(t, err) + assert.Len(t, visibleAdmin, 2) + assert.ElementsMatch(t, []string{"repo1", "repo3"}, []string{visibleAdmin[0].RepoName, visibleAdmin[1].RepoName}) +} diff --git a/services/org/team_test.go b/services/org/team_test.go index a5e01e7a54..5cb588b7dd 100644 --- a/services/org/team_test.go +++ b/services/org/team_test.go @@ -8,6 +8,7 @@ import ( "strings" "testing" + issues_model "code.gitea.io/gitea/models/issues" "code.gitea.io/gitea/models/organization" "code.gitea.io/gitea/models/perm" access_model "code.gitea.io/gitea/models/perm/access" @@ -62,6 +63,36 @@ func TestTeam_RemoveMember(t *testing.T) { assert.True(t, organization.IsErrLastOrgOwner(err)) } +func TestRemoveTeamMemberRemovesSubscriptionsAndStopwatches(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + + ctx := t.Context() + team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 2}) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}) + issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{RepoID: repo.ID}) + + assert.NoError(t, repo_model.WatchRepo(ctx, user, repo, true)) + assert.NoError(t, issues_model.CreateOrUpdateIssueWatch(ctx, user.ID, issue.ID, true)) + ok, err := issues_model.CreateIssueStopwatch(ctx, user, issue) + assert.NoError(t, err) + assert.True(t, ok) + + assert.NoError(t, RemoveTeamMember(ctx, team, user)) + + watch, err := repo_model.GetWatch(ctx, user.ID, repo.ID) + assert.NoError(t, err) + assert.False(t, repo_model.IsWatchMode(watch.Mode)) + + _, exists, err := issues_model.GetIssueWatch(ctx, user.ID, issue.ID) + assert.NoError(t, err) + assert.False(t, exists) + + hasStopwatch, _, _, err := issues_model.HasUserStopwatch(ctx, user.ID) + assert.NoError(t, err) + assert.False(t, hasStopwatch) +} + func TestNewTeam(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) diff --git a/services/repository/collaboration.go b/services/repository/collaboration.go index 53b3c2e203..cb56d90ae2 100644 --- a/services/repository/collaboration.go +++ b/services/repository/collaboration.go @@ -120,6 +120,11 @@ func ReconsiderWatches(ctx context.Context, repo *repo_model.Repository, user *u return err } + // Remove all stopwatches a user has running in the repository + if err := issues_model.RemoveStopwatchesByRepoID(ctx, user.ID, repo.ID); err != nil { + return err + } + // Remove all IssueWatches a user has subscribed to in the repository return issues_model.RemoveIssueWatchersByRepoID(ctx, user.ID, repo.ID) } diff --git a/services/repository/collaboration_test.go b/services/repository/collaboration_test.go index 5e33c50366..56d9d72e0a 100644 --- a/services/repository/collaboration_test.go +++ b/services/repository/collaboration_test.go @@ -6,7 +6,10 @@ package repository import ( "testing" + "code.gitea.io/gitea/models/db" + issues_model "code.gitea.io/gitea/models/issues" "code.gitea.io/gitea/models/perm" + access_model "code.gitea.io/gitea/models/perm/access" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" @@ -32,8 +35,8 @@ func TestRepository_AddCollaborator(t *testing.T) { func TestRepository_DeleteCollaboration(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4}) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 15}) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 22}) assert.NoError(t, repo.LoadOwner(t.Context())) assert.NoError(t, DeleteCollaboration(t.Context(), repo, user)) @@ -44,3 +47,50 @@ func TestRepository_DeleteCollaboration(t *testing.T) { unittest.CheckConsistencyFor(t, &repo_model.Repository{ID: repo.ID}) } + +func TestRepository_DeleteCollaborationRemovesSubscriptionsAndStopwatches(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + + ctx := t.Context() + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 15}) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 22}) + assert.NoError(t, repo.LoadOwner(ctx)) + assert.NoError(t, repo_model.WatchRepo(ctx, user, repo, true)) + + hasAccess, err := access_model.HasAnyUnitAccess(ctx, user.ID, repo) + assert.NoError(t, err) + assert.True(t, hasAccess) + + issueCount, err := db.GetEngine(ctx).Where("repo_id=?", repo.ID).Count(new(issues_model.Issue)) + assert.NoError(t, err) + tempIssue := &issues_model.Issue{ + RepoID: repo.ID, + Index: issueCount + 1, + PosterID: repo.OwnerID, + Title: "temp issue", + Content: "temp", + } + assert.NoError(t, db.Insert(ctx, tempIssue)) + assert.NoError(t, issues_model.CreateOrUpdateIssueWatch(ctx, user.ID, tempIssue.ID, true)) + ok, err := issues_model.CreateIssueStopwatch(ctx, user, tempIssue) + assert.NoError(t, err) + assert.True(t, ok) + + assert.NoError(t, DeleteCollaboration(ctx, repo, user)) + + hasAccess, err = access_model.HasAnyUnitAccess(ctx, user.ID, repo) + assert.NoError(t, err) + assert.False(t, hasAccess) + + watch, err := repo_model.GetWatch(ctx, user.ID, repo.ID) + assert.NoError(t, err) + assert.False(t, repo_model.IsWatchMode(watch.Mode)) + + _, exists, err := issues_model.GetIssueWatch(ctx, user.ID, tempIssue.ID) + assert.NoError(t, err) + assert.False(t, exists) + + hasStopwatch, _, _, err := issues_model.HasUserStopwatch(ctx, user.ID) + assert.NoError(t, err) + assert.False(t, hasStopwatch) +} From 1c1a7b8492d83310e129ae1faa1e9167d4c46577 Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Wed, 14 Jan 2026 23:35:52 +0800 Subject: [PATCH 12/23] Fix incorrect text content detection (#36364) Fix #36325 --- modules/typesniffer/typesniffer.go | 23 +++++++++++++++++++++++ modules/typesniffer/typesniffer_test.go | 23 +++++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/modules/typesniffer/typesniffer.go b/modules/typesniffer/typesniffer.go index 2e8d9c4a1e..0c4867d8f0 100644 --- a/modules/typesniffer/typesniffer.go +++ b/modules/typesniffer/typesniffer.go @@ -107,6 +107,17 @@ func detectFileTypeBox(data []byte) (brands []string, found bool) { return brands, true } +func isEmbeddedOpenType(data []byte) bool { + // https://www.w3.org/submissions/EOT + if len(data) < 80 { + return false + } + version := binary.LittleEndian.Uint32(data[8:]) // Actually this standard is abandoned (for IE6-IE11 only), there are only 3 versions defined + magic := binary.LittleEndian.Uint16(data[34:36]) // MagicNumber: 0x504C ("LP") + reserved := data[64:80] // Reserved 1-4 (each: unsigned long) + return (version == 0x00010000 || version == 0x00020001 || version == 0x00020002) && magic == 0x504C && bytes.Count(reserved, []byte{0}) == len(reserved) +} + // DetectContentType extends http.DetectContentType with more content types. Defaults to text/plain if input is empty. func DetectContentType(data []byte) SniffedType { if len(data) == 0 { @@ -119,6 +130,18 @@ func DetectContentType(data []byte) SniffedType { data = data[:SniffContentSize] } + const typeMsFontObject = "application/vnd.ms-fontobject" + if ct == typeMsFontObject { + // Stupid Golang blindly detects any content with 34th-35th bytes being "LP" as font. + // If it is not really for ".eot" content, we try to detect it again by hiding the "LP", see the test for more details. + if isEmbeddedOpenType(data) { + return SniffedType{typeMsFontObject} + } + data = slices.Clone(data) + data[34] = 'l' + ct = http.DetectContentType(data) + } + vars := globalVars() // SVG is unsupported by http.DetectContentType, https://github.com/golang/go/issues/15888 detectByHTML := strings.Contains(ct, "text/plain") || strings.Contains(ct, "text/html") diff --git a/modules/typesniffer/typesniffer_test.go b/modules/typesniffer/typesniffer_test.go index ad3f78afdc..17d67f41f7 100644 --- a/modules/typesniffer/typesniffer_test.go +++ b/modules/typesniffer/typesniffer_test.go @@ -6,6 +6,7 @@ package typesniffer import ( "encoding/base64" "encoding/hex" + "net/http" "strings" "testing" @@ -154,3 +155,25 @@ func TestDetectContentTypeAvif(t *testing.T) { st := DetectContentType(buf) assert.Equal(t, MimeTypeImageAvif, st.contentType) } + +func TestDetectContentTypeIncorrectFont(t *testing.T) { + s := "Stupid Golang keep detecting 34th LP as font" + // They don't want to have any improvement to it: https://github.com/golang/go/issues/77172 + golangDetected := http.DetectContentType([]byte(s)) + assert.Equal(t, "application/vnd.ms-fontobject", golangDetected) + // We have to make our patch to make it work correctly + ourDetected := DetectContentType([]byte(s)) + assert.Equal(t, "text/plain; charset=utf-8", ourDetected.contentType) + + // For binary content, ensure it still detects as font. The content is from "opensans-regular.eot" + b := []byte{ + 0x3d, 0x30, 0x00, 0x00, 0x6b, 0x2f, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x02, 0x0b, 0x06, 0x06, 0x03, 0x05, 0x04, 0x02, 0x02, 0x04, 0x01, 0x00, 0x90, 0x01, 0x00, 0x00, + 0x04, 0x00, 0x4c, 0x50, 0xef, 0x02, 0x00, 0xe0, 0x5b, 0x20, 0x00, 0x40, 0x28, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x9f, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x63, 0xf4, 0x17, 0x14, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x12, 0x00, 0x4f, 0x00, 0x70, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x20, 0x00, 0x53, 0x00, + } + assert.Equal(t, "application/vnd.ms-fontobject", http.DetectContentType(b)) + assert.Equal(t, "application/vnd.ms-fontobject", DetectContentType(b).contentType) +} From 8a98ac22131cffef3d8ea23701167098da2772b4 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Wed, 14 Jan 2026 08:11:22 -0800 Subject: [PATCH 13/23] clean watches when make a repository private and check permission when send release emails (#36319) --- models/repo/release.go | 22 +++++--- models/repo/watch.go | 10 ++++ models/repo/watch_test.go | 19 +++++++ services/mailer/mail_release.go | 13 +++++ services/mailer/mail_release_test.go | 71 ++++++++++++++++++++++++++ services/repository/repository.go | 4 ++ services/repository/repository_test.go | 22 ++++++++ 7 files changed, 153 insertions(+), 8 deletions(-) create mode 100644 services/mailer/mail_release_test.go diff --git a/models/repo/release.go b/models/repo/release.go index 67aa390e6d..05475899b8 100644 --- a/models/repo/release.go +++ b/models/repo/release.go @@ -93,15 +93,21 @@ func init() { db.RegisterModel(new(Release)) } -// LoadAttributes load repo and publisher attributes for a release -func (r *Release) LoadAttributes(ctx context.Context) error { - var err error - if r.Repo == nil { - r.Repo, err = GetRepositoryByID(ctx, r.RepoID) - if err != nil { - return err - } +func (r *Release) LoadRepo(ctx context.Context) (err error) { + if r.Repo != nil { + return nil } + + r.Repo, err = GetRepositoryByID(ctx, r.RepoID) + return err +} + +// LoadAttributes load repo and publisher attributes for a release +func (r *Release) LoadAttributes(ctx context.Context) (err error) { + if err := r.LoadRepo(ctx); err != nil { + return err + } + if r.Publisher == nil { r.Publisher, err = user_model.GetUserByID(ctx, r.PublisherID) if err != nil { diff --git a/models/repo/watch.go b/models/repo/watch.go index a616544cae..1e63d5c3d2 100644 --- a/models/repo/watch.go +++ b/models/repo/watch.go @@ -176,3 +176,13 @@ func WatchIfAuto(ctx context.Context, userID, repoID int64, isWrite bool) error } return watchRepoMode(ctx, watch, WatchModeAuto) } + +// ClearRepoWatches clears all watches for a repository and from the user that watched it. +// Used when a repository is set to private. +func ClearRepoWatches(ctx context.Context, repoID int64) error { + if _, err := db.Exec(ctx, "UPDATE `repository` SET num_watches = 0 WHERE id = ?", repoID); err != nil { + return err + } + + return db.DeleteBeans(ctx, Watch{RepoID: repoID}) +} diff --git a/models/repo/watch_test.go b/models/repo/watch_test.go index 19e363f6b0..97576fb787 100644 --- a/models/repo/watch_test.go +++ b/models/repo/watch_test.go @@ -13,6 +13,7 @@ import ( "code.gitea.io/gitea/modules/setting" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestIsWatching(t *testing.T) { @@ -119,3 +120,21 @@ func TestWatchIfAuto(t *testing.T) { assert.NoError(t, err) assert.Len(t, watchers, prevCount) } + +func TestClearRepoWatches(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + + const repoID int64 = 1 + watchers, err := repo_model.GetRepoWatchersIDs(t.Context(), repoID) + require.NoError(t, err) + require.NotEmpty(t, watchers) + + assert.NoError(t, repo_model.ClearRepoWatches(t.Context(), repoID)) + + watchers, err = repo_model.GetRepoWatchersIDs(t.Context(), repoID) + assert.NoError(t, err) + assert.Empty(t, watchers) + + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID}) + assert.Zero(t, repo.NumWatches) +} diff --git a/services/mailer/mail_release.go b/services/mailer/mail_release.go index 248cf0ab90..1f940f33df 100644 --- a/services/mailer/mail_release.go +++ b/services/mailer/mail_release.go @@ -7,9 +7,12 @@ import ( "bytes" "context" "fmt" + "slices" + access_model "code.gitea.io/gitea/models/perm/access" "code.gitea.io/gitea/models/renderhelper" repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/markup/markdown" @@ -44,6 +47,16 @@ func MailNewRelease(ctx context.Context, rel *repo_model.Release) { return } + if err := rel.LoadRepo(ctx); err != nil { + log.Error("rel.LoadRepo: %v", err) + return + } + + // delete publisher or any users with no permission + recipients = slices.DeleteFunc(recipients, func(u *user_model.User) bool { + return u.ID == rel.PublisherID || !access_model.CheckRepoUnitUser(ctx, rel.Repo, u, unit.TypeReleases) + }) + langMap := make(map[string][]*user_model.User) for _, user := range recipients { if user.ID != rel.PublisherID { diff --git a/services/mailer/mail_release_test.go b/services/mailer/mail_release_test.go new file mode 100644 index 0000000000..d078bdde74 --- /dev/null +++ b/services/mailer/mail_release_test.go @@ -0,0 +1,71 @@ +// Copyright 2026 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package mailer + +import ( + "testing" + + repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/models/unittest" + user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/setting" + sender_service "code.gitea.io/gitea/services/mailer/sender" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestMailNewReleaseFiltersUnauthorizedWatchers(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + + origMailService := setting.MailService + origDomain := setting.Domain + origAppName := setting.AppName + origAppURL := setting.AppURL + origTemplates := LoadedTemplates() + defer func() { + setting.MailService = origMailService + setting.Domain = origDomain + setting.AppName = origAppName + setting.AppURL = origAppURL + loadedTemplates.Store(origTemplates) + }() + + setting.MailService = &setting.Mailer{ + From: "Gitea", + FromEmail: "noreply@example.com", + } + setting.Domain = "example.com" + setting.AppName = "Gitea" + setting.AppURL = "https://example.com/" + prepareMailTemplates(string(tplNewReleaseMail), "{{.Subject}}", "

{{.Release.TagName}}

") + + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}) + require.True(t, repo.IsPrivate) + + admin := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) + unauthorized := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}) + + assert.NoError(t, repo_model.WatchRepo(t.Context(), admin, repo, true)) + assert.NoError(t, repo_model.WatchRepo(t.Context(), unauthorized, repo, true)) + + rel := unittest.AssertExistsAndLoadBean(t, &repo_model.Release{ID: 11}) + rel.Repo = nil + rel.Publisher = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: rel.PublisherID}) + + var sent []*sender_service.Message + origSend := SendAsync + SendAsync = func(msgs ...*sender_service.Message) { + sent = append(sent, msgs...) + } + defer func() { + SendAsync = origSend + }() + + MailNewRelease(t.Context(), rel) + + require.Len(t, sent, 1) + assert.Equal(t, admin.EmailTo(), sent[0].To) + assert.NotEqual(t, unauthorized.EmailTo(), sent[0].To) +} diff --git a/services/repository/repository.go b/services/repository/repository.go index 4d07cb0e38..21a75a559f 100644 --- a/services/repository/repository.go +++ b/services/repository/repository.go @@ -194,6 +194,10 @@ func MakeRepoPrivate(ctx context.Context, repo *repo_model.Repository) (err erro return err } + if err = repo_model.ClearRepoWatches(ctx, repo.ID); err != nil { + return err + } + // Create/Remove git-daemon-export-ok for git-daemon... if err := CheckDaemonExportOK(ctx, repo); err != nil { return err diff --git a/services/repository/repository_test.go b/services/repository/repository_test.go index 5673a4a161..cf7dd6b7ed 100644 --- a/services/repository/repository_test.go +++ b/services/repository/repository_test.go @@ -13,6 +13,7 @@ import ( "code.gitea.io/gitea/models/unittest" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestLinkedRepository(t *testing.T) { @@ -70,3 +71,24 @@ func TestRepository_HasWiki(t *testing.T) { repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}) assert.False(t, HasWiki(t.Context(), repo2)) } + +func TestMakeRepoPrivateClearsWatches(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) + repo.IsPrivate = false + + watchers, err := repo_model.GetRepoWatchersIDs(t.Context(), repo.ID) + require.NoError(t, err) + require.NotEmpty(t, watchers) + + assert.NoError(t, MakeRepoPrivate(t.Context(), repo)) + + watchers, err = repo_model.GetRepoWatchersIDs(t.Context(), repo.ID) + assert.NoError(t, err) + assert.Empty(t, watchers) + + updatedRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repo.ID}) + assert.True(t, updatedRepo.IsPrivate) + assert.Zero(t, updatedRepo.NumWatches) +} From 07ac29da320a237bb9a1527b64f04362cce51bd3 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Wed, 14 Jan 2026 08:56:23 -0800 Subject: [PATCH 14/23] Fix bug when compare in the pull request (#36363) The pull request comparison should not use `direct compare`. --- routers/api/v1/repo/pull.go | 4 ++-- services/pull/pull.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/routers/api/v1/repo/pull.go b/routers/api/v1/repo/pull.go index f33867f4ed..2f59bef7c7 100644 --- a/routers/api/v1/repo/pull.go +++ b/routers/api/v1/repo/pull.go @@ -1532,9 +1532,9 @@ func GetPullRequestFiles(ctx *context.APIContext) { var compareInfo *git_service.CompareInfo if pr.HasMerged { - compareInfo, err = git_service.GetCompareInfo(ctx, pr.BaseRepo, pr.BaseRepo, baseGitRepo, git.RefName(pr.MergeBase), git.RefName(pr.GetGitHeadRefName()), true, false) + compareInfo, err = git_service.GetCompareInfo(ctx, pr.BaseRepo, pr.BaseRepo, baseGitRepo, git.RefName(pr.MergeBase), git.RefName(pr.GetGitHeadRefName()), false, false) } else { - compareInfo, err = git_service.GetCompareInfo(ctx, pr.BaseRepo, pr.BaseRepo, baseGitRepo, git.RefNameFromBranch(pr.BaseBranch), git.RefName(pr.GetGitHeadRefName()), true, false) + compareInfo, err = git_service.GetCompareInfo(ctx, pr.BaseRepo, pr.BaseRepo, baseGitRepo, git.RefNameFromBranch(pr.BaseBranch), git.RefName(pr.GetGitHeadRefName()), false, false) } if err != nil { ctx.APIErrorInternal(err) diff --git a/services/pull/pull.go b/services/pull/pull.go index 7038285bd1..9b84e5c721 100644 --- a/services/pull/pull.go +++ b/services/pull/pull.go @@ -1077,7 +1077,7 @@ func GetPullCommits(ctx context.Context, baseGitRepo *git.Repository, doer *user if pull.HasMerged { baseBranch = pull.MergeBase } - compareInfo, err := git_service.GetCompareInfo(ctx, pull.BaseRepo, pull.BaseRepo, baseGitRepo, git.RefNameFromBranch(baseBranch), git.RefName(pull.GetGitHeadRefName()), true, false) + compareInfo, err := git_service.GetCompareInfo(ctx, pull.BaseRepo, pull.BaseRepo, baseGitRepo, git.RefNameFromBranch(baseBranch), git.RefName(pull.GetGitHeadRefName()), false, false) if err != nil { return nil, "", err } From 7b5de594cd92e30b9c3d40ffda119acad794cc64 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Wed, 14 Jan 2026 09:29:33 -0800 Subject: [PATCH 15/23] Fix permission check on org project operations (#36318) --- models/project/column.go | 12 ++++ models/project/project.go | 12 ++++ routers/web/org/projects.go | 99 +++++++++----------------------- routers/web/org/projects_test.go | 30 ++++++++++ 4 files changed, 82 insertions(+), 71 deletions(-) diff --git a/models/project/column.go b/models/project/column.go index 9b9d874997..79f6dfe911 100644 --- a/models/project/column.go +++ b/models/project/column.go @@ -213,6 +213,18 @@ func GetColumn(ctx context.Context, columnID int64) (*Column, error) { return column, nil } +func GetColumnByIDAndProjectID(ctx context.Context, columnID, projectID int64) (*Column, error) { + column := new(Column) + has, err := db.GetEngine(ctx).ID(columnID).And("project_id=?", projectID).Get(column) + if err != nil { + return nil, err + } else if !has { + return nil, ErrProjectColumnNotExist{ColumnID: columnID} + } + + return column, nil +} + // UpdateColumn updates a project column func UpdateColumn(ctx context.Context, column *Column) error { var fieldToUpdate []string diff --git a/models/project/project.go b/models/project/project.go index c003664fa3..7646c3dd71 100644 --- a/models/project/project.go +++ b/models/project/project.go @@ -302,6 +302,18 @@ func GetProjectByID(ctx context.Context, id int64) (*Project, error) { return p, nil } +func GetProjectByIDAndOwner(ctx context.Context, id, ownerID int64) (*Project, error) { + p := new(Project) + has, err := db.GetEngine(ctx).ID(id).And("owner_id = ?", ownerID).Get(p) + if err != nil { + return nil, err + } else if !has { + return nil, ErrProjectNotExist{ID: id} + } + + return p, nil +} + // GetProjectForRepoByID returns the projects in a repository func GetProjectForRepoByID(ctx context.Context, repoID, id int64) (*Project, error) { p := new(Project) diff --git a/routers/web/org/projects.go b/routers/web/org/projects.go index d524409c41..f4a54db006 100644 --- a/routers/web/org/projects.go +++ b/routers/web/org/projects.go @@ -205,22 +205,24 @@ func ChangeProjectStatus(ctx *context.Context) { } id := ctx.PathParamInt64("id") - if err := project_model.ChangeProjectStatusByRepoIDAndID(ctx, 0, id, toClose); err != nil { - ctx.NotFoundOrServerError("ChangeProjectStatusByRepoIDAndID", project_model.IsErrProjectNotExist, err) - return - } - ctx.JSONRedirect(project_model.ProjectLinkForOrg(ctx.ContextUser, id)) -} - -// DeleteProject delete a project -func DeleteProject(ctx *context.Context) { - p, err := project_model.GetProjectByID(ctx, ctx.PathParamInt64("id")) + project, err := project_model.GetProjectByIDAndOwner(ctx, id, ctx.ContextUser.ID) if err != nil { ctx.NotFoundOrServerError("GetProjectByID", project_model.IsErrProjectNotExist, err) return } - if p.OwnerID != ctx.ContextUser.ID { - ctx.NotFound(nil) + + if err := project_model.ChangeProjectStatusByRepoIDAndID(ctx, 0, project.ID, toClose); err != nil { + ctx.NotFoundOrServerError("ChangeProjectStatusByRepoIDAndID", project_model.IsErrProjectNotExist, err) + return + } + ctx.JSONRedirect(project_model.ProjectLinkForOrg(ctx.ContextUser, project.ID)) +} + +// DeleteProject delete a project +func DeleteProject(ctx *context.Context) { + p, err := project_model.GetProjectByIDAndOwner(ctx, ctx.PathParamInt64("id"), ctx.ContextUser.ID) + if err != nil { + ctx.NotFoundOrServerError("GetProjectByID", project_model.IsErrProjectNotExist, err) return } @@ -246,15 +248,11 @@ func RenderEditProject(ctx *context.Context) { return } - p, err := project_model.GetProjectByID(ctx, ctx.PathParamInt64("id")) + p, err := project_model.GetProjectByIDAndOwner(ctx, ctx.PathParamInt64("id"), ctx.ContextUser.ID) if err != nil { ctx.NotFoundOrServerError("GetProjectByID", project_model.IsErrProjectNotExist, err) return } - if p.OwnerID != ctx.ContextUser.ID { - ctx.NotFound(nil) - return - } ctx.Data["projectID"] = p.ID ctx.Data["title"] = p.Title @@ -288,15 +286,11 @@ func EditProjectPost(ctx *context.Context) { return } - p, err := project_model.GetProjectByID(ctx, projectID) + p, err := project_model.GetProjectByIDAndOwner(ctx, projectID, ctx.ContextUser.ID) if err != nil { ctx.NotFoundOrServerError("GetProjectByID", project_model.IsErrProjectNotExist, err) return } - if p.OwnerID != ctx.ContextUser.ID { - ctx.NotFound(nil) - return - } p.Title = form.Title p.Description = form.Content @@ -316,15 +310,12 @@ func EditProjectPost(ctx *context.Context) { // ViewProject renders the project with board view for a project func ViewProject(ctx *context.Context) { - project, err := project_model.GetProjectByID(ctx, ctx.PathParamInt64("id")) + project, err := project_model.GetProjectByIDAndOwner(ctx, ctx.PathParamInt64("id"), ctx.ContextUser.ID) if err != nil { ctx.NotFoundOrServerError("GetProjectByID", project_model.IsErrProjectNotExist, err) return } - if project.OwnerID != ctx.ContextUser.ID { - ctx.NotFound(nil) - return - } + if err := project.LoadOwner(ctx); err != nil { ctx.ServerError("LoadOwner", err) return @@ -455,28 +446,15 @@ func DeleteProjectColumn(ctx *context.Context) { return } - project, err := project_model.GetProjectByID(ctx, ctx.PathParamInt64("id")) + project, err := project_model.GetProjectByIDAndOwner(ctx, ctx.PathParamInt64("id"), ctx.ContextUser.ID) if err != nil { ctx.NotFoundOrServerError("GetProjectByID", project_model.IsErrProjectNotExist, err) return } - pb, err := project_model.GetColumn(ctx, ctx.PathParamInt64("columnID")) + _, err = project_model.GetColumnByIDAndProjectID(ctx, ctx.PathParamInt64("columnID"), project.ID) if err != nil { - ctx.ServerError("GetProjectColumn", err) - return - } - if pb.ProjectID != ctx.PathParamInt64("id") { - ctx.JSON(http.StatusUnprocessableEntity, map[string]string{ - "message": fmt.Sprintf("ProjectColumn[%d] is not in Project[%d] as expected", pb.ID, project.ID), - }) - return - } - - if project.OwnerID != ctx.ContextUser.ID { - ctx.JSON(http.StatusUnprocessableEntity, map[string]string{ - "message": fmt.Sprintf("ProjectColumn[%d] is not in Owner[%d] as expected", pb.ID, ctx.ContextUser.ID), - }) + ctx.NotFoundOrServerError("GetColumnByIDAndProjectID", project_model.IsErrProjectColumnNotExist, err) return } @@ -492,7 +470,7 @@ func DeleteProjectColumn(ctx *context.Context) { func AddColumnToProjectPost(ctx *context.Context) { form := web.GetForm(ctx).(*forms.EditProjectColumnForm) - project, err := project_model.GetProjectByID(ctx, ctx.PathParamInt64("id")) + project, err := project_model.GetProjectByIDAndOwner(ctx, ctx.PathParamInt64("id"), ctx.ContextUser.ID) if err != nil { ctx.NotFoundOrServerError("GetProjectByID", project_model.IsErrProjectNotExist, err) return @@ -520,30 +498,18 @@ func CheckProjectColumnChangePermissions(ctx *context.Context) (*project_model.P return nil, nil } - project, err := project_model.GetProjectByID(ctx, ctx.PathParamInt64("id")) + project, err := project_model.GetProjectByIDAndOwner(ctx, ctx.PathParamInt64("id"), ctx.ContextUser.ID) if err != nil { ctx.NotFoundOrServerError("GetProjectByID", project_model.IsErrProjectNotExist, err) return nil, nil } - column, err := project_model.GetColumn(ctx, ctx.PathParamInt64("columnID")) + column, err := project_model.GetColumnByIDAndProjectID(ctx, ctx.PathParamInt64("columnID"), project.ID) if err != nil { - ctx.ServerError("GetProjectColumn", err) - return nil, nil - } - if column.ProjectID != ctx.PathParamInt64("id") { - ctx.JSON(http.StatusUnprocessableEntity, map[string]string{ - "message": fmt.Sprintf("ProjectColumn[%d] is not in Project[%d] as expected", column.ID, project.ID), - }) + ctx.NotFoundOrServerError("GetColumnByIDAndProjectID", project_model.IsErrProjectColumnNotExist, err) return nil, nil } - if project.OwnerID != ctx.ContextUser.ID { - ctx.JSON(http.StatusUnprocessableEntity, map[string]string{ - "message": fmt.Sprintf("ProjectColumn[%d] is not in Repository[%d] as expected", column.ID, project.ID), - }) - return nil, nil - } return project, column } @@ -595,24 +561,15 @@ func MoveIssues(ctx *context.Context) { return } - project, err := project_model.GetProjectByID(ctx, ctx.PathParamInt64("id")) + project, err := project_model.GetProjectByIDAndOwner(ctx, ctx.PathParamInt64("id"), ctx.ContextUser.ID) if err != nil { ctx.NotFoundOrServerError("GetProjectByID", project_model.IsErrProjectNotExist, err) return } - if project.OwnerID != ctx.ContextUser.ID { - ctx.NotFound(nil) - return - } - column, err := project_model.GetColumn(ctx, ctx.PathParamInt64("columnID")) + column, err := project_model.GetColumnByIDAndProjectID(ctx, ctx.PathParamInt64("columnID"), project.ID) if err != nil { - ctx.NotFoundOrServerError("GetProjectColumn", project_model.IsErrProjectColumnNotExist, err) - return - } - - if column.ProjectID != project.ID { - ctx.NotFound(nil) + ctx.NotFoundOrServerError("GetColumnByIDAndProjectID", project_model.IsErrProjectColumnNotExist, err) return } diff --git a/routers/web/org/projects_test.go b/routers/web/org/projects_test.go index c3a769e621..63bcefb6e2 100644 --- a/routers/web/org/projects_test.go +++ b/routers/web/org/projects_test.go @@ -4,11 +4,14 @@ package org_test import ( + "net/http" "testing" "code.gitea.io/gitea/models/unittest" + "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/web/org" "code.gitea.io/gitea/services/contexttest" + "code.gitea.io/gitea/services/forms" "github.com/stretchr/testify/assert" ) @@ -26,3 +29,30 @@ func TestCheckProjectColumnChangePermissions(t *testing.T) { assert.NotNil(t, column) assert.False(t, ctx.Written()) } + +func TestChangeProjectStatusRejectsForeignProjects(t *testing.T) { + unittest.PrepareTestEnv(t) + // project 4 is owned by user2 not user1 + ctx, _ := contexttest.MockContext(t, "user1/-/projects/4/close") + contexttest.LoadUser(t, ctx, 1) + ctx.ContextUser = ctx.Doer + ctx.SetPathParam("action", "close") + ctx.SetPathParam("id", "4") + + org.ChangeProjectStatus(ctx) + + assert.Equal(t, http.StatusNotFound, ctx.Resp.WrittenStatus()) +} + +func TestAddColumnToProjectPostRejectsForeignProjects(t *testing.T) { + unittest.PrepareTestEnv(t) + ctx, _ := contexttest.MockContext(t, "user1/-/projects/4/columns/new") + contexttest.LoadUser(t, ctx, 1) + ctx.ContextUser = ctx.Doer + ctx.SetPathParam("id", "4") + web.SetForm(ctx, &forms.EditProjectColumnForm{Title: "foreign"}) + + org.AddColumnToProjectPost(ctx) + + assert.Equal(t, http.StatusNotFound, ctx.Resp.WrittenStatus()) +} From 14e8c9b767d36d59eadb075c08207d40648a847d Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Wed, 14 Jan 2026 11:37:53 -0800 Subject: [PATCH 16/23] Release attachments must belong to the intended repo (#36347) --- models/repo/attachment.go | 5 ++++ models/repo/attachment_test.go | 16 ++++++++++++ models/repo/release.go | 9 +++++++ models/repo/release_test.go | 14 +++++++++++ routers/web/repo/attachment.go | 35 +++++++++++++++++++------- services/repository/repository.go | 23 ++++++++--------- services/repository/repository_test.go | 16 +++++------- services/user/user.go | 18 +++++++++++++ services/user/user_test.go | 18 +++++++++++++ 9 files changed, 122 insertions(+), 32 deletions(-) diff --git a/models/repo/attachment.go b/models/repo/attachment.go index 835bee5402..27856f2d2e 100644 --- a/models/repo/attachment.go +++ b/models/repo/attachment.go @@ -166,6 +166,11 @@ func GetAttachmentByReleaseIDFileName(ctx context.Context, releaseID int64, file return attach, nil } +func GetUnlinkedAttachmentsByUserID(ctx context.Context, userID int64) ([]*Attachment, error) { + attachments := make([]*Attachment, 0, 10) + return attachments, db.GetEngine(ctx).Where("uploader_id = ? AND issue_id = 0 AND release_id = 0 AND comment_id = 0", userID).Find(&attachments) +} + // DeleteAttachment deletes the given attachment and optionally the associated file. func DeleteAttachment(ctx context.Context, a *Attachment, remove bool) error { _, err := DeleteAttachments(ctx, []*Attachment{a}, remove) diff --git a/models/repo/attachment_test.go b/models/repo/attachment_test.go index d41008344d..07f4c587a7 100644 --- a/models/repo/attachment_test.go +++ b/models/repo/attachment_test.go @@ -101,3 +101,19 @@ func TestGetAttachmentsByUUIDs(t *testing.T) { assert.Equal(t, int64(1), attachList[0].IssueID) assert.Equal(t, int64(5), attachList[1].IssueID) } + +func TestGetUnlinkedAttachmentsByUserID(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + + attachments, err := repo_model.GetUnlinkedAttachmentsByUserID(t.Context(), 8) + assert.NoError(t, err) + assert.Len(t, attachments, 1) + assert.Equal(t, int64(10), attachments[0].ID) + assert.Zero(t, attachments[0].IssueID) + assert.Zero(t, attachments[0].ReleaseID) + assert.Zero(t, attachments[0].CommentID) + + attachments, err = repo_model.GetUnlinkedAttachmentsByUserID(t.Context(), 1) + assert.NoError(t, err) + assert.Empty(t, attachments) +} diff --git a/models/repo/release.go b/models/repo/release.go index 05475899b8..68fb6b1724 100644 --- a/models/repo/release.go +++ b/models/repo/release.go @@ -174,6 +174,11 @@ func UpdateReleaseNumCommits(ctx context.Context, rel *Release) error { // AddReleaseAttachments adds a release attachments func AddReleaseAttachments(ctx context.Context, releaseID int64, attachmentUUIDs []string) (err error) { + rel, err := GetReleaseByID(ctx, releaseID) + if err != nil { + return err + } + // Check attachments attachments, err := GetAttachmentsByUUIDs(ctx, attachmentUUIDs) if err != nil { @@ -181,6 +186,10 @@ func AddReleaseAttachments(ctx context.Context, releaseID int64, attachmentUUIDs } for i := range attachments { + if attachments[i].RepoID != rel.RepoID { + return util.NewPermissionDeniedErrorf("attachment belongs to different repository") + } + if attachments[i].ReleaseID != 0 { return util.NewPermissionDeniedErrorf("release permission denied") } diff --git a/models/repo/release_test.go b/models/repo/release_test.go index 01f0fb3cff..8e30e76f49 100644 --- a/models/repo/release_test.go +++ b/models/repo/release_test.go @@ -7,6 +7,7 @@ import ( "testing" "code.gitea.io/gitea/models/unittest" + "code.gitea.io/gitea/modules/util" "github.com/stretchr/testify/assert" ) @@ -37,3 +38,16 @@ func Test_FindTagsByCommitIDs(t *testing.T) { assert.Equal(t, "delete-tag", rels[1].TagName) assert.Equal(t, "v1.0", rels[2].TagName) } + +func TestAddReleaseAttachmentsRejectsDifferentRepo(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + + uuid := "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a12" // attachment 2 belongs to repo 2 + err := AddReleaseAttachments(t.Context(), 1, []string{uuid}) + assert.Error(t, err) + assert.ErrorIs(t, err, util.ErrPermissionDenied) + + attach, err := GetAttachmentByUUID(t.Context(), uuid) + assert.NoError(t, err) + assert.Zero(t, attach.ReleaseID, "attachment should not be linked to release on failure") +} diff --git a/routers/web/repo/attachment.go b/routers/web/repo/attachment.go index bff91b51a7..c8501792ce 100644 --- a/routers/web/repo/attachment.go +++ b/routers/web/repo/attachment.go @@ -132,23 +132,40 @@ func ServeAttachment(ctx *context.Context, uuid string) { return } - repository, unitType, err := repo_service.LinkedRepository(ctx, attach) - if err != nil { - ctx.ServerError("LinkedRepository", err) + // prevent visiting attachment from other repository directly + if ctx.Repo.Repository != nil && ctx.Repo.Repository.ID != attach.RepoID { + ctx.HTTPError(http.StatusNotFound) return } - if repository == nil { // If not linked + unitType, err := repo_service.GetAttachmentLinkedType(ctx, attach) + if err != nil { + ctx.ServerError("GetAttachmentLinkedType", err) + return + } + + if unitType == unit.TypeInvalid { // unlinked attachment can only be accessed by the uploader if !(ctx.IsSigned && attach.UploaderID == ctx.Doer.ID) { // We block if not the uploader ctx.HTTPError(http.StatusNotFound) return } - } else { // If we have the repository we check access - perm, err := access_model.GetUserRepoPermission(ctx, repository, ctx.Doer) - if err != nil { - ctx.ServerError("GetUserRepoPermission", err) - return + } else { // If we have the linked type, we need to check access + var perm access_model.Permission + if ctx.Repo.Repository == nil { + repo, err := repo_model.GetRepositoryByID(ctx, attach.RepoID) + if err != nil { + ctx.ServerError("GetRepositoryByID", err) + return + } + perm, err = access_model.GetUserRepoPermission(ctx, repo, ctx.Doer) + if err != nil { + ctx.ServerError("GetUserRepoPermission", err) + return + } + } else { + perm = ctx.Repo.Permission } + if !perm.CanRead(unitType) { ctx.HTTPError(http.StatusNotFound) return diff --git a/services/repository/repository.go b/services/repository/repository.go index 21a75a559f..318ab423e5 100644 --- a/services/repository/repository.go +++ b/services/repository/repository.go @@ -221,28 +221,25 @@ func MakeRepoPrivate(ctx context.Context, repo *repo_model.Repository) (err erro }) } -// LinkedRepository returns the linked repo if any -func LinkedRepository(ctx context.Context, a *repo_model.Attachment) (*repo_model.Repository, unit.Type, error) { +// GetAttachmentLinkedType returns the linked type of attachment if any +func GetAttachmentLinkedType(ctx context.Context, a *repo_model.Attachment) (unit.Type, error) { if a.IssueID != 0 { iss, err := issues_model.GetIssueByID(ctx, a.IssueID) if err != nil { - return nil, unit.TypeIssues, err + return unit.TypeIssues, err } - repo, err := repo_model.GetRepositoryByID(ctx, iss.RepoID) unitType := unit.TypeIssues if iss.IsPull { unitType = unit.TypePullRequests } - return repo, unitType, err - } else if a.ReleaseID != 0 { - rel, err := repo_model.GetReleaseByID(ctx, a.ReleaseID) - if err != nil { - return nil, unit.TypeReleases, err - } - repo, err := repo_model.GetRepositoryByID(ctx, rel.RepoID) - return repo, unit.TypeReleases, err + return unitType, nil } - return nil, -1, nil + + if a.ReleaseID != 0 { + _, err := repo_model.GetReleaseByID(ctx, a.ReleaseID) + return unit.TypeReleases, err + } + return unit.TypeInvalid, nil } // CheckDaemonExportOK creates/removes git-daemon-export-ok for git-daemon... diff --git a/services/repository/repository_test.go b/services/repository/repository_test.go index cf7dd6b7ed..b3447ae166 100644 --- a/services/repository/repository_test.go +++ b/services/repository/repository_test.go @@ -16,28 +16,24 @@ import ( "github.com/stretchr/testify/require" ) -func TestLinkedRepository(t *testing.T) { +func TestAttachLinkedType(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) testCases := []struct { name string attachID int64 - expectedRepo *repo_model.Repository expectedUnitType unit.Type }{ - {"LinkedIssue", 1, &repo_model.Repository{ID: 1}, unit.TypeIssues}, - {"LinkedComment", 3, &repo_model.Repository{ID: 1}, unit.TypePullRequests}, - {"LinkedRelease", 9, &repo_model.Repository{ID: 1}, unit.TypeReleases}, - {"Notlinked", 10, nil, -1}, + {"LinkedIssue", 1, unit.TypeIssues}, + {"LinkedComment", 3, unit.TypePullRequests}, + {"LinkedRelease", 9, unit.TypeReleases}, + {"Notlinked", 10, unit.TypeInvalid}, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { attach, err := repo_model.GetAttachmentByID(t.Context(), tc.attachID) assert.NoError(t, err) - repo, unitType, err := LinkedRepository(t.Context(), attach) + unitType, err := GetAttachmentLinkedType(t.Context(), attach) assert.NoError(t, err) - if tc.expectedRepo != nil { - assert.Equal(t, tc.expectedRepo.ID, repo.ID) - } assert.Equal(t, tc.expectedUnitType, unitType) }) } diff --git a/services/user/user.go b/services/user/user.go index 8e42fa3ccd..9b8bcf83c0 100644 --- a/services/user/user.go +++ b/services/user/user.go @@ -239,6 +239,11 @@ func DeleteUser(ctx context.Context, u *user_model.User, purge bool) error { if err := deleteUser(ctx, u, purge); err != nil { return fmt.Errorf("DeleteUser: %w", err) } + + // Finally delete any unlinked attachments, this will also delete the attached files + if err := deleteUserUnlinkedAttachments(ctx, u); err != nil { + return fmt.Errorf("deleteUserUnlinkedAttachments: %w", err) + } return nil }); err != nil { return err @@ -269,6 +274,19 @@ func DeleteUser(ctx context.Context, u *user_model.User, purge bool) error { return nil } +func deleteUserUnlinkedAttachments(ctx context.Context, u *user_model.User) error { + attachments, err := repo_model.GetUnlinkedAttachmentsByUserID(ctx, u.ID) + if err != nil { + return fmt.Errorf("GetUnlinkedAttachmentsByUserID: %w", err) + } + for _, attach := range attachments { + if err := repo_model.DeleteAttachment(ctx, attach, true); err != nil { + return fmt.Errorf("DeleteAttachment ID[%d]: %w", attach.ID, err) + } + } + return nil +} + // DeleteInactiveUsers deletes all inactive users and their email addresses. func DeleteInactiveUsers(ctx context.Context, olderThan time.Duration) error { inactiveUsers, err := user_model.GetInactiveUsers(ctx, olderThan) diff --git a/services/user/user_test.go b/services/user/user_test.go index 25e8ee7b2f..4d8d448dcd 100644 --- a/services/user/user_test.go +++ b/services/user/user_test.go @@ -63,6 +63,24 @@ func TestDeleteUser(t *testing.T) { assert.Error(t, DeleteUser(t.Context(), org, false)) } +func TestDeleteUserUnlinkedAttachments(t *testing.T) { + t.Run("DeleteExisting", func(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 8}) + unittest.AssertExistsAndLoadBean(t, &repo_model.Attachment{ID: 10}) + + assert.NoError(t, deleteUserUnlinkedAttachments(t.Context(), user)) + unittest.AssertNotExistsBean(t, &repo_model.Attachment{ID: 10}) + }) + + t.Run("NoUnlinkedAttachments", func(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + + assert.NoError(t, deleteUserUnlinkedAttachments(t.Context(), user)) + }) +} + func TestPurgeUser(t *testing.T) { test := func(userID int64) { assert.NoError(t, unittest.PrepareTestDatabase()) From 8e9fb4d14c26e0cc72258a51e4dd312913093523 Mon Sep 17 00:00:00 2001 From: Michael Hoang Date: Thu, 15 Jan 2026 09:25:14 +1100 Subject: [PATCH 17/23] Indicate when only optional checks failed (#36367) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently it's not clear that you can merge a PR when only optional checks failed: Screenshot 2026-01-14 at 4 08 17 pm This PR changes the text to say "Some optional checks failed" when only optional checks failed: Screenshot 2026-01-14 at 3 59 08 pm When a required check fails it'll still say "Some checks failed": Screenshot 2026-01-14 at 3 59 20 pm --------- Co-authored-by: wxiaoguang --- options/locale/locale_en-US.json | 3 +- routers/web/repo/pull.go | 36 +++++++++++++++---- .../issue/view_content/pull_merge_box.tmpl | 16 +++++---- templates/repo/pulls/status.tmpl | 14 +------- 4 files changed, 42 insertions(+), 27 deletions(-) diff --git a/options/locale/locale_en-US.json b/options/locale/locale_en-US.json index 1dbb0975a3..96a541a947 100644 --- a/options/locale/locale_en-US.json +++ b/options/locale/locale_en-US.json @@ -1847,7 +1847,8 @@ "repo.pulls.status_checking": "Some checks are pending", "repo.pulls.status_checks_success": "All checks were successful", "repo.pulls.status_checks_warning": "Some checks reported warnings", - "repo.pulls.status_checks_failure": "Some checks failed", + "repo.pulls.status_checks_failure_required": "Some required checks failed", + "repo.pulls.status_checks_failure_optional": "Some optional checks failed", "repo.pulls.status_checks_error": "Some checks reported errors", "repo.pulls.status_checks_requested": "Required", "repo.pulls.status_checks_details": "Details", diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go index 60f0ee6db8..627fe93b77 100644 --- a/routers/web/repo/pull.go +++ b/routers/web/repo/pull.go @@ -23,6 +23,7 @@ import ( repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/commitstatus" "code.gitea.io/gitea/modules/emoji" "code.gitea.io/gitea/modules/fileicon" "code.gitea.io/gitea/modules/git" @@ -35,6 +36,7 @@ import ( "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/templates" + "code.gitea.io/gitea/modules/translation" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/utils" @@ -320,6 +322,26 @@ type pullCommitStatusCheckData struct { RequireApprovalRunCount int // number of workflow runs that require approval CanApprove bool // whether the user can approve workflow runs ApproveLink string // link to approve all checks + RequiredChecksState commitstatus.CommitStatusState + LatestCommitStatus *git_model.CommitStatus +} + +func (d *pullCommitStatusCheckData) CommitStatusCheckPrompt(locale translation.Locale) string { + if d.RequiredChecksState.IsPending() || len(d.MissingRequiredChecks) > 0 { + return locale.TrString("repo.pulls.status_checking") + } else if d.RequiredChecksState.IsSuccess() { + if d.LatestCommitStatus != nil && d.LatestCommitStatus.State.IsFailure() { + return locale.TrString("repo.pulls.status_checks_failure_optional") + } + return locale.TrString("repo.pulls.status_checks_success") + } else if d.RequiredChecksState.IsWarning() { + return locale.TrString("repo.pulls.status_checks_warning") + } else if d.RequiredChecksState.IsFailure() { + return locale.TrString("repo.pulls.status_checks_failure_required") + } else if d.RequiredChecksState.IsError() { + return locale.TrString("repo.pulls.status_checks_error") + } + return locale.TrString("repo.pulls.status_checking") } // prepareViewPullInfo show meta information for a pull request preview page @@ -360,6 +382,8 @@ func prepareViewPullInfo(ctx *context.Context, issue *issues_model.Issue) *git_s defer baseGitRepo.Close() } + statusCheckData := &pullCommitStatusCheckData{} + if exist, _ := git_model.IsBranchExist(ctx, pull.BaseRepo.ID, pull.BaseBranch); !exist { ctx.Data["BaseBranchNotExist"] = true ctx.Data["IsPullRequestBroken"] = true @@ -380,9 +404,10 @@ func prepareViewPullInfo(ctx *context.Context, issue *issues_model.Issue) *git_s git_model.CommitStatusesHideActionsURL(ctx, commitStatuses) } + statusCheckData.LatestCommitStatus = git_model.CalcCommitStatus(commitStatuses) if len(commitStatuses) > 0 { ctx.Data["LatestCommitStatuses"] = commitStatuses - ctx.Data["LatestCommitStatus"] = git_model.CalcCommitStatus(commitStatuses) + ctx.Data["LatestCommitStatus"] = statusCheckData.LatestCommitStatus } compareInfo, err := git_service.GetCompareInfo(ctx, pull.BaseRepo, pull.BaseRepo, baseGitRepo, @@ -467,10 +492,8 @@ func prepareViewPullInfo(ctx *context.Context, issue *issues_model.Issue) *git_s return nil } - statusCheckData := &pullCommitStatusCheckData{ - ApproveLink: fmt.Sprintf("%s/actions/approve-all-checks?commit_id=%s", repo.Link(), sha), - } ctx.Data["StatusCheckData"] = statusCheckData + statusCheckData.ApproveLink = fmt.Sprintf("%s/actions/approve-all-checks?commit_id=%s", repo.Link(), sha) commitStatuses, err := git_model.GetLatestCommitStatus(ctx, repo.ID, sha, db.ListOptionsAll) if err != nil { @@ -495,9 +518,10 @@ func prepareViewPullInfo(ctx *context.Context, issue *issues_model.Issue) *git_s statusCheckData.CanApprove = ctx.Repo.CanWrite(unit.TypeActions) } + statusCheckData.LatestCommitStatus = git_model.CalcCommitStatus(commitStatuses) if len(commitStatuses) > 0 { ctx.Data["LatestCommitStatuses"] = commitStatuses - ctx.Data["LatestCommitStatus"] = git_model.CalcCommitStatus(commitStatuses) + ctx.Data["LatestCommitStatus"] = statusCheckData.LatestCommitStatus } if pb != nil && pb.EnableStatusCheck { @@ -534,7 +558,7 @@ func prepareViewPullInfo(ctx *context.Context, issue *issues_model.Issue) *git_s } return false } - ctx.Data["RequiredStatusCheckState"] = pull_service.MergeRequiredContextsCommitStatus(commitStatuses, pb.StatusCheckContexts) + statusCheckData.RequiredChecksState = pull_service.MergeRequiredContextsCommitStatus(commitStatuses, pb.StatusCheckContexts) } ctx.Data["HeadBranchMovedOn"] = headBranchSha != sha diff --git a/templates/repo/issue/view_content/pull_merge_box.tmpl b/templates/repo/issue/view_content/pull_merge_box.tmpl index 5e89ef5e69..d47d426dfa 100644 --- a/templates/repo/issue/view_content/pull_merge_box.tmpl +++ b/templates/repo/issue/view_content/pull_merge_box.tmpl @@ -8,6 +8,8 @@ data-pull-link="{{.Issue.Link}}" {{end}} > + {{$statusCheckData := .StatusCheckData}} + {{$requiredStatusCheckState := $statusCheckData.RequiredChecksState}}
{{end}} @@ -145,12 +147,12 @@
  • {{.}}
  • {{end}} - {{else if and .EnableStatusCheck (or .RequiredStatusCheckState.IsError .RequiredStatusCheckState.IsFailure)}} + {{else if and .EnableStatusCheck (or $requiredStatusCheckState.IsError $requiredStatusCheckState.IsFailure)}}
    {{svg "octicon-x"}} {{ctx.Locale.Tr "repo.pulls.required_status_check_failed"}}
    - {{else if and .EnableStatusCheck (not .RequiredStatusCheckState.IsSuccess)}} + {{else if and .EnableStatusCheck (not $requiredStatusCheckState.IsSuccess)}}
    {{svg "octicon-x"}} {{ctx.Locale.Tr "repo.pulls.required_status_check_missing"}} @@ -166,7 +168,7 @@
    {{end}} - {{$notAllOverridableChecksOk := or .IsBlockedByApprovals .IsBlockedByRejection .IsBlockedByOfficialReviewRequests .IsBlockedByOutdatedBranch .IsBlockedByChangedProtectedFiles (and .EnableStatusCheck (not .RequiredStatusCheckState.IsSuccess))}} + {{$notAllOverridableChecksOk := or .IsBlockedByApprovals .IsBlockedByRejection .IsBlockedByOfficialReviewRequests .IsBlockedByOutdatedBranch .IsBlockedByChangedProtectedFiles (and .EnableStatusCheck (not $requiredStatusCheckState.IsSuccess))}} {{/* admin can merge without checks, writer can merge when checks succeed */}} {{$canMergeNow := and (or (and (not $.ProtectedBranch.BlockAdminMergeOverride) $.IsRepoAdmin) (not $notAllOverridableChecksOk)) (or (not .AllowMerge) (not .RequireSigned) .WillSign)}} @@ -351,7 +353,7 @@
  • {{.}}
  • {{end}} - {{else if and .EnableStatusCheck (not .RequiredStatusCheckState.IsSuccess)}} + {{else if and .EnableStatusCheck (not $requiredStatusCheckState.IsSuccess)}}
    {{svg "octicon-x"}} {{ctx.Locale.Tr "repo.pulls.required_status_check_failed"}} diff --git a/templates/repo/pulls/status.tmpl b/templates/repo/pulls/status.tmpl index f3c1973c2b..7962b2ffbf 100644 --- a/templates/repo/pulls/status.tmpl +++ b/templates/repo/pulls/status.tmpl @@ -8,19 +8,7 @@ {{if .CommitStatus}}
    - {{if or (eq .CommitStatus.State "pending") (.MissingRequiredChecks)}} - {{ctx.Locale.Tr "repo.pulls.status_checking"}} - {{else if eq .CommitStatus.State "success"}} - {{ctx.Locale.Tr "repo.pulls.status_checks_success"}} - {{else if eq .CommitStatus.State "warning"}} - {{ctx.Locale.Tr "repo.pulls.status_checks_warning"}} - {{else if eq .CommitStatus.State "failure"}} - {{ctx.Locale.Tr "repo.pulls.status_checks_failure"}} - {{else if eq .CommitStatus.State "error"}} - {{ctx.Locale.Tr "repo.pulls.status_checks_error"}} - {{else}} - {{ctx.Locale.Tr "repo.pulls.status_checking"}} - {{end}} + {{$statusCheckData.CommitStatusCheckPrompt ctx.Locale}} {{if .ShowHideChecks}}
    From 915a2cd86fe6c1072302286baf59e6fb199c59bf Mon Sep 17 00:00:00 2001 From: silverwind Date: Thu, 15 Jan 2026 07:18:33 +0100 Subject: [PATCH 18/23] Rename CSS variables and improve colorblind themes (#36353) Followup https://github.com/go-gitea/gitea/pull/36215, rename the variables for consistency with existing vars and change green to value of `--color-blue` in the relevant color blind themes: image The blue coloring also matched GitHub: image --------- Co-authored-by: Lunny Xiao --- templates/repo/diff/stats.tmpl | 4 ++-- web_src/css/repo.css | 4 ++-- .../theme-gitea-dark-protanopia-deuteranopia.css | 15 ++++++++------- .../css/themes/theme-gitea-dark-tritanopia.css | 10 +++++----- web_src/css/themes/theme-gitea-dark.css | 4 ++-- .../theme-gitea-light-protanopia-deuteranopia.css | 15 ++++++++------- .../css/themes/theme-gitea-light-tritanopia.css | 10 +++++----- web_src/css/themes/theme-gitea-light.css | 4 ++-- 8 files changed, 34 insertions(+), 32 deletions(-) diff --git a/templates/repo/diff/stats.tmpl b/templates/repo/diff/stats.tmpl index 31797cd970..09ce9b3478 100644 --- a/templates/repo/diff/stats.tmpl +++ b/templates/repo/diff/stats.tmpl @@ -6,8 +6,8 @@ {{if or .Addition .Deletion}}
    - {{if .Addition}}+{{.Addition}}{{end}} - {{if .Deletion}}-{{.Deletion}}{{end}} + {{if .Addition}}+{{.Addition}}{{end}} + {{if .Deletion}}-{{.Deletion}}{{end}} {{/* if the denominator is zero, then the float result is "width: NaNpx", as before, it just works */}} diff --git a/web_src/css/repo.css b/web_src/css/repo.css index 4de1f3ccdf..abb891cf9b 100644 --- a/web_src/css/repo.css +++ b/web_src/css/repo.css @@ -1752,13 +1752,13 @@ tbody.commit-list { .diff-stats-bar { display: inline-block; - background-color: var(--color-diff-prompt-del-fg); /* the background is used as "text foreground color" */ + background-color: var(--color-diff-removed-fg); /* the background is used as "text foreground color" */ height: 12px; width: 44px; } .diff-stats-bar .diff-stats-add-bar { - background-color: var(--color-diff-prompt-add-fg); + background-color: var(--color-diff-added-fg); height: 100%; } diff --git a/web_src/css/themes/theme-gitea-dark-protanopia-deuteranopia.css b/web_src/css/themes/theme-gitea-dark-protanopia-deuteranopia.css index 9f2b6ce73f..01f53e3908 100644 --- a/web_src/css/themes/theme-gitea-dark-protanopia-deuteranopia.css +++ b/web_src/css/themes/theme-gitea-dark-protanopia-deuteranopia.css @@ -7,12 +7,13 @@ gitea-theme-meta-info { } /* red/green colorblind-friendly colors */ -/* from GitHub: --diffBlob-addition-*, --diffBlob-deletion-*, etc */ :root { - --color-diff-added-linenum-bg: #1979fd46; - --color-diff-added-row-bg: #1979fd20; - --color-diff-added-word-bg: #1979fd66; - --color-diff-removed-linenum-bg: #c8622146; - --color-diff-removed-row-bg: #c8622120; - --color-diff-removed-word-bg: #c8622166; + --color-diff-added-fg: #58a6ff; + --color-diff-added-linenum-bg: #243d5d; + --color-diff-added-row-bg: #132339; + --color-diff-added-word-bg: #214d87; + --color-diff-removed-fg: #f0883e; + --color-diff-removed-linenum-bg: #5b361c; + --color-diff-removed-row-bg: #3c2419; + --color-diff-removed-word-bg: #824e1f; } diff --git a/web_src/css/themes/theme-gitea-dark-tritanopia.css b/web_src/css/themes/theme-gitea-dark-tritanopia.css index 1dbd9967dd..dd4e0502c4 100644 --- a/web_src/css/themes/theme-gitea-dark-tritanopia.css +++ b/web_src/css/themes/theme-gitea-dark-tritanopia.css @@ -1,4 +1,4 @@ -@import "./theme-gitea-dark-protanopia-deuteranopia.css"; +@import "./theme-gitea-dark.css"; gitea-theme-meta-info { --theme-display-name: "Dark"; @@ -7,9 +7,9 @@ gitea-theme-meta-info { } /* blue/yellow colorblind-friendly colors */ -/* from GitHub: blue yellow blindness is based on red green blindness, and --diffBlob-deletion-* restored to the normal theme color */ :root { - --color-diff-removed-linenum-bg: #482121; - --color-diff-removed-row-bg: #301e1e; - --color-diff-removed-word-bg: #6f3333; + --color-diff-added-fg: #58a6ff; + --color-diff-added-linenum-bg: #243d5d; + --color-diff-added-row-bg: #132339; + --color-diff-added-word-bg: #214d87; } diff --git a/web_src/css/themes/theme-gitea-dark.css b/web_src/css/themes/theme-gitea-dark.css index 7998f54990..f58c222c9a 100644 --- a/web_src/css/themes/theme-gitea-dark.css +++ b/web_src/css/themes/theme-gitea-dark.css @@ -148,18 +148,18 @@ gitea-theme-meta-info { --color-grey-light: #818f9e; --color-gold: #b1983b; --color-white: #ffffff; + --color-diff-added-fg: #87ab63; --color-diff-added-linenum-bg: #274227; --color-diff-added-row-bg: #203224; --color-diff-added-row-border: #314a37; --color-diff-added-word-bg: #3c653c; --color-diff-moved-row-bg: #818044; --color-diff-moved-row-border: #bcca6f; + --color-diff-removed-fg: #cc4848; --color-diff-removed-linenum-bg: #482121; --color-diff-removed-row-bg: #301e1e; --color-diff-removed-row-border: #634343; --color-diff-removed-word-bg: #6f3333; - --color-diff-prompt-add-fg: #87ab63; - --color-diff-prompt-del-fg: #cc4848; --color-diff-inactive: #22282d; --color-error-border: #a04141; --color-error-bg: #522; diff --git a/web_src/css/themes/theme-gitea-light-protanopia-deuteranopia.css b/web_src/css/themes/theme-gitea-light-protanopia-deuteranopia.css index 421085a2a7..6350cdd156 100644 --- a/web_src/css/themes/theme-gitea-light-protanopia-deuteranopia.css +++ b/web_src/css/themes/theme-gitea-light-protanopia-deuteranopia.css @@ -7,12 +7,13 @@ gitea-theme-meta-info { } /* red/green colorblind-friendly colors */ -/* from GitHub: --diffBlob-addition-*, --diffBlob-deletion-*, etc */ :root { - --color-diff-added-linenum-bg: #54aeff4d; - --color-diff-added-row-bg: #ddf4ff80; - --color-diff-added-word-bg: #54aeff66; - --color-diff-removed-linenum-bg: #ffb77c4d; - --color-diff-removed-row-bg: #fff1e580; - --color-diff-removed-word-bg: #ffb77c80; + --color-diff-added-fg: #2185d0; + --color-diff-added-linenum-bg: #b6e3ff; + --color-diff-added-row-bg: #ddf4ff; + --color-diff-added-word-bg: #b6e3ff; + --color-diff-removed-fg: #fc6500; + --color-diff-removed-linenum-bg: #ffd8b5; + --color-diff-removed-row-bg: #fff1e5; + --color-diff-removed-word-bg: #ffd8b5; } diff --git a/web_src/css/themes/theme-gitea-light-tritanopia.css b/web_src/css/themes/theme-gitea-light-tritanopia.css index a50fd9c1a4..15f3019be4 100644 --- a/web_src/css/themes/theme-gitea-light-tritanopia.css +++ b/web_src/css/themes/theme-gitea-light-tritanopia.css @@ -1,4 +1,4 @@ -@import "./theme-gitea-light-protanopia-deuteranopia.css"; +@import "./theme-gitea-light.css"; gitea-theme-meta-info { --theme-display-name: "Light"; @@ -7,9 +7,9 @@ gitea-theme-meta-info { } /* blue/yellow colorblind-friendly colors */ -/* from GitHub: blue yellow blindness is based on red green blindness, and --diffBlob-deletion-* restored to the normal theme color */ :root { - --color-diff-removed-linenum-bg: #ffcecb; - --color-diff-removed-row-bg: #ffeef0; - --color-diff-removed-word-bg: #fdb8c0; + --color-diff-added-fg: #2185d0; + --color-diff-added-linenum-bg: #b6e3ff; + --color-diff-added-row-bg: #ddf4ff; + --color-diff-added-word-bg: #b6e3ff; } diff --git a/web_src/css/themes/theme-gitea-light.css b/web_src/css/themes/theme-gitea-light.css index d169492041..1969b52ed1 100644 --- a/web_src/css/themes/theme-gitea-light.css +++ b/web_src/css/themes/theme-gitea-light.css @@ -148,18 +148,18 @@ gitea-theme-meta-info { --color-grey-light: #7c838a; --color-gold: #a1882b; --color-white: #ffffff; + --color-diff-added-fg: #21ba45; --color-diff-added-linenum-bg: #d1f8d9; --color-diff-added-row-bg: #e6ffed; --color-diff-added-row-border: #e6ffed; --color-diff-added-word-bg: #acf2bd; --color-diff-moved-row-bg: #f1f8d1; --color-diff-moved-row-border: #d0e27f; + --color-diff-removed-fg: #db2828; --color-diff-removed-linenum-bg: #ffcecb; --color-diff-removed-row-bg: #ffeef0; --color-diff-removed-row-border: #f1c0c0; --color-diff-removed-word-bg: #fdb8c0; - --color-diff-prompt-add-fg: #21ba45; - --color-diff-prompt-del-fg: #db2828; --color-diff-inactive: #f0f2f4; --color-error-border: #e0b4b4; --color-error-bg: #fff6f6; From 4a9ac538627eefddcf5ff2b2df2493f368aeeee4 Mon Sep 17 00:00:00 2001 From: silverwind Date: Thu, 15 Jan 2026 12:01:23 +0100 Subject: [PATCH 19/23] Migrate to `import.meta.env` and clean up types and eslint (#36362) `import.meta.env` is supported in both vitest and webpack [as of recent](https://github.com/webpack/webpack/pull/19996), so replace all previous use of `process.env` with it. Current usage is limited to test files, I've also verified it works in actual frontend code. `webpack/module` is added to typescript types which includes the definition for `import.meta.env`. I've also made the eslint globals more precise. Finally, `__webpack_public_path__` is removed from our type definitions because `webpack/module` also provides it. --- eslint.config.ts | 29 ++----------------- tsconfig.json | 1 + web_src/js/bootstrap.ts | 4 +-- web_src/js/features/notification.ts | 2 +- web_src/js/features/stopwatch.ts | 2 +- web_src/js/globals.d.ts | 3 -- web_src/js/utils/testhelper.ts | 2 +- .../js/webcomponents/absolute-date.test.ts | 6 ++-- 8 files changed, 12 insertions(+), 37 deletions(-) diff --git a/eslint.config.ts b/eslint.config.ts index 38797a4d1a..740f30a281 100644 --- a/eslint.config.ts +++ b/eslint.config.ts @@ -32,10 +32,6 @@ export default defineConfig([ languageOptions: { ecmaVersion: 'latest', sourceType: 'module', - globals: { - ...globals.browser, - ...globals.node, - }, parser: typescriptParser, parserOptions: { sourceType: 'module', @@ -363,7 +359,7 @@ export default defineConfig([ 'import-x/no-self-import': [2], 'import-x/no-unassigned-import': [0], 'import-x/no-unresolved': [2, {commonjs: true, ignore: ['\\?.+$']}], - // 'import-x/no-unused-modules': [2, {unusedExports: true}], // not compatible with eslint 9 + 'import-x/no-unused-modules': [0], // incompatible with eslint 9 'import-x/no-useless-path-segments': [2, {commonjs: true}], 'import-x/no-webpack-loader-syntax': [2], 'import-x/order': [0], @@ -990,38 +986,19 @@ export default defineConfig([ 'vitest/valid-title': [2], }, }, - { - files: ['web_src/js/types.ts'], - rules: { - 'import-x/no-unused-modules': [0], - }, - }, { files: ['**/*.d.ts'], rules: { - 'import-x/no-unused-modules': [0], '@typescript-eslint/consistent-type-definitions': [0], '@typescript-eslint/consistent-type-imports': [0], }, }, { - files: ['*.config.*'], - rules: { - 'import-x/no-unused-modules': [0], - }, + files: ['*', 'tools/**/*'], + languageOptions: {globals: globals.node}, }, { files: ['web_src/**/*', 'docs/**/*'], languageOptions: {globals: globals.browser}, }, - { - files: ['web_src/**/*'], - languageOptions: { - globals: { - ...globals.browser, - __webpack_public_path__: true, - process: false, // https://github.com/webpack/webpack/issues/15833 - }, - }, - }, ]); diff --git a/tsconfig.json b/tsconfig.json index 2466faf592..d2149a37bd 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -44,6 +44,7 @@ "stripInternal": true, "verbatimModuleSyntax": true, "types": [ + "webpack/module", "vitest/globals", "./web_src/js/globals.d.ts", "./types.d.ts", diff --git a/web_src/js/bootstrap.ts b/web_src/js/bootstrap.ts index a94e1d66b0..9d30e9ea52 100644 --- a/web_src/js/bootstrap.ts +++ b/web_src/js/bootstrap.ts @@ -6,7 +6,7 @@ import {html} from './utils/html.ts'; // This sets up the URL prefix used in webpack's chunk loading. // This file must be imported before any lazy-loading is being attempted. -__webpack_public_path__ = `${window.config?.assetUrlPrefix ?? '/assets'}/`; +window.__webpack_public_path__ = `${window.config?.assetUrlPrefix ?? '/assets'}/`; function shouldIgnoreError(err: Error) { const ignorePatterns = [ @@ -41,7 +41,7 @@ export function showGlobalErrorMessage(msg: string, msgType: Intent = 'error') { function processWindowErrorEvent({error, reason, message, type, filename, lineno, colno}: ErrorEvent & PromiseRejectionEvent) { const err = error ?? reason; - const assetBaseUrl = String(new URL(__webpack_public_path__, window.location.origin)); + const assetBaseUrl = String(new URL(window.__webpack_public_path__, window.location.origin)); const {runModeIsProd} = window.config ?? {}; // `error` and `reason` are not guaranteed to be errors. If the value is falsy, it is likely a diff --git a/web_src/js/features/notification.ts b/web_src/js/features/notification.ts index ae318e6c78..915f65f88d 100644 --- a/web_src/js/features/notification.ts +++ b/web_src/js/features/notification.ts @@ -33,7 +33,7 @@ export function initNotificationCount() { if (notificationSettings.EventSourceUpdateTime > 0 && window.EventSource && window.SharedWorker) { // Try to connect to the event source via the shared worker first - const worker = new SharedWorker(`${__webpack_public_path__}js/eventsource.sharedworker.js?v=${assetVersionEncoded}`, 'notification-worker'); + const worker = new SharedWorker(`${window.__webpack_public_path__}js/eventsource.sharedworker.js?v=${assetVersionEncoded}`, 'notification-worker'); worker.addEventListener('error', (event) => { console.error('worker error', event); }); diff --git a/web_src/js/features/stopwatch.ts b/web_src/js/features/stopwatch.ts index 07f9c435b8..34e985332b 100644 --- a/web_src/js/features/stopwatch.ts +++ b/web_src/js/features/stopwatch.ts @@ -47,7 +47,7 @@ export function initStopwatch() { // if the browser supports EventSource and SharedWorker, use it instead of the periodic poller if (notificationSettings.EventSourceUpdateTime > 0 && window.EventSource && window.SharedWorker) { // Try to connect to the event source via the shared worker first - const worker = new SharedWorker(`${__webpack_public_path__}js/eventsource.sharedworker.js?v=${assetVersionEncoded}`, 'notification-worker'); + const worker = new SharedWorker(`${window.__webpack_public_path__}js/eventsource.sharedworker.js?v=${assetVersionEncoded}`, 'notification-worker'); worker.addEventListener('error', (event) => { console.error('worker error', event); }); diff --git a/web_src/js/globals.d.ts b/web_src/js/globals.d.ts index 49ce63d688..c0ee81af0b 100644 --- a/web_src/js/globals.d.ts +++ b/web_src/js/globals.d.ts @@ -18,8 +18,6 @@ declare module '*.vue' { export function initRepositoryActionView(): void; } -declare let __webpack_public_path__: string; - declare module 'htmx.org/dist/htmx.esm.js' { const value = await import('htmx.org'); export default value; @@ -51,7 +49,6 @@ interface Element { } interface Window { - __webpack_public_path__: string; config: import('./web_src/js/types.ts').Config; $: typeof import('@types/jquery'), jQuery: typeof import('@types/jquery'), diff --git a/web_src/js/utils/testhelper.ts b/web_src/js/utils/testhelper.ts index e91cf85e86..0e0aff9fa3 100644 --- a/web_src/js/utils/testhelper.ts +++ b/web_src/js/utils/testhelper.ts @@ -2,5 +2,5 @@ // even if backend is in testing mode, frontend could be complied in production mode // so this function only checks if the frontend is in unit testing mode (usually from *.test.ts files) export function isInFrontendUnitTest() { - return process.env.TEST === 'true'; + return import.meta.env.TEST === 'true'; } diff --git a/web_src/js/webcomponents/absolute-date.test.ts b/web_src/js/webcomponents/absolute-date.test.ts index bf591358bd..4eee80048d 100644 --- a/web_src/js/webcomponents/absolute-date.test.ts +++ b/web_src/js/webcomponents/absolute-date.test.ts @@ -18,9 +18,9 @@ test('toAbsoluteLocaleDate', () => { expect(toAbsoluteLocaleDate('10000-01-01', '', {})).toEqual('Invalid Date'); // test different timezone - const oldTZ = process.env.TZ; - process.env.TZ = 'America/New_York'; + const oldTZ = import.meta.env.TZ; + import.meta.env.TZ = 'America/New_York'; expect(new Date('2024-03-15').toLocaleString('en-US')).toEqual('3/14/2024, 8:00:00 PM'); expect(toAbsoluteLocaleDate('2024-03-15', 'en-US')).toEqual('3/15/2024, 12:00:00 AM'); - process.env.TZ = oldTZ; + import.meta.env.TZ = oldTZ; }); From 3f46de82657a7ab04f043610639e13752687aad8 Mon Sep 17 00:00:00 2001 From: Zeno <65364211+telometto@users.noreply.github.com> Date: Fri, 16 Jan 2026 00:15:18 +0100 Subject: [PATCH 20/23] Add chunked transfer encoding support for LFS uploads (#36380) Enable chunked transfer encoding for Git LFS uploads by adding Transfer-Encoding: chunked header to upload action responses. This prevents large file uploads (100+ MB) from being blocked by reverse proxies like Cloudflare that buffer non-chunked requests. Fix https://github.com/go-gitea/gitea/issues/22233 --------- Co-authored-by: wxiaoguang --- modules/lfs/shared.go | 15 ++++++++++++ services/lfs/server.go | 33 ++++++++++---------------- tests/integration/api_repo_lfs_test.go | 1 + 3 files changed, 28 insertions(+), 21 deletions(-) diff --git a/modules/lfs/shared.go b/modules/lfs/shared.go index cd9488e3db..e04c089e51 100644 --- a/modules/lfs/shared.go +++ b/modules/lfs/shared.go @@ -66,6 +66,21 @@ type Link struct { ExpiresAt *time.Time `json:"expires_at,omitempty"` } +func NewLink(href string) *Link { + return &Link{Href: href} +} + +func (l *Link) WithHeader(k, v string) *Link { + if v == "" { + return l + } + if l.Header == nil { + l.Header = make(map[string]string) + } + l.Header[k] = v + return l +} + // ObjectError defines the JSON structure returned to the client in case of an error. type ObjectError struct { Code int `json:"code"` diff --git a/services/lfs/server.go b/services/lfs/server.go index 3455b4b9bd..4819437bf1 100644 --- a/services/lfs/server.go +++ b/services/lfs/server.go @@ -11,7 +11,6 @@ import ( "errors" "fmt" "io" - "maps" "net/http" "net/url" "regexp" @@ -487,40 +486,32 @@ func buildObjectResponse(rc *requestContext, pointer lfs_module.Pointer, downloa rep.Error = err } else { rep.Actions = make(map[string]*lfs_module.Link) - - header := make(map[string]string) - - if len(rc.Authorization) > 0 { - header["Authorization"] = rc.Authorization - } - if download { var link *lfs_module.Link if setting.LFS.Storage.ServeDirect() { // If we have a signed url (S3, object storage), redirect to this directly. u, err := storage.LFS.URL(pointer.RelativePath(), pointer.Oid, rc.Method, nil) if u != nil && err == nil { - // Presigned url does not need the Authorization header - // https://github.com/go-gitea/gitea/issues/21525 - delete(header, "Authorization") - link = &lfs_module.Link{Href: u.String(), Header: header} + link = lfs_module.NewLink(u.String()) // Presigned url does not need the Authorization header } } if link == nil { - link = &lfs_module.Link{Href: rc.DownloadLink(pointer), Header: header} + link = lfs_module.NewLink(rc.DownloadLink(pointer)).WithHeader("Authorization", rc.Authorization) } rep.Actions["download"] = link } if upload { - rep.Actions["upload"] = &lfs_module.Link{Href: rc.UploadLink(pointer), Header: header} + // Set Transfer-Encoding header to enable chunked uploads. Required by git-lfs client to do chunked transfer. + // See: https://github.com/git-lfs/git-lfs/blob/main/tq/basic_upload.go#L58-59 + rep.Actions["upload"] = lfs_module.NewLink(rc.UploadLink(pointer)). + WithHeader("Authorization", rc.Authorization). + WithHeader("Transfer-Encoding", "chunked") - verifyHeader := make(map[string]string) - maps.Copy(verifyHeader, header) - - // This is only needed to workaround https://github.com/git-lfs/git-lfs/issues/3662 - verifyHeader["Accept"] = lfs_module.AcceptHeader - - rep.Actions["verify"] = &lfs_module.Link{Href: rc.VerifyLink(pointer), Header: verifyHeader} + // "Accept" header is the workaround for git-lfs < 2.8.0 (before 2019). + // This workaround could be removed in the future: https://github.com/git-lfs/git-lfs/issues/3662 + rep.Actions["verify"] = lfs_module.NewLink(rc.VerifyLink(pointer)). + WithHeader("Authorization", rc.Authorization). + WithHeader("Accept", lfs_module.AcceptHeader) } } return rep diff --git a/tests/integration/api_repo_lfs_test.go b/tests/integration/api_repo_lfs_test.go index fb55d311cc..86d5f69b9c 100644 --- a/tests/integration/api_repo_lfs_test.go +++ b/tests/integration/api_repo_lfs_test.go @@ -317,6 +317,7 @@ func TestAPILFSBatch(t *testing.T) { ul := br.Objects[0].Actions["upload"] assert.NotNil(t, ul) assert.NotEmpty(t, ul.Href) + assert.Equal(t, "chunked", ul.Header["Transfer-Encoding"], "git-lfs client needs Transfer-Encoding to do chunked transfer") assert.Contains(t, br.Objects[0].Actions, "verify") vl := br.Objects[0].Actions["verify"] assert.NotNil(t, vl) From 67e75f30a83d2523cedc37ad7b03bcba66947833 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Thu, 15 Jan 2026 21:11:13 -0800 Subject: [PATCH 21/23] Fix bug on notification read (#36339) When a user has been revoked permission to access a repository, the related notification could still be visited. But the repository's information should not be leaked any more. --- services/convert/notification.go | 18 ++++++--- services/convert/notification_test.go | 57 +++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 6 deletions(-) create mode 100644 services/convert/notification_test.go diff --git a/services/convert/notification.go b/services/convert/notification.go index 69470638be..87166501a6 100644 --- a/services/convert/notification.go +++ b/services/convert/notification.go @@ -8,8 +8,8 @@ import ( "net/url" activities_model "code.gitea.io/gitea/models/activities" - "code.gitea.io/gitea/models/perm" access_model "code.gitea.io/gitea/models/perm/access" + "code.gitea.io/gitea/modules/log" api "code.gitea.io/gitea/modules/structs" ) @@ -25,11 +25,17 @@ func ToNotificationThread(ctx context.Context, n *activities_model.Notification) // since user only get notifications when he has access to use minimal access mode if n.Repository != nil { - result.Repository = ToRepo(ctx, n.Repository, access_model.Permission{AccessMode: perm.AccessModeRead}) - - // This permission is not correct and we should not be reporting it - for repository := result.Repository; repository != nil; repository = repository.Parent { - repository.Permissions = nil + perm, err := access_model.GetUserRepoPermission(ctx, n.Repository, n.User) + if err != nil { + log.Error("GetUserRepoPermission failed: %v", err) + return result + } + if perm.HasAnyUnitAccessOrPublicAccess() { // if user has been revoked access to repo, do not show repo info + result.Repository = ToRepo(ctx, n.Repository, perm) + // This permission is not correct and we should not be reporting it + for repository := result.Repository; repository != nil; repository = repository.Parent { + repository.Permissions = nil + } } } diff --git a/services/convert/notification_test.go b/services/convert/notification_test.go new file mode 100644 index 0000000000..718a070819 --- /dev/null +++ b/services/convert/notification_test.go @@ -0,0 +1,57 @@ +// Copyright 2026 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package convert + +import ( + "testing" + + activities_model "code.gitea.io/gitea/models/activities" + repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/models/unittest" + user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/timeutil" + + "github.com/stretchr/testify/assert" +) + +func TestToNotificationThreadIncludesRepoForAccessibleUser(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + + n := newRepoNotification(t, 1, 4) + thread := ToNotificationThread(t.Context(), n) + + if assert.NotNil(t, thread.Repository) { + assert.Equal(t, n.Repository.FullName(), thread.Repository.FullName) + assert.Nil(t, thread.Repository.Permissions) + } +} + +func TestToNotificationThreadOmitsRepoWhenAccessRevoked(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + + n := newRepoNotification(t, 2, 4) + thread := ToNotificationThread(t.Context(), n) + + assert.Nil(t, thread.Repository) +} + +func newRepoNotification(t *testing.T, repoID, userID int64) *activities_model.Notification { + t.Helper() + + ctx := t.Context() + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID}) + assert.NoError(t, repo.LoadOwner(ctx)) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: userID}) + + return &activities_model.Notification{ + ID: repoID*1000 + userID, + UserID: user.ID, + RepoID: repo.ID, + Status: activities_model.NotificationStatusUnread, + Source: activities_model.NotificationSourceRepository, + UpdatedUnix: timeutil.TimeStampNow(), + Repository: repo, + User: user, + } +} From 69c5921d7138cff87404a032bb8587bffdc74121 Mon Sep 17 00:00:00 2001 From: TheFox0x7 Date: Fri, 16 Jan 2026 10:31:12 +0100 Subject: [PATCH 22/23] Add ability to download subpath archive (#36371) closes: https://github.com/go-gitea/gitea/issues/4478 --------- Signed-off-by: wxiaoguang Co-authored-by: wxiaoguang --- .golangci.yml | 2 + go.mod | 2 +- modules/git/gitcmd/command.go | 22 +++++- modules/git/gitcmd/command_test.go | 12 ++++ modules/git/gitcmd/utils.go | 12 +++- modules/gitrepo/archive.go | 11 ++- modules/test/utils.go | 31 ++++++++ options/locale/locale_en-US.json | 1 + routers/api/v1/repo/download.go | 22 ++++-- routers/api/v1/repo/file.go | 10 ++- routers/web/repo/repo.go | 20 ++++-- services/pull/commit_status.go | 18 ++--- services/repository/archiver/archiver.go | 72 +++++++------------ services/repository/archiver/archiver_test.go | 38 +++++----- templates/repo/view_content.tmpl | 5 ++ templates/swagger/v1_json.tmpl | 10 +++ tests/integration/api_packages_arch_test.go | 37 ++-------- tests/integration/repo_archive_test.go | 39 ++++++++-- 18 files changed, 230 insertions(+), 134 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index e9b9a03c43..41a0185df7 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -48,6 +48,8 @@ linters: desc: do not use the ini package, use gitea's config system instead - pkg: gitea.com/go-chi/cache desc: do not use the go-chi cache package, use gitea's cache system + - pkg: github.com/pkg/errors + desc: use builtin errors package instead nolintlint: allow-unused: false require-explanation: true diff --git a/go.mod b/go.mod index 07d71963ef..76b69d5098 100644 --- a/go.mod +++ b/go.mod @@ -95,7 +95,6 @@ require ( github.com/olivere/elastic/v7 v7.0.32 github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/image-spec v1.1.1 - github.com/pkg/errors v0.9.1 github.com/pquerna/otp v1.5.0 github.com/prometheus/client_golang v1.23.0 github.com/quasoft/websspi v1.1.2 @@ -251,6 +250,7 @@ require ( github.com/philhofer/fwd v1.2.0 // indirect github.com/pierrec/lz4/v4 v4.1.22 // indirect github.com/pjbgf/sha1cd v0.4.0 // indirect + github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/client_model v0.6.2 // indirect github.com/prometheus/common v0.65.0 // indirect diff --git a/modules/git/gitcmd/command.go b/modules/git/gitcmd/command.go index ff2827bd6c..11dd46f472 100644 --- a/modules/git/gitcmd/command.go +++ b/modules/git/gitcmd/command.go @@ -426,9 +426,9 @@ type RunStdError interface { } type runStdError struct { - err error - stderr string - errMsg string + err error // usually the low-level error like `*exec.ExitError` + stderr string // git command's stderr output + errMsg string // the cached error message for Error() method } func (r *runStdError) Error() string { @@ -448,6 +448,22 @@ func (r *runStdError) Stderr() string { return r.stderr } +func ErrorAsStderr(err error) (string, bool) { + var runErr RunStdError + if errors.As(err, &runErr) { + return runErr.Stderr(), true + } + return "", false +} + +func StderrHasPrefix(err error, prefix string) bool { + stderr, ok := ErrorAsStderr(err) + if !ok { + return false + } + return strings.HasPrefix(stderr, prefix) +} + func IsErrorExitCode(err error, code int) bool { var exitError *exec.ExitError if errors.As(err, &exitError) { diff --git a/modules/git/gitcmd/command_test.go b/modules/git/gitcmd/command_test.go index d813ffce6d..4a21154cf2 100644 --- a/modules/git/gitcmd/command_test.go +++ b/modules/git/gitcmd/command_test.go @@ -12,6 +12,7 @@ import ( "code.gitea.io/gitea/modules/tempdir" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestMain(m *testing.M) { @@ -99,3 +100,14 @@ func TestCommandString(t *testing.T) { cmd = NewCommand("url: https://a:b@c/", "/root/dir-a/dir-b") assert.Equal(t, cmd.prog+` "url: https://sanitized-credential@c/" .../dir-a/dir-b`, cmd.LogString()) } + +func TestRunStdError(t *testing.T) { + e := &runStdError{stderr: "some error"} + var err RunStdError = e + + var asErr RunStdError + require.ErrorAs(t, err, &asErr) + require.Equal(t, "some error", asErr.Stderr()) + + require.ErrorAs(t, fmt.Errorf("wrapped %w", err), &asErr) +} diff --git a/modules/git/gitcmd/utils.go b/modules/git/gitcmd/utils.go index ee24eb6a9a..74d9d89e41 100644 --- a/modules/git/gitcmd/utils.go +++ b/modules/git/gitcmd/utils.go @@ -3,12 +3,18 @@ package gitcmd -import "fmt" +import ( + "fmt" -// ConcatenateError concatenats an error with stderr string + "code.gitea.io/gitea/modules/util" +) + +// ConcatenateError concatenates an error with stderr string +// FIXME: use RunStdError instead func ConcatenateError(err error, stderr string) error { if len(stderr) == 0 { return err } - return fmt.Errorf("%w - %s", err, stderr) + errMsg := fmt.Sprintf("%s - %s", err.Error(), stderr) + return util.ErrorWrap(&runStdError{err: err, stderr: stderr, errMsg: errMsg}, "%s", errMsg) } diff --git a/modules/gitrepo/archive.go b/modules/gitrepo/archive.go index b78922e126..086dc86344 100644 --- a/modules/gitrepo/archive.go +++ b/modules/gitrepo/archive.go @@ -8,7 +8,9 @@ import ( "fmt" "io" "os" + "path" "path/filepath" + "slices" "strings" "code.gitea.io/gitea/modules/git/gitcmd" @@ -16,7 +18,7 @@ import ( ) // CreateArchive create archive content to the target path -func CreateArchive(ctx context.Context, repo Repository, format string, target io.Writer, usePrefix bool, commitID string) error { +func CreateArchive(ctx context.Context, repo Repository, format string, target io.Writer, usePrefix bool, commitID string, paths []string) error { if format == "unknown" { return fmt.Errorf("unknown format: %v", format) } @@ -28,6 +30,13 @@ func CreateArchive(ctx context.Context, repo Repository, format string, target i cmd.AddOptionFormat("--format=%s", format) cmd.AddDynamicArguments(commitID) + paths = slices.Clone(paths) + for i := range paths { + // although "git archive" already ensures the paths won't go outside the repo, we still clean them here for safety + paths[i] = path.Clean(paths[i]) + } + cmd.AddDynamicArguments(paths...) + var stderr strings.Builder if err := RunCmd(ctx, repo, cmd.WithStdout(target).WithStderr(&stderr)); err != nil { return gitcmd.ConcatenateError(err, stderr.String()) diff --git a/modules/test/utils.go b/modules/test/utils.go index 53c6a3ed52..34c11ff6b2 100644 --- a/modules/test/utils.go +++ b/modules/test/utils.go @@ -4,6 +4,9 @@ package test import ( + "archive/tar" + "compress/gzip" + "io" "net/http" "net/http/httptest" "os" @@ -71,3 +74,31 @@ func SetupGiteaRoot() string { _ = os.Setenv("GITEA_ROOT", giteaRoot) return giteaRoot } + +func ReadAllTarGzContent(r io.Reader) (map[string]string, error) { + gzr, err := gzip.NewReader(r) + if err != nil { + return nil, err + } + + content := make(map[string]string) + + tr := tar.NewReader(gzr) + for { + hd, err := tr.Next() + if err == io.EOF { + break + } + if err != nil { + return nil, err + } + + buf, err := io.ReadAll(tr) + if err != nil { + return nil, err + } + + content[hd.Name] = string(buf) + } + return content, nil +} diff --git a/options/locale/locale_en-US.json b/options/locale/locale_en-US.json index 96a541a947..80082c8089 100644 --- a/options/locale/locale_en-US.json +++ b/options/locale/locale_en-US.json @@ -977,6 +977,7 @@ "repo.fork.blocked_user": "Cannot fork the repository because you are blocked by the repository owner.", "repo.use_template": "Use this template", "repo.open_with_editor": "Open with %s", + "repo.download_directory_as": "Download directory as %s", "repo.download_zip": "Download ZIP", "repo.download_tar": "Download TAR.GZ", "repo.download_bundle": "Download BUNDLE", diff --git a/routers/api/v1/repo/download.go b/routers/api/v1/repo/download.go index ea5846d343..5ddda525f9 100644 --- a/routers/api/v1/repo/download.go +++ b/routers/api/v1/repo/download.go @@ -8,25 +8,35 @@ import ( "net/http" repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/services/context" archiver_service "code.gitea.io/gitea/services/repository/archiver" ) -func serveRepoArchive(ctx *context.APIContext, reqFileName string) { - aReq, err := archiver_service.NewRequest(ctx.Repo.Repository, ctx.Repo.GitRepo, reqFileName) +func serveRepoArchive(ctx *context.APIContext, reqFileName string, paths []string) { + aReq, err := archiver_service.NewRequest(ctx.Repo.Repository, ctx.Repo.GitRepo, reqFileName, paths) if err != nil { - if errors.Is(err, archiver_service.ErrUnknownArchiveFormat{}) { + if errors.Is(err, util.ErrInvalidArgument) { ctx.APIError(http.StatusBadRequest, err) - } else if errors.Is(err, archiver_service.RepoRefNotFoundError{}) { + } else if errors.Is(err, util.ErrNotExist) { ctx.APIError(http.StatusNotFound, err) } else { ctx.APIErrorInternal(err) } return } - archiver_service.ServeRepoArchive(ctx.Base, aReq) + err = archiver_service.ServeRepoArchive(ctx.Base, aReq) + if err != nil { + if errors.Is(err, util.ErrInvalidArgument) { + ctx.APIError(http.StatusBadRequest, err) + } else { + ctx.APIErrorInternal(err) + } + } } +// DownloadArchive is the GitHub-compatible endpoint to download repository archives +// TODO: The API document is missing: Add github compatible tarball download API endpoints (#32572) func DownloadArchive(ctx *context.APIContext) { var tp repo_model.ArchiveType switch ballType := ctx.PathParam("ball_type"); ballType { @@ -40,5 +50,5 @@ func DownloadArchive(ctx *context.APIContext) { ctx.APIError(http.StatusBadRequest, "Unknown archive type: "+ballType) return } - serveRepoArchive(ctx, ctx.PathParam("*")+"."+tp.String()) + serveRepoArchive(ctx, ctx.PathParam("*")+"."+tp.String(), ctx.FormStrings("path")) } diff --git a/routers/api/v1/repo/file.go b/routers/api/v1/repo/file.go index 27a0827a10..deb68963c2 100644 --- a/routers/api/v1/repo/file.go +++ b/routers/api/v1/repo/file.go @@ -273,13 +273,19 @@ func GetArchive(ctx *context.APIContext) { // description: the git reference for download with attached archive format (e.g. master.zip) // type: string // required: true + // - name: path + // in: query + // type: array + // items: + // type: string + // description: subpath of the repository to download + // collectionFormat: multi // responses: // 200: // description: success // "404": // "$ref": "#/responses/notFound" - - serveRepoArchive(ctx, ctx.PathParam("*")) + serveRepoArchive(ctx, ctx.PathParam("*"), ctx.FormStrings("path")) } // GetEditorconfig get editor config of a repository diff --git a/routers/web/repo/repo.go b/routers/web/repo/repo.go index 3a0976ffa0..bc2b0264c0 100644 --- a/routers/web/repo/repo.go +++ b/routers/web/repo/repo.go @@ -364,31 +364,39 @@ func RedirectDownload(ctx *context.Context) { // Download an archive of a repository func Download(ctx *context.Context) { - aReq, err := archiver_service.NewRequest(ctx.Repo.Repository, ctx.Repo.GitRepo, ctx.PathParam("*")) + aReq, err := archiver_service.NewRequest(ctx.Repo.Repository, ctx.Repo.GitRepo, ctx.PathParam("*"), ctx.FormStrings("path")) if err != nil { - if errors.Is(err, archiver_service.ErrUnknownArchiveFormat{}) { + if errors.Is(err, util.ErrInvalidArgument) { ctx.HTTPError(http.StatusBadRequest, err.Error()) - } else if errors.Is(err, archiver_service.RepoRefNotFoundError{}) { + } else if errors.Is(err, util.ErrNotExist) { ctx.HTTPError(http.StatusNotFound, err.Error()) } else { ctx.ServerError("archiver_service.NewRequest", err) } return } - archiver_service.ServeRepoArchive(ctx.Base, aReq) + err = archiver_service.ServeRepoArchive(ctx.Base, aReq) + if err != nil { + if errors.Is(err, util.ErrInvalidArgument) { + ctx.HTTPError(http.StatusBadRequest, err.Error()) + } else { + ctx.ServerError("archiver_service.ServeRepoArchive", err) + } + } } // InitiateDownload will enqueue an archival request, as needed. It may submit // a request that's already in-progress, but the archiver service will just // kind of drop it on the floor if this is the case. func InitiateDownload(ctx *context.Context) { - if setting.Repository.StreamArchives { + paths := ctx.FormStrings("path") + if setting.Repository.StreamArchives || len(paths) > 0 { ctx.JSON(http.StatusOK, map[string]any{ "complete": true, }) return } - aReq, err := archiver_service.NewRequest(ctx.Repo.Repository, ctx.Repo.GitRepo, ctx.PathParam("*")) + aReq, err := archiver_service.NewRequest(ctx.Repo.Repository, ctx.Repo.GitRepo, ctx.PathParam("*"), paths) if err != nil { ctx.HTTPError(http.StatusBadRequest, "invalid archive request") return diff --git a/services/pull/commit_status.go b/services/pull/commit_status.go index 25860fc1a8..656bcc50af 100644 --- a/services/pull/commit_status.go +++ b/services/pull/commit_status.go @@ -6,6 +6,8 @@ package pull import ( "context" + "errors" + "fmt" "code.gitea.io/gitea/models/db" git_model "code.gitea.io/gitea/models/git" @@ -14,8 +16,6 @@ import ( "code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/glob" "code.gitea.io/gitea/modules/log" - - "github.com/pkg/errors" ) // MergeRequiredContextsCommitStatus returns a commit status state for given required contexts @@ -69,7 +69,7 @@ func MergeRequiredContextsCommitStatus(commitStatuses []*git_model.CommitStatus, func IsPullCommitStatusPass(ctx context.Context, pr *issues_model.PullRequest) (bool, error) { pb, err := git_model.GetFirstMatchProtectedBranchRule(ctx, pr.BaseRepoID, pr.BaseBranch) if err != nil { - return false, errors.Wrap(err, "GetLatestCommitStatus") + return false, fmt.Errorf("GetLatestCommitStatus: %w", err) } if pb == nil || !pb.EnableStatusCheck { return true, nil @@ -86,19 +86,19 @@ func IsPullCommitStatusPass(ctx context.Context, pr *issues_model.PullRequest) ( func GetPullRequestCommitStatusState(ctx context.Context, pr *issues_model.PullRequest) (commitstatus.CommitStatusState, error) { // Ensure HeadRepo is loaded if err := pr.LoadHeadRepo(ctx); err != nil { - return "", errors.Wrap(err, "LoadHeadRepo") + return "", fmt.Errorf("LoadHeadRepo: %w", err) } // check if all required status checks are successful headGitRepo, closer, err := gitrepo.RepositoryFromContextOrOpen(ctx, pr.HeadRepo) if err != nil { - return "", errors.Wrap(err, "OpenRepository") + return "", fmt.Errorf("OpenRepository: %w", err) } defer closer.Close() if pr.Flow == issues_model.PullRequestFlowGithub { if exist, err := git_model.IsBranchExist(ctx, pr.HeadRepo.ID, pr.HeadBranch); err != nil { - return "", errors.Wrap(err, "IsBranchExist") + return "", fmt.Errorf("IsBranchExist: %w", err) } else if !exist { return "", errors.New("Head branch does not exist, can not merge") } @@ -118,17 +118,17 @@ func GetPullRequestCommitStatusState(ctx context.Context, pr *issues_model.PullR } if err := pr.LoadBaseRepo(ctx); err != nil { - return "", errors.Wrap(err, "LoadBaseRepo") + return "", fmt.Errorf("LoadBaseRepo: %w", err) } commitStatuses, err := git_model.GetLatestCommitStatus(ctx, pr.BaseRepo.ID, sha, db.ListOptionsAll) if err != nil { - return "", errors.Wrap(err, "GetLatestCommitStatus") + return "", fmt.Errorf("GetLatestCommitStatus: %w", err) } pb, err := git_model.GetFirstMatchProtectedBranchRule(ctx, pr.BaseRepoID, pr.BaseBranch) if err != nil { - return "", errors.Wrap(err, "LoadProtectedBranch") + return "", fmt.Errorf("LoadProtectedBranch: %w", err) } var requiredContexts []string if pb != nil { diff --git a/services/repository/archiver/archiver.go b/services/repository/archiver/archiver.go index b2ca74871c..bfd941ebf6 100644 --- a/services/repository/archiver/archiver.go +++ b/services/repository/archiver/archiver.go @@ -8,7 +8,6 @@ import ( "errors" "fmt" "io" - "net/http" "os" "strings" "time" @@ -16,6 +15,7 @@ import ( "code.gitea.io/gitea/models/db" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/git/gitcmd" "code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/graceful" "code.gitea.io/gitea/modules/httplib" @@ -24,6 +24,7 @@ import ( "code.gitea.io/gitea/modules/queue" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/storage" + "code.gitea.io/gitea/modules/util" gitea_context "code.gitea.io/gitea/services/context" ) @@ -36,58 +37,31 @@ type ArchiveRequest struct { Repo *repo_model.Repository Type repo_model.ArchiveType CommitID string + Paths []string archiveRefShortName string // the ref short name to download the archive, for example: "master", "v1.0.0", "commit id" } -// ErrUnknownArchiveFormat request archive format is not supported -type ErrUnknownArchiveFormat struct { - RequestNameType string -} - -// Error implements error -func (err ErrUnknownArchiveFormat) Error() string { - return "unknown format: " + err.RequestNameType -} - -// Is implements error -func (ErrUnknownArchiveFormat) Is(err error) bool { - _, ok := err.(ErrUnknownArchiveFormat) - return ok -} - -// RepoRefNotFoundError is returned when a requested reference (commit, tag) was not found. -type RepoRefNotFoundError struct { - RefShortName string -} - -// Error implements error. -func (e RepoRefNotFoundError) Error() string { - return "unrecognized repository reference: " + e.RefShortName -} - -func (e RepoRefNotFoundError) Is(err error) bool { - _, ok := err.(RepoRefNotFoundError) - return ok -} - // NewRequest creates an archival request, based on the URI. The // resulting ArchiveRequest is suitable for being passed to Await() // if it's determined that the request still needs to be satisfied. -func NewRequest(repo *repo_model.Repository, gitRepo *git.Repository, archiveRefExt string) (*ArchiveRequest, error) { +func NewRequest(repo *repo_model.Repository, gitRepo *git.Repository, archiveRefExt string, paths []string) (*ArchiveRequest, error) { // here the archiveRefShortName is not a clear ref, it could be a tag, branch or commit id archiveRefShortName, archiveType := repo_model.SplitArchiveNameType(archiveRefExt) if archiveType == repo_model.ArchiveUnknown { - return nil, ErrUnknownArchiveFormat{archiveRefExt} + return nil, util.NewInvalidArgumentErrorf("unknown format: %s", archiveRefExt) + } + if archiveType == repo_model.ArchiveBundle && len(paths) != 0 { + return nil, util.NewInvalidArgumentErrorf("cannot specify paths when requesting a bundle") } // Get corresponding commit. commitID, err := gitRepo.ConvertToGitID(archiveRefShortName) if err != nil { - return nil, RepoRefNotFoundError{RefShortName: archiveRefShortName} + return nil, util.NewNotExistErrorf("unrecognized repository reference: %s", archiveRefShortName) } - r := &ArchiveRequest{Repo: repo, archiveRefShortName: archiveRefShortName, Type: archiveType} + r := &ArchiveRequest{Repo: repo, archiveRefShortName: archiveRefShortName, Type: archiveType, Paths: paths} r.CommitID = commitID.String() return r, nil } @@ -159,6 +133,7 @@ func (aReq *ArchiveRequest) Stream(ctx context.Context, w io.Writer) error { w, setting.Repository.PrefixArchiveFiles, aReq.CommitID, + aReq.Paths, ) } @@ -339,7 +314,7 @@ func DeleteRepositoryArchives(ctx context.Context) error { return storage.Clean(storage.RepoArchives) } -func ServeRepoArchive(ctx *gitea_context.Base, archiveReq *ArchiveRequest) { +func ServeRepoArchive(ctx *gitea_context.Base, archiveReq *ArchiveRequest) error { // Add nix format link header so tarballs lock correctly: // https://github.com/nixos/nix/blob/56763ff918eb308db23080e560ed2ea3e00c80a7/doc/manual/src/protocols/tarball-fetcher.md ctx.Resp.Header().Add("Link", fmt.Sprintf(`<%s/archive/%s.%s?rev=%s>; rel="immutable"`, @@ -350,20 +325,22 @@ func ServeRepoArchive(ctx *gitea_context.Base, archiveReq *ArchiveRequest) { )) downloadName := archiveReq.Repo.Name + "-" + archiveReq.GetArchiveName() - if setting.Repository.StreamArchives { + if setting.Repository.StreamArchives || len(archiveReq.Paths) > 0 { + // the header must be set before starting streaming even an error would occur, + // because errors may happen in git command and such cases aren't in our control. httplib.ServeSetHeaders(ctx.Resp, &httplib.ServeHeaderOptions{Filename: downloadName}) if err := archiveReq.Stream(ctx, ctx.Resp); err != nil && !ctx.Written() { - log.Error("Archive %v streaming failed: %v", archiveReq, err) - ctx.HTTPError(http.StatusInternalServerError) + if gitcmd.StderrHasPrefix(err, "fatal: pathspec") { + return util.NewInvalidArgumentErrorf("path doesn't exist or is invalid") + } + return fmt.Errorf("archive repo %s: failed to stream: %w", archiveReq.Repo.FullName(), err) } - return + return nil } archiver, err := archiveReq.Await(ctx) if err != nil { - log.Error("Archive %v await failed: %v", archiveReq, err) - ctx.HTTPError(http.StatusInternalServerError) - return + return fmt.Errorf("archive repo %s: failed to await: %w", archiveReq.Repo.FullName(), err) } rPath := archiver.RelativePath() @@ -372,15 +349,13 @@ func ServeRepoArchive(ctx *gitea_context.Base, archiveReq *ArchiveRequest) { u, err := storage.RepoArchives.URL(rPath, downloadName, ctx.Req.Method, nil) if u != nil && err == nil { ctx.Redirect(u.String()) - return + return nil } } fr, err := storage.RepoArchives.Open(rPath) if err != nil { - log.Error("Archive %v open file failed: %v", archiveReq, err) - ctx.HTTPError(http.StatusInternalServerError) - return + return fmt.Errorf("archive repo %s: failed to open archive file: %w", archiveReq.Repo.FullName(), err) } defer fr.Close() @@ -388,4 +363,5 @@ func ServeRepoArchive(ctx *gitea_context.Base, archiveReq *ArchiveRequest) { Filename: downloadName, LastModified: archiver.CreatedUnix.AsLocalTime(), }) + return nil } diff --git a/services/repository/archiver/archiver_test.go b/services/repository/archiver/archiver_test.go index ae5232f5a1..6cc1856a9c 100644 --- a/services/repository/archiver/archiver_test.go +++ b/services/repository/archiver/archiver_test.go @@ -8,11 +8,13 @@ import ( "time" "code.gitea.io/gitea/models/unittest" + "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/services/contexttest" _ "code.gitea.io/gitea/models/actions" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestMain(m *testing.M) { @@ -29,47 +31,47 @@ func TestArchive_Basic(t *testing.T) { contexttest.LoadGitRepo(t, ctx) defer ctx.Repo.GitRepo.Close() - bogusReq, err := NewRequest(ctx.Repo.Repository, ctx.Repo.GitRepo, firstCommit+".zip") + bogusReq, err := NewRequest(ctx.Repo.Repository, ctx.Repo.GitRepo, firstCommit+".zip", nil) assert.NoError(t, err) assert.NotNil(t, bogusReq) assert.Equal(t, firstCommit+".zip", bogusReq.GetArchiveName()) // Check a series of bogus requests. // Step 1, valid commit with a bad extension. - bogusReq, err = NewRequest(ctx.Repo.Repository, ctx.Repo.GitRepo, firstCommit+".unknown") + bogusReq, err = NewRequest(ctx.Repo.Repository, ctx.Repo.GitRepo, firstCommit+".unknown", nil) assert.Error(t, err) assert.Nil(t, bogusReq) // Step 2, missing commit. - bogusReq, err = NewRequest(ctx.Repo.Repository, ctx.Repo.GitRepo, "dbffff.zip") + bogusReq, err = NewRequest(ctx.Repo.Repository, ctx.Repo.GitRepo, "dbffff.zip", nil) assert.Error(t, err) assert.Nil(t, bogusReq) // Step 3, doesn't look like branch/tag/commit. - bogusReq, err = NewRequest(ctx.Repo.Repository, ctx.Repo.GitRepo, "db.zip") + bogusReq, err = NewRequest(ctx.Repo.Repository, ctx.Repo.GitRepo, "db.zip", nil) assert.Error(t, err) assert.Nil(t, bogusReq) - bogusReq, err = NewRequest(ctx.Repo.Repository, ctx.Repo.GitRepo, "master.zip") + bogusReq, err = NewRequest(ctx.Repo.Repository, ctx.Repo.GitRepo, "master.zip", nil) assert.NoError(t, err) assert.NotNil(t, bogusReq) assert.Equal(t, "master.zip", bogusReq.GetArchiveName()) - bogusReq, err = NewRequest(ctx.Repo.Repository, ctx.Repo.GitRepo, "test/archive.zip") + bogusReq, err = NewRequest(ctx.Repo.Repository, ctx.Repo.GitRepo, "test/archive.zip", nil) assert.NoError(t, err) assert.NotNil(t, bogusReq) assert.Equal(t, "test-archive.zip", bogusReq.GetArchiveName()) // Now two valid requests, firstCommit with valid extensions. - zipReq, err := NewRequest(ctx.Repo.Repository, ctx.Repo.GitRepo, firstCommit+".zip") + zipReq, err := NewRequest(ctx.Repo.Repository, ctx.Repo.GitRepo, firstCommit+".zip", nil) assert.NoError(t, err) assert.NotNil(t, zipReq) - tgzReq, err := NewRequest(ctx.Repo.Repository, ctx.Repo.GitRepo, firstCommit+".tar.gz") + tgzReq, err := NewRequest(ctx.Repo.Repository, ctx.Repo.GitRepo, firstCommit+".tar.gz", nil) assert.NoError(t, err) assert.NotNil(t, tgzReq) - secondReq, err := NewRequest(ctx.Repo.Repository, ctx.Repo.GitRepo, secondCommit+".bundle") + secondReq, err := NewRequest(ctx.Repo.Repository, ctx.Repo.GitRepo, secondCommit+".bundle", nil) assert.NoError(t, err) assert.NotNil(t, secondReq) @@ -89,7 +91,7 @@ func TestArchive_Basic(t *testing.T) { // Sleep two seconds to make sure the queue doesn't change. time.Sleep(2 * time.Second) - zipReq2, err := NewRequest(ctx.Repo.Repository, ctx.Repo.GitRepo, firstCommit+".zip") + zipReq2, err := NewRequest(ctx.Repo.Repository, ctx.Repo.GitRepo, firstCommit+".zip", nil) assert.NoError(t, err) // This zipReq should match what's sitting in the queue, as we haven't // let it release yet. From the consumer's point of view, this looks like @@ -104,12 +106,12 @@ func TestArchive_Basic(t *testing.T) { // Now we'll submit a request and TimedWaitForCompletion twice, before and // after we release it. We should trigger both the timeout and non-timeout // cases. - timedReq, err := NewRequest(ctx.Repo.Repository, ctx.Repo.GitRepo, secondCommit+".tar.gz") + timedReq, err := NewRequest(ctx.Repo.Repository, ctx.Repo.GitRepo, secondCommit+".tar.gz", nil) assert.NoError(t, err) assert.NotNil(t, timedReq) doArchive(t.Context(), timedReq) - zipReq2, err = NewRequest(ctx.Repo.Repository, ctx.Repo.GitRepo, firstCommit+".zip") + zipReq2, err = NewRequest(ctx.Repo.Repository, ctx.Repo.GitRepo, firstCommit+".zip", nil) assert.NoError(t, err) // Now, we're guaranteed to have released the original zipReq from the queue. // Ensure that we don't get handed back the released entry somehow, but they @@ -124,9 +126,13 @@ func TestArchive_Basic(t *testing.T) { // Ideally, the extension would match what we originally requested. assert.NotEqual(t, zipReq.GetArchiveName(), tgzReq.GetArchiveName()) assert.NotEqual(t, zipReq.GetArchiveName(), secondReq.GetArchiveName()) -} -func TestErrUnknownArchiveFormat(t *testing.T) { - err := ErrUnknownArchiveFormat{RequestNameType: "xxx"} - assert.ErrorIs(t, err, ErrUnknownArchiveFormat{}) + t.Run("BadPath", func(t *testing.T) { + badRequest, err := NewRequest(ctx.Repo.Repository, ctx.Repo.GitRepo, firstCommit+".tar.gz", []string{"not-a-path"}) + require.NoError(t, err) + err = ServeRepoArchive(ctx.Base, badRequest) + require.Error(t, err) + assert.ErrorIs(t, err, util.ErrInvalidArgument) + assert.ErrorContains(t, err, "path doesn't exist or is invalid") + }) } diff --git a/templates/repo/view_content.tmpl b/templates/repo/view_content.tmpl index b31648fbbe..5d9b3a94b4 100644 --- a/templates/repo/view_content.tmpl +++ b/templates/repo/view_content.tmpl @@ -100,6 +100,11 @@ {{svg "octicon-link" 16}}{{ctx.Locale.Tr "repo.file_copy_permalink"}} + {{if and (not $.DisableDownloadSourceArchives) $.RefFullName}} +
    + {{svg "octicon-file-zip"}}{{ctx.Locale.Tr "repo.download_directory_as" "ZIP"}} + {{svg "octicon-file-zip"}}{{ctx.Locale.Tr "repo.download_directory_as" "TAR.GZ"}} + {{end}} {{if and (.Permission.CanWrite ctx.Consts.RepoUnitTypeCode) (not .Repository.IsArchived) (not $isTreePathRoot)}}
    diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index 0c33227364..9490154f4b 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -6256,6 +6256,16 @@ "name": "archive", "in": "path", "required": true + }, + { + "type": "array", + "items": { + "type": "string" + }, + "collectionFormat": "multi", + "description": "subpath of the repository to download", + "name": "path", + "in": "query" } ], "responses": { diff --git a/tests/integration/api_packages_arch_test.go b/tests/integration/api_packages_arch_test.go index a0e21fcfc7..4acb745156 100644 --- a/tests/integration/api_packages_arch_test.go +++ b/tests/integration/api_packages_arch_test.go @@ -16,6 +16,7 @@ import ( "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" arch_module "code.gitea.io/gitea/modules/packages/arch" + "code.gitea.io/gitea/modules/test" arch_service "code.gitea.io/gitea/services/packages/arch" "code.gitea.io/gitea/tests" @@ -78,34 +79,6 @@ license = MIT`) return buf.Bytes() } - readIndexContent := func(r io.Reader) (map[string]string, error) { - gzr, err := gzip.NewReader(r) - if err != nil { - return nil, err - } - - content := make(map[string]string) - - tr := tar.NewReader(gzr) - for { - hd, err := tr.Next() - if err == io.EOF { - break - } - if err != nil { - return nil, err - } - - buf, err := io.ReadAll(tr) - if err != nil { - return nil, err - } - - content[hd.Name] = string(buf) - } - - return content, nil - } compressions := []string{"gz", "xz", "zst"} repositories := []string{"main", "testing", "with/slash", ""} @@ -204,7 +177,7 @@ license = MIT`) req := NewRequest(t, "GET", fmt.Sprintf("%s/%s/aarch64/%s", rootURL, repository, arch_service.IndexArchiveFilename)) resp := MakeRequest(t, req, http.StatusOK) - content, err := readIndexContent(resp.Body) + content, err := test.ReadAllTarGzContent(resp.Body) assert.NoError(t, err) desc, has := content[fmt.Sprintf("%s-%s/desc", packageName, packageVersion)] @@ -256,7 +229,7 @@ license = MIT`) req = NewRequest(t, "GET", fmt.Sprintf("%s/%s/aarch64/%s", rootURL, repository, arch_service.IndexArchiveFilename)) resp := MakeRequest(t, req, http.StatusOK) - content, err := readIndexContent(resp.Body) + content, err := test.ReadAllTarGzContent(resp.Body) assert.NoError(t, err) desc, has := content[fmt.Sprintf("%s-%s/desc", packageName, packageVersion)] @@ -311,7 +284,7 @@ license = MIT`) req = NewRequest(t, "GET", fmt.Sprintf("%s/aarch64/%s", rootURL, arch_service.IndexArchiveFilename)) resp := MakeRequest(t, req, http.StatusOK) - content, err := readIndexContent(resp.Body) + content, err := test.ReadAllTarGzContent(resp.Body) assert.NoError(t, err) assert.Len(t, content, 2) @@ -326,7 +299,7 @@ license = MIT`) req = NewRequest(t, "GET", fmt.Sprintf("%s/aarch64/%s", rootURL, arch_service.IndexArchiveFilename)) resp = MakeRequest(t, req, http.StatusOK) - content, err = readIndexContent(resp.Body) + content, err = test.ReadAllTarGzContent(resp.Body) assert.NoError(t, err) assert.Len(t, content, 2) _, has = content["gitea-test-1.0.0/desc"] diff --git a/tests/integration/repo_archive_test.go b/tests/integration/repo_archive_test.go index c64ad1193d..4c190121b8 100644 --- a/tests/integration/repo_archive_test.go +++ b/tests/integration/repo_archive_test.go @@ -15,6 +15,7 @@ import ( "code.gitea.io/gitea/tests" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestRepoDownloadArchive(t *testing.T) { @@ -23,11 +24,35 @@ func TestRepoDownloadArchive(t *testing.T) { defer test.MockVariableValue(&web.GzipMinSize, 10)() defer test.MockVariableValue(&testWebRoutes, routers.NormalRoutes())() - req := NewRequest(t, "GET", "/user2/repo1/archive/master.zip") - req.Header.Set("Accept-Encoding", "gzip") - resp := MakeRequest(t, req, http.StatusOK) - bs, err := io.ReadAll(resp.Body) - assert.NoError(t, err) - assert.Empty(t, resp.Header().Get("Content-Encoding")) - assert.Len(t, bs, 320) + t.Run("NoDuplicateCompression", func(t *testing.T) { + req := NewRequest(t, "GET", "/user2/repo1/archive/master.zip") + req.Header.Set("Accept-Encoding", "gzip") + resp := MakeRequest(t, req, http.StatusOK) + bs, err := io.ReadAll(resp.Body) + assert.NoError(t, err) + assert.Empty(t, resp.Header().Get("Content-Encoding")) + assert.Len(t, bs, 320) + }) + + t.Run("SubPath", func(t *testing.T) { + // When using "archiving and caching" approach, archiving with paths will always use streaming and never be cached + defer test.MockVariableValue(&setting.Repository.StreamArchives, false) // this can be removed if there is always streaming mode + req := NewRequest(t, "GET", "/user2/glob/archive/master.tar.gz?path=aaa.doc&path=x/y") + resp := MakeRequest(t, req, http.StatusOK) + content, err := test.ReadAllTarGzContent(resp.Body) + require.NoError(t, err) + assert.Empty(t, content["glob/a.txt"]) + assert.NotEmpty(t, content["glob/aaa.doc"]) + assert.Empty(t, content["glob/x/b.txt"]) + assert.NotEmpty(t, content["glob/x/y/a.txt"]) + + req = NewRequest(t, "GET", "/user2/glob/archive/master.tar.gz") + resp = MakeRequest(t, req, http.StatusOK) + content, err = test.ReadAllTarGzContent(resp.Body) + require.NoError(t, err) + assert.NotEmpty(t, content["glob/a.txt"]) + assert.NotEmpty(t, content["glob/aaa.doc"]) + assert.NotEmpty(t, content["glob/x/b.txt"]) + assert.NotEmpty(t, content["glob/x/y/a.txt"]) + }) } From 49edbbbc2e3c78efca3d96a665ad560b34e2c587 Mon Sep 17 00:00:00 2001 From: silverwind Date: Fri, 16 Jan 2026 12:00:16 +0100 Subject: [PATCH 23/23] Update JS and PY deps (#36383) - Update JS and PY dependencies - Workaround https://github.com/stylelint/stylelint/issues/8893 by moving the stylint config file to JS - Regenerate SVGs - Bump to python 3.14 in devcontainer and actions - Verified `@github/text-expander-element` - Removed obsolete type stub --- .devcontainer/devcontainer.json | 2 +- .github/labeler.yml | 4 +- .github/workflows/pull-compliance.yml | 4 +- package.json | 16 +- pnpm-lock.yaml | 441 ++++++++++-------- public/assets/img/svg/octicon-logo-github.svg | 2 +- public/assets/img/svg/octicon-mark-github.svg | 2 +- pyproject.toml | 2 +- stylelint.config.ts => stylelint.config.js | 4 +- types.d.ts | 5 - uv.lock | 333 ++++++------- 11 files changed, 436 insertions(+), 379 deletions(-) rename stylelint.config.ts => stylelint.config.js (98%) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 0b20da7c16..4f82a5d8c6 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -13,7 +13,7 @@ "ghcr.io/devcontainers/features/git-lfs:1.2.5": {}, "ghcr.io/jsburckhardt/devcontainer-features/uv:1": {}, "ghcr.io/devcontainers/features/python:1": { - "version": "3.13" + "version": "3.14" }, "ghcr.io/warrenbuckley/codespace-features/sqlite:1": {} }, diff --git a/.github/labeler.yml b/.github/labeler.yml index c940afef0c..64127e50e9 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -46,7 +46,7 @@ modifies/internal: - ".gitpod.yml" - ".markdownlint.yaml" - ".spectral.yaml" - - "stylelint.config.ts" + - "stylelint.config.*" - ".yamllint.yaml" - ".github/**" - ".gitea/**" @@ -89,4 +89,4 @@ topic/code-linting: - ".markdownlint.yaml" - ".spectral.yaml" - ".yamllint.yaml" - - "stylelint.config.ts" + - "stylelint.config.*" diff --git a/.github/workflows/pull-compliance.yml b/.github/workflows/pull-compliance.yml index 99ff95e9c6..fb81622bd6 100644 --- a/.github/workflows/pull-compliance.yml +++ b/.github/workflows/pull-compliance.yml @@ -39,7 +39,7 @@ jobs: steps: - uses: actions/checkout@v6 - uses: astral-sh/setup-uv@v7 - - run: uv python install 3.12 + - run: uv python install 3.14 - uses: pnpm/action-setup@v4 - uses: actions/setup-node@v6 with: @@ -59,7 +59,7 @@ jobs: steps: - uses: actions/checkout@v6 - uses: astral-sh/setup-uv@v7 - - run: uv python install 3.12 + - run: uv python install 3.14 - run: make deps-py - run: make lint-yaml diff --git a/package.json b/package.json index 3867a6c648..9ca7075fa6 100644 --- a/package.json +++ b/package.json @@ -13,9 +13,9 @@ "@github/markdown-toolbar-element": "2.2.3", "@github/paste-markdown": "1.5.3", "@github/relative-time-element": "5.0.0", - "@github/text-expander-element": "2.9.2", + "@github/text-expander-element": "2.9.4", "@mcaptcha/vanilla-glue": "0.1.0-alpha-3", - "@primer/octicons": "19.21.1", + "@primer/octicons": "19.21.2", "@resvg/resvg-wasm": "2.6.2", "@silverwind/vue3-calendar-heatmap": "2.1.1", "@techknowlogick/license-checker-webpack-plugin": "0.3.0", @@ -65,11 +65,11 @@ "wrap-ansi": "9.0.2" }, "devDependencies": { - "@eslint-community/eslint-plugin-eslint-comments": "4.5.0", + "@eslint-community/eslint-plugin-eslint-comments": "4.6.0", "@eslint/json": "0.14.0", "@playwright/test": "1.57.0", "@stylistic/eslint-plugin": "5.7.0", - "@stylistic/stylelint-plugin": "4.0.0", + "@stylistic/stylelint-plugin": "4.0.1", "@types/codemirror": "5.60.17", "@types/dropzone": "5.7.9", "@types/jquery": "3.5.33", @@ -96,15 +96,15 @@ "eslint-plugin-vue-scoped-css": "2.12.0", "eslint-plugin-wc": "3.0.2", "globals": "17.0.0", - "happy-dom": "20.1.0", + "happy-dom": "20.3.0", "jiti": "2.6.1", "markdownlint-cli": "0.47.0", "material-icon-theme": "5.30.0", "nolyfill": "1.0.44", - "postcss-html": "1.8.0", + "postcss-html": "1.8.1", "spectral-cli-bundle": "1.0.3", - "stylelint": "16.26.1", - "stylelint-config-recommended": "17.0.0", + "stylelint": "17.0.0", + "stylelint-config-recommended": "18.0.0", "stylelint-declaration-block-no-ignored-properties": "2.8.0", "stylelint-declaration-strict-value": "1.10.11", "stylelint-value-no-unknown-custom-properties": "6.1.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1b49f68721..0769a6afc5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -48,14 +48,14 @@ importers: specifier: 5.0.0 version: 5.0.0 '@github/text-expander-element': - specifier: 2.9.2 - version: 2.9.2 + specifier: 2.9.4 + version: 2.9.4 '@mcaptcha/vanilla-glue': specifier: 0.1.0-alpha-3 version: 0.1.0-alpha-3 '@primer/octicons': - specifier: 19.21.1 - version: 19.21.1 + specifier: 19.21.2 + version: 19.21.2 '@resvg/resvg-wasm': specifier: 2.6.2 version: 2.6.2 @@ -199,8 +199,8 @@ importers: version: 9.0.2 devDependencies: '@eslint-community/eslint-plugin-eslint-comments': - specifier: 4.5.0 - version: 4.5.0(eslint@9.39.2(jiti@2.6.1)) + specifier: 4.6.0 + version: 4.6.0(eslint@9.39.2(jiti@2.6.1)) '@eslint/json': specifier: 0.14.0 version: 0.14.0 @@ -211,8 +211,8 @@ importers: specifier: 5.7.0 version: 5.7.0(eslint@9.39.2(jiti@2.6.1)) '@stylistic/stylelint-plugin': - specifier: 4.0.0 - version: 4.0.0(stylelint@16.26.1(typescript@5.9.3)) + specifier: 4.0.1 + version: 4.0.1(stylelint@17.0.0(typescript@5.9.3)) '@types/codemirror': specifier: 5.60.17 version: 5.60.17 @@ -248,10 +248,10 @@ importers: version: 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) '@vitejs/plugin-vue': specifier: 6.0.3 - version: 6.0.3(vite@7.3.1(@types/node@25.0.6)(jiti@2.6.1)(stylus@0.57.0)(terser@5.44.1)(yaml@2.8.2))(vue@3.5.26(typescript@5.9.3)) + version: 6.0.3(vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(stylus@0.57.0)(terser@5.45.0)(yaml@2.8.2))(vue@3.5.26(typescript@5.9.3)) '@vitest/eslint-plugin': specifier: 1.6.6 - version: 1.6.6(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)(vitest@4.0.17(@types/node@25.0.6)(happy-dom@20.1.0)(jiti@2.6.1)(stylus@0.57.0)(terser@5.44.1)(yaml@2.8.2)) + version: 1.6.6(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)(vitest@4.0.17(@types/node@25.0.9)(happy-dom@20.3.0)(jiti@2.6.1)(stylus@0.57.0)(terser@5.45.0)(yaml@2.8.2)) eslint: specifier: 9.39.2 version: 9.39.2(jiti@2.6.1) @@ -292,8 +292,8 @@ importers: specifier: 17.0.0 version: 17.0.0 happy-dom: - specifier: 20.1.0 - version: 20.1.0 + specifier: 20.3.0 + version: 20.3.0 jiti: specifier: 2.6.1 version: 2.6.1 @@ -307,26 +307,26 @@ importers: specifier: 1.0.44 version: 1.0.44 postcss-html: - specifier: 1.8.0 - version: 1.8.0 + specifier: 1.8.1 + version: 1.8.1 spectral-cli-bundle: specifier: 1.0.3 version: 1.0.3 stylelint: - specifier: 16.26.1 - version: 16.26.1(typescript@5.9.3) - stylelint-config-recommended: specifier: 17.0.0 - version: 17.0.0(stylelint@16.26.1(typescript@5.9.3)) + version: 17.0.0(typescript@5.9.3) + stylelint-config-recommended: + specifier: 18.0.0 + version: 18.0.0(stylelint@17.0.0(typescript@5.9.3)) stylelint-declaration-block-no-ignored-properties: specifier: 2.8.0 - version: 2.8.0(stylelint@16.26.1(typescript@5.9.3)) + version: 2.8.0(stylelint@17.0.0(typescript@5.9.3)) stylelint-declaration-strict-value: specifier: 1.10.11 - version: 1.10.11(stylelint@16.26.1(typescript@5.9.3)) + version: 1.10.11(stylelint@17.0.0(typescript@5.9.3)) stylelint-value-no-unknown-custom-properties: specifier: 6.1.0 - version: 6.1.0(stylelint@16.26.1(typescript@5.9.3)) + version: 6.1.0(stylelint@17.0.0(typescript@5.9.3)) svgo: specifier: 4.0.0 version: 4.0.0 @@ -344,7 +344,7 @@ importers: version: 1.4.9 vitest: specifier: 4.0.17 - version: 4.0.17(@types/node@25.0.6)(happy-dom@20.1.0)(jiti@2.6.1)(stylus@0.57.0)(terser@5.44.1)(yaml@2.8.2) + version: 4.0.17(@types/node@25.0.9)(happy-dom@20.3.0)(jiti@2.6.1)(stylus@0.57.0)(terser@5.45.0)(yaml@2.8.2) vue-tsc: specifier: 3.2.2 version: 3.2.2(typescript@5.9.3) @@ -461,6 +461,12 @@ packages: peerDependencies: '@csstools/css-tokenizer': ^3.0.4 + '@csstools/css-parser-algorithms@4.0.0': + resolution: {integrity: sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==} + engines: {node: '>=20.19.0'} + peerDependencies: + '@csstools/css-tokenizer': ^4.0.0 + '@csstools/css-syntax-patches-for-csstree@1.0.25': resolution: {integrity: sha512-g0Kw9W3vjx5BEBAF8c5Fm2NcB/Fs8jJXh85aXqwEXiL+tqtOut07TWgyaGzAAfTM+gKckrrncyeGEZPcaRgm2Q==} engines: {node: '>=18'} @@ -469,6 +475,10 @@ packages: resolution: {integrity: sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==} engines: {node: '>=18'} + '@csstools/css-tokenizer@4.0.0': + resolution: {integrity: sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==} + engines: {node: '>=20.19.0'} + '@csstools/media-query-list-parser@4.0.3': resolution: {integrity: sha512-HAYH7d3TLRHDOUQK4mZKf9k9Ph/m8Akstg66ywKR4SFAigjs3yBiUeZtFxywiTm5moZMAp/5W/ZuFnNXXYLuuQ==} engines: {node: '>=18'} @@ -476,19 +486,29 @@ packages: '@csstools/css-parser-algorithms': ^3.0.5 '@csstools/css-tokenizer': ^3.0.4 - '@csstools/selector-specificity@5.0.0': - resolution: {integrity: sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw==} - engines: {node: '>=18'} + '@csstools/media-query-list-parser@5.0.0': + resolution: {integrity: sha512-T9lXmZOfnam3eMERPsszjY5NK0jX8RmThmmm99FZ8b7z8yMaFZWKwLWGZuTwdO3ddRY5fy13GmmEYZXB4I98Eg==} + engines: {node: '>=20.19.0'} peerDependencies: - postcss-selector-parser: ^7.0.0 + '@csstools/css-parser-algorithms': ^4.0.0 + '@csstools/css-tokenizer': ^4.0.0 + + '@csstools/selector-resolve-nested@4.0.0': + resolution: {integrity: sha512-9vAPxmp+Dx3wQBIUwc1v7Mdisw1kbbaGqXUM8QLTgWg7SoPGYtXBsMXvsFs/0Bn5yoFhcktzxNZGNaUt0VjgjA==} + engines: {node: '>=20.19.0'} + peerDependencies: + postcss-selector-parser: ^7.1.1 + + '@csstools/selector-specificity@6.0.0': + resolution: {integrity: sha512-4sSgl78OtOXEX/2d++8A83zHNTgwCJMaR24FvsYL7Uf/VS8HZk9PTwR51elTbGqMuwH3szLvvOXEaVnqn0Z3zA==} + engines: {node: '>=20.19.0'} + peerDependencies: + postcss-selector-parser: ^7.1.1 '@discoveryjs/json-ext@0.6.3': resolution: {integrity: sha512-4B4OijXeVNOPZlYA2oEwWOTkzyltLao+xbotHQeqN++Rv27Y6s818+n2Qkp8q+Fxhn0t/5lA5X1Mxktud8eayQ==} engines: {node: '>=14.17.0'} - '@dual-bundle/import-meta-resolve@4.2.1': - resolution: {integrity: sha512-id+7YRUgoUX6CgV0DtuhirQWodeeA7Lf4i2x71JS/vtA5pRb/hIGWlw+G6MeXvsM+MXrz0VAydTGElX1rAfgPg==} - '@emnapi/core@1.8.1': resolution: {integrity: sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg==} @@ -654,8 +674,8 @@ packages: cpu: [x64] os: [win32] - '@eslint-community/eslint-plugin-eslint-comments@4.5.0': - resolution: {integrity: sha512-MAhuTKlr4y/CE3WYX26raZjy+I/kS2PLKSzvfmDCGrBLTFHOYwqROZdr4XwPgXwX3K9rjzMr4pSmUWGnzsUyMg==} + '@eslint-community/eslint-plugin-eslint-comments@4.6.0': + resolution: {integrity: sha512-2EX2bBQq1ez++xz2o9tEeEQkyvfieWgUFMH4rtJJri2q0Azvhja3hZGXsjPXs31R4fQkZDtWzNDDK2zQn5UE5g==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 @@ -730,8 +750,8 @@ packages: '@github/relative-time-element@5.0.0': resolution: {integrity: sha512-L/2r0DNR/rMbmHWcsdmhtOiy2gESoGOhItNFD4zJ3nZfHl79Dx3N18Vfx/pYr2lruMOdk1cJZb4wEumm+Dxm1w==} - '@github/text-expander-element@2.9.2': - resolution: {integrity: sha512-XY8EUMqM4GAloNxXNA1Py1ny+engWwYntbgsnpstQN4piaTI9rIlfYldyd0nnPXhxjGCVqHPmP6yg17Q0/n9Vg==} + '@github/text-expander-element@2.9.4': + resolution: {integrity: sha512-+zxSlek2r0NrbFmRfymVtYhES9YU033acc/mouXUkN2bs8DaYScPucvBhwg/5d0hsEb2rIykKnkA/2xxWSqCTw==} '@humanfs/core@0.19.1': resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} @@ -894,8 +914,8 @@ packages: '@popperjs/core@2.11.8': resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==} - '@primer/octicons@19.21.1': - resolution: {integrity: sha512-7tgtBkCNcg75YJnckinzvES+uxysYQCe+CHSEnzr3VYgxttzKRvfmrnVogl3aEuHCQP4xhiE9k2lFDhYwGtTzQ==} + '@primer/octicons@19.21.2': + resolution: {integrity: sha512-SRTcpAZtKYh2266VQpAqNkXAQpPvYWk6dxggkHDzwI95NrE5mEzJ7cfFt/bSVbqDffKQ+tm7TEdLHoSjEcggfQ==} '@resvg/resvg-wasm@2.6.2': resolution: {integrity: sha512-FqALmHI8D4o6lk/LRWDnhw95z5eO+eAa6ORjVg09YRR7BkcM6oPHU9uyC0gtQG5vpFLvgpeU4+zEAz2H8APHNw==} @@ -1045,6 +1065,10 @@ packages: '@simonwep/pickr@1.9.0': resolution: {integrity: sha512-oEYvv15PyfZzjoAzvXYt3UyNGwzsrpFxLaZKzkOSd0WYBVwLd19iJerePDONxC1iF6+DpcswPdLIM2KzCJuYFg==} + '@sindresorhus/merge-streams@4.0.0': + resolution: {integrity: sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==} + engines: {node: '>=18'} + '@solid-primitives/refs@1.1.2': resolution: {integrity: sha512-K7tf2thy7L+YJjdqXspXOg5xvNEOH8tgEWsp0+1mQk3obHBRD6hEjYZk7p7FlJphSZImS35je3UfmWuD7MhDfg==} peerDependencies: @@ -1069,8 +1093,8 @@ packages: peerDependencies: eslint: '>=9.0.0' - '@stylistic/stylelint-plugin@4.0.0': - resolution: {integrity: sha512-CFwt3K4Y/7bygNCLCQ8Sy4Hzgbhxq3BsNW0FIuYxl17HD3ywptm54ocyeiLVRrk5jtz1Zwks7Xr9eiZt8SWHAw==} + '@stylistic/stylelint-plugin@4.0.1': + resolution: {integrity: sha512-jKZSZr/S/NehfgayNJI3O/JEq+W5lSeHUJNvdOebRPNFP2ZylTbAx/p5qR8scQFpiVzy1VQM9R+G0kIB62r1Pw==} engines: {node: ^18.12 || >=20.9} peerDependencies: stylelint: ^16.22.0 @@ -1227,11 +1251,11 @@ packages: '@types/ms@2.1.0': resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} - '@types/node@20.19.28': - resolution: {integrity: sha512-VyKBr25BuFDzBFCK5sUM6ZXiWfqgCTwTAOK8qzGV/m9FCirXYDlmczJ+d5dXBAQALGCdRRdbteKYfJ84NGEusw==} + '@types/node@20.19.30': + resolution: {integrity: sha512-WJtwWJu7UdlvzEAUm484QNg5eAoq5QR08KDNx7g45Usrs2NtOPiX8ugDqmKdXkyL03rBqU5dYNYVQetEpBHq2g==} - '@types/node@25.0.6': - resolution: {integrity: sha512-NNu0sjyNxpoiW3YuVFfNz7mxSQ+S4X2G28uqg2s+CzoqoQjLPsWSbsFFyztIAqt2vb8kfEAsJNepMGPTxFDx3Q==} + '@types/node@25.0.9': + resolution: {integrity: sha512-/rpCXHlCWeqClNBwUhDcusJxXYDjZTyE8v5oTO7WbL8eij2nKhUeU89/6xgjU7N4/Vh3He0BtyhJdQbDyhiXAw==} '@types/pdfobject@2.2.5': resolution: {integrity: sha512-7gD5tqc/RUDq0PyoLemL0vEHxBYi+zY0WVaFAx/Y0jBsXFgot1vB9No1GhDZGwRGJMCIZbgAb74QG9MTyTNU/g==} @@ -1676,10 +1700,6 @@ packages: resolution: {integrity: sha512-M1HQyIXcBGtVywBt8WVdim+lrNaK7VHp99Qt5pSNziXznKHViIBbXWtfRTpEFpF/c4FdfxNAsCCwPp5phBYJtw==} engines: {node: '>=0.10.0'} - array-union@2.1.0: - resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} - engines: {node: '>=8'} - asciinema-player@3.14.0: resolution: {integrity: sha512-44m3CpNavn8i7DSr/AeeV+rJpHpcqc/OCildCs9FAu5gnXB6XNBdbhfg6mHMG4uU3R1rxFNA3ZRTt8FMhHC48Q==} @@ -1710,8 +1730,9 @@ packages: balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - balanced-match@2.0.0: - resolution: {integrity: sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA==} + balanced-match@3.0.1: + resolution: {integrity: sha512-vjtV3hiLqYDNRoiAv0zC4QaGAMPomEoq83PRmYIofPswwZurCeWR5LByXm7SyoL0Zh5+2z0+HC7jG8gSZJUh0w==} + engines: {node: '>= 16'} base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} @@ -2053,8 +2074,8 @@ packages: resolution: {integrity: sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==} engines: {node: '>=12'} - d3-format@3.1.0: - resolution: {integrity: sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==} + d3-format@3.1.2: + resolution: {integrity: sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==} engines: {node: '>=12'} d3-geo@3.1.1: @@ -2193,10 +2214,6 @@ packages: didyoumean@1.2.2: resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} - dir-glob@3.0.1: - resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} - engines: {node: '>=8'} - dlv@1.1.3: resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} @@ -2430,8 +2447,8 @@ packages: peerDependencies: eslint: '>=8.40.0' - eslint-plugin-prettier@5.5.4: - resolution: {integrity: sha512-swNtI95SToIz05YINMA6Ox5R057IMAmWZ26GqPxusAp1TZzj+IdY9tXNWWD3vkF/wEqydCONcwjTFpxybBqZsg==} + eslint-plugin-prettier@5.5.5: + resolution: {integrity: sha512-hscXkbqUZ2sPithAuLm5MXL+Wph+U7wHngPBv9OMWwlP8iaflyxpjTYZkmdgB4/vPIhemRlBEoLrH7UC1n7aUw==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: '@types/eslint': '>=8.0.0' @@ -2702,9 +2719,9 @@ packages: resolution: {integrity: sha512-gv5BeD2EssA793rlFWVPMMCqefTlpusw6/2TbAVMy0FzcG8wKJn4O+NqJ4+XWmmwrayJgw5TzrmWjFgmz1XPqw==} engines: {node: '>=18'} - globby@11.1.0: - resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} - engines: {node: '>=10'} + globby@16.1.0: + resolution: {integrity: sha512-+A4Hq7m7Ze592k9gZRy4gJ27DrXRNnC1vPjxTt1qQxEY8RxagBkBxivkCwg7FxSTG0iLLEMaUx13oOr0R2/qcQ==} + engines: {node: '>=20'} globjoin@0.1.4: resolution: {integrity: sha512-xYfnw62CKG8nLkZBfWbhWwDw02CHty86jfPcc2cr3ZfeuK9ysoVPPEUxf21bAD/rWAgk52SuBrLJlefNy8mvFg==} @@ -2719,14 +2736,18 @@ packages: resolution: {integrity: sha512-tSQXBXS/MWQOn/RKckawJ61vvsDpCom87JgxiYdGwHdOa0ht0vzUWDlfioofFCRU0L+6NGDt6XzbgoJvZkMeRQ==} engines: {node: '>=0.8.0'} - happy-dom@20.1.0: - resolution: {integrity: sha512-ebvqjBqzenBk2LjzNEAzoj7yhw7rW/R2/wVevMu6Mrq3MXtcI/RUz4+ozpcOcqVLEWPqLfg2v9EAU7fFXZUUJw==} + happy-dom@20.3.0: + resolution: {integrity: sha512-5qJbkqcvR8j/a4av5IWqqIWmEGf9dt6OhGMS6qxCgjSOBGzGa5XLoqg40OyD8XNzQ+g1g2zsXi10kjfpzYH55Q==} engines: {node: '>=20.0.0'} has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} + has-flag@5.0.1: + resolution: {integrity: sha512-CsNUt5x9LUdx6hnk/E2SZLsDyvfqANZSUq4+D3D8RzDJ2M+HDTIkF60ibS1vHaK55vzgiZw1bEPFG9yH7l33wA==} + engines: {node: '>=12'} + hash-sum@2.0.0: resolution: {integrity: sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg==} @@ -2737,9 +2758,9 @@ packages: hookified@1.15.0: resolution: {integrity: sha512-51w+ZZGt7Zw5q7rM3nC4t3aLn/xvKDETsXqMczndvwyVQhAHfUmUuFBRFcos8Iyebtk7OAE9dL26wFNzZVVOkw==} - html-tags@3.3.1: - resolution: {integrity: sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==} - engines: {node: '>=8'} + html-tags@5.1.0: + resolution: {integrity: sha512-n6l5uca7/y5joxZ3LUePhzmBFUJ+U2YWzhMa8XUTecSeSlQiZdF5XAd/Q3/WUl0VsXgUwWi8I7CNIwdI5WN1SQ==} + engines: {node: '>=20.10'} htmlparser2@8.0.2: resolution: {integrity: sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==} @@ -2780,6 +2801,9 @@ packages: engines: {node: '>=8'} hasBin: true + import-meta-resolve@4.2.0: + resolution: {integrity: sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==} + imurmurhash@0.1.4: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} @@ -2858,6 +2882,10 @@ packages: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} + is-path-inside@4.0.0: + resolution: {integrity: sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA==} + engines: {node: '>=12'} + is-plain-object@2.0.4: resolution: {integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==} engines: {node: '>=0.10.0'} @@ -3094,8 +3122,8 @@ packages: resolution: {integrity: sha512-GAB9vZGEVBQWD7NfZpx6mzkV47IJ6MaSFRLTXIhk9eCKrHbT5BlCwkeieu1Db/hDJHrQ/n+RdMvGtZa70FCGCQ==} engines: {vscode: ^1.55.0} - mathml-tag-names@2.1.3: - resolution: {integrity: sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg==} + mathml-tag-names@4.0.0: + resolution: {integrity: sha512-aa6AU2Pcx0VP/XWnh8IGL0SYSgQHDT6Ucror2j2mXeFAlN3ahaNs8EZtG1YiticMkSLj3Gt6VPFfZogt7G5iFQ==} mdn-data@2.0.28: resolution: {integrity: sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==} @@ -3106,9 +3134,9 @@ packages: mdurl@2.0.0: resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==} - meow@13.2.0: - resolution: {integrity: sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==} - engines: {node: '>=18'} + meow@14.0.0: + resolution: {integrity: sha512-JhC3R1f6dbspVtmF3vKjAWz1EVIvwFrGGPLSdU6rK79xBwHWTuHoLnRX/t1/zHS1Ch1Y2UtIrih7DAHuH9JFJA==} + engines: {node: '>=20'} merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} @@ -3379,10 +3407,6 @@ packages: path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} - path-type@4.0.0: - resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} - engines: {node: '>=8'} - pathe@2.0.3: resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} @@ -3438,8 +3462,8 @@ packages: points-on-path@0.2.1: resolution: {integrity: sha512-25ClnWWuw7JbWZcgqY/gJ4FQWadKxGWk+3kR/7kD0tCaDtPPMj7oHu2ToLaVhfpnHrZzYby2w6tUA0eOIuUg8g==} - postcss-html@1.8.0: - resolution: {integrity: sha512-5mMeb1TgLWoRKxZ0Xh9RZDfwUUIqRrcxO2uXO+Ezl1N5lqpCiSU5Gk6+1kZediBfBHFtPCdopr2UZ2SgUsKcgQ==} + postcss-html@1.8.1: + resolution: {integrity: sha512-OLF6P7qctfAWayOhLpcVnTGqVeJzu2W3WpIYelfz2+JV5oGxfkcEvweN9U4XpeqE0P98dcD9ssusGwlF0TK0uQ==} engines: {node: ^12 || >=14} postcss-import@15.1.0: @@ -3509,9 +3533,6 @@ packages: peerDependencies: postcss: ^8.2.14 - postcss-resolve-nested-selector@0.1.6: - resolution: {integrity: sha512-0sglIs9Wmkzbr8lQwEyIzlDOOC9bGmfVKcJTaxv3vMmd3uo4o4DerC3En0bnmgceeql9BfC8hRkp7cg0fjdVqw==} - postcss-safe-parser@6.0.0: resolution: {integrity: sha512-FARHN8pwH+WiS2OPCxJI8FuRJpTVnn6ZNFiqAM2aeW2LwTHWWmWgIyKC6cUo0L8aeKiF/14MNvnpls6R2PBeMQ==} engines: {node: '>=12.0'} @@ -3557,8 +3578,8 @@ packages: resolution: {integrity: sha512-SxToR7P8Y2lWmv/kTzVLC1t/GDI2WGjMwNhLLE9qtH8Q13C+aEmuRlzDst4Up4s0Wc8sF2M+J57iB3cMLqftfg==} engines: {node: '>=6.0.0'} - prettier@3.7.4: - resolution: {integrity: sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==} + prettier@3.8.0: + resolution: {integrity: sha512-yEPsovQfpxYfgWNhCfECjG5AQaO+K3dp6XERmOepyPDVqcJm+bjyCVO3pmU+nAPe0N5dDvekfGezt/EIiRe1TA==} engines: {node: '>=14'} hasBin: true @@ -3721,9 +3742,9 @@ packages: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} - slash@3.0.0: - resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} - engines: {node: '>=8'} + slash@5.1.0: + resolution: {integrity: sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==} + engines: {node: '>=14.16'} slice-ansi@4.0.0: resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==} @@ -3838,11 +3859,11 @@ packages: style-search@0.1.0: resolution: {integrity: sha512-Dj1Okke1C3uKKwQcetra4jSuk0DqbzbYtXipzFlFMZtowbF1x7BKJwB9AayVMyFARvU8EDrZdcax4At/452cAg==} - stylelint-config-recommended@17.0.0: - resolution: {integrity: sha512-WaMSdEiPfZTSFVoYmJbxorJfA610O0tlYuU2aEwY33UQhSPgFbClrVJYWvy3jGJx+XW37O+LyNLiZOEXhKhJmA==} - engines: {node: '>=18.12.0'} + stylelint-config-recommended@18.0.0: + resolution: {integrity: sha512-mxgT2XY6YZ3HWWe3Di8umG6aBmWmHTblTgu/f10rqFXnyWxjKWwNdjSWkgkwCtxIKnqjSJzvFmPT5yabVIRxZg==} + engines: {node: '>=20.19.0'} peerDependencies: - stylelint: ^16.23.0 + stylelint: ^17.0.0 stylelint-declaration-block-no-ignored-properties@2.8.0: resolution: {integrity: sha512-Ws8Cav7Y+SPN0JsV407LrnNXWOrqGjxShf+37GBtnU/C58Syve9c0+I/xpLcFOosST3ternykn3Lp77f3ITnFw==} @@ -3862,9 +3883,9 @@ packages: peerDependencies: stylelint: '>=16' - stylelint@16.26.1: - resolution: {integrity: sha512-v20V59/crfc8sVTAtge0mdafI3AdnzQ2KsWe6v523L4OA1bJO02S7MO2oyXDCS6iWb9ckIPnqAFVItqSBQr7jw==} - engines: {node: '>=18.12.0'} + stylelint@17.0.0: + resolution: {integrity: sha512-saMZ2mqdQre4AfouxcbTdpVglDRcROb4MIucKHvgsDb/0IX7ODhcaz+EOIyfxAsm8Zjl/7j4hJj6MgIYYM8Xwg==} + engines: {node: '>=20.19.0'} hasBin: true stylis@4.3.6: @@ -3882,6 +3903,10 @@ packages: superstruct@0.10.13: resolution: {integrity: sha512-W4SitSZ9MOyMPbHreoZVEneSZyPEeNGbdfJo/7FkJyRs/M3wQRFzq+t3S/NBwlrFSWdx1ONLjLb9pB+UKe4IqQ==} + supports-color@10.2.2: + resolution: {integrity: sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==} + engines: {node: '>=18'} + supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} @@ -3890,9 +3915,9 @@ packages: resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} engines: {node: '>=10'} - supports-hyperlinks@3.2.0: - resolution: {integrity: sha512-zFObLMyZeEwzAoKCyu1B91U79K2t7ApXuQfo8OuxwXLDgcKxuwM+YvcbIhm6QWqz7mHUH1TVytR1PwVVjEuMig==} - engines: {node: '>=14.18'} + supports-hyperlinks@4.4.0: + resolution: {integrity: sha512-UKbpT93hN5Nr9go5UY7bopIB9YQlMz9nm/ct4IXt/irb5YRkn9WaqrOBJGZ5Pwvsd5FQzSVeYlGdXoCAPQZrPg==} + engines: {node: '>=20'} supports-preserve-symlinks-flag@1.0.0: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} @@ -3919,8 +3944,8 @@ packages: resolution: {integrity: sha512-esiWJ7ixSKGpd9DJPBTC4ckChqdOjIwJfYhVHkcQ2Gnm41323p1TRmEI+esTQ9ppD+b5opps2OTEGTCGX5kF+g==} engines: {node: '>=14'} - synckit@0.11.11: - resolution: {integrity: sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==} + synckit@0.11.12: + resolution: {integrity: sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ==} engines: {node: ^14.18.0 || >=16.0.0} table@6.9.0: @@ -3952,8 +3977,8 @@ packages: uglify-js: optional: true - terser@5.44.1: - resolution: {integrity: sha512-t/R3R/n0MSwnnazuPpPNVO60LX0SKL45pyl9YlvxIdkH0Of7D5qM2EVe+yASRIlY5pZ73nclYJfNANGWPwFDZw==} + terser@5.45.0: + resolution: {integrity: sha512-hQ9c+JZEnMug8eqzuU48sCeq95f00lLDAaJ5gWhRkFXsfy3+SUkZXiF/Z66ZO6EomSmgqXnkhVrWXKaQ8K41Ug==} engines: {node: '>=10'} hasBin: true @@ -4046,8 +4071,8 @@ packages: uc.micro@2.1.0: resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==} - ufo@1.6.2: - resolution: {integrity: sha512-heMioaxBcG9+Znsda5Q8sQbWnLJSl98AFDXTO80wELWEzX3hordXsTdxrIfMQoO9IY1MEnoGoPjpoKpMj+Yx0Q==} + ufo@1.6.3: + resolution: {integrity: sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==} uint8-to-base64@0.2.1: resolution: {integrity: sha512-uO/84GaoDUfiAxpa8EksjVLE77A9Kc7ZTziN4zRpq4de9yLaLcZn3jx1/sVjyupsywcVX6RKWbqLe7gUNyzH+Q==} @@ -4058,6 +4083,10 @@ packages: undici-types@7.16.0: resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} + unicorn-magic@0.4.0: + resolution: {integrity: sha512-wH590V9VNgYH9g3lH9wWjTrUoKsjLF6sGLjhR4sH1LWpLmCOH0Zf7PukhDA8BiS7KHe4oPNkcTHqYkj7SOGUOw==} + engines: {node: '>=20'} + unrs-resolver@1.11.1: resolution: {integrity: sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==} @@ -4226,8 +4255,8 @@ packages: typescript: optional: true - watchpack@2.5.0: - resolution: {integrity: sha512-e6vZvY6xboSwLz2GD36c16+O/2Z6fKvIf4pOXptw2rY9MVwE/TXc6RGqxD3I3x0a28lwBY7DE+76uTPSsBrrCA==} + watchpack@2.5.1: + resolution: {integrity: sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==} engines: {node: '>=10.13.0'} webidl-conversions@3.0.1: @@ -4307,9 +4336,9 @@ packages: wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - write-file-atomic@5.0.1: - resolution: {integrity: sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + write-file-atomic@7.0.0: + resolution: {integrity: sha512-YnlPC6JqnZl6aO4uRc+dx5PHguiR9S6WeoLtpxNT9wIG+BDya7ZNE1q7KOjVgaA73hKhKLpVPgJ5QA9THQ5BRg==} + engines: {node: ^20.17.0 || >=22.9.0} ws@8.19.0: resolution: {integrity: sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==} @@ -4465,23 +4494,36 @@ snapshots: dependencies: '@csstools/css-tokenizer': 3.0.4 + '@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0)': + dependencies: + '@csstools/css-tokenizer': 4.0.0 + '@csstools/css-syntax-patches-for-csstree@1.0.25': {} '@csstools/css-tokenizer@3.0.4': {} + '@csstools/css-tokenizer@4.0.0': {} + '@csstools/media-query-list-parser@4.0.3(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)': dependencies: '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) '@csstools/css-tokenizer': 3.0.4 - '@csstools/selector-specificity@5.0.0(postcss-selector-parser@7.1.1)': + '@csstools/media-query-list-parser@5.0.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': + dependencies: + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + + '@csstools/selector-resolve-nested@4.0.0(postcss-selector-parser@7.1.1)': + dependencies: + postcss-selector-parser: 7.1.1 + + '@csstools/selector-specificity@6.0.0(postcss-selector-parser@7.1.1)': dependencies: postcss-selector-parser: 7.1.1 '@discoveryjs/json-ext@0.6.3': {} - '@dual-bundle/import-meta-resolve@4.2.1': {} - '@emnapi/core@1.8.1': dependencies: '@emnapi/wasi-threads': 1.1.0 @@ -4576,11 +4618,11 @@ snapshots: '@esbuild/win32-x64@0.27.2': optional: true - '@eslint-community/eslint-plugin-eslint-comments@4.5.0(eslint@9.39.2(jiti@2.6.1))': + '@eslint-community/eslint-plugin-eslint-comments@4.6.0(eslint@9.39.2(jiti@2.6.1))': dependencies: escape-string-regexp: 4.0.0 eslint: 9.39.2(jiti@2.6.1) - ignore: 5.3.2 + ignore: 7.0.5 '@eslint-community/eslint-utils@4.9.1(eslint@9.39.2(jiti@2.6.1))': dependencies: @@ -4653,7 +4695,7 @@ snapshots: '@github/relative-time-element@5.0.0': {} - '@github/text-expander-element@2.9.2': + '@github/text-expander-element@2.9.4': dependencies: '@github/combobox-nav': 2.3.1 dom-input-range: 2.0.1 @@ -4803,7 +4845,7 @@ snapshots: '@popperjs/core@2.11.8': {} - '@primer/octicons@19.21.1': + '@primer/octicons@19.21.2': dependencies: object-assign: 4.1.1 @@ -4900,6 +4942,8 @@ snapshots: core-js: 3.32.2 nanopop: 2.3.0 + '@sindresorhus/merge-streams@4.0.0': {} + '@solid-primitives/refs@1.1.2(solid-js@1.9.10)': dependencies: '@solid-primitives/utils': 6.3.2(solid-js@1.9.10) @@ -4925,7 +4969,7 @@ snapshots: estraverse: 5.3.0 picomatch: 4.0.3 - '@stylistic/stylelint-plugin@4.0.0(stylelint@16.26.1(typescript@5.9.3))': + '@stylistic/stylelint-plugin@4.0.1(stylelint@17.0.0(typescript@5.9.3))': dependencies: '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) '@csstools/css-tokenizer': 3.0.4 @@ -4934,7 +4978,7 @@ snapshots: postcss-selector-parser: 7.1.1 postcss-value-parser: 4.2.0 style-search: 0.1.0 - stylelint: 16.26.1(typescript@5.9.3) + stylelint: 17.0.0(typescript@5.9.3) '@swc/helpers@0.2.14': {} @@ -5122,11 +5166,11 @@ snapshots: '@types/ms@2.1.0': {} - '@types/node@20.19.28': + '@types/node@20.19.30': dependencies: undici-types: 6.21.0 - '@types/node@25.0.6': + '@types/node@25.0.9': dependencies: undici-types: 7.16.0 @@ -5157,7 +5201,7 @@ snapshots: '@types/ws@8.18.1': dependencies: - '@types/node': 20.19.28 + '@types/node': 20.19.30 '@typescript-eslint/eslint-plugin@8.53.0(@typescript-eslint/parser@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': dependencies: @@ -5309,20 +5353,20 @@ snapshots: '@unrs/resolver-binding-win32-x64-msvc@1.11.1': optional: true - '@vitejs/plugin-vue@6.0.3(vite@7.3.1(@types/node@25.0.6)(jiti@2.6.1)(stylus@0.57.0)(terser@5.44.1)(yaml@2.8.2))(vue@3.5.26(typescript@5.9.3))': + '@vitejs/plugin-vue@6.0.3(vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(stylus@0.57.0)(terser@5.45.0)(yaml@2.8.2))(vue@3.5.26(typescript@5.9.3))': dependencies: '@rolldown/pluginutils': 1.0.0-beta.53 - vite: 7.3.1(@types/node@25.0.6)(jiti@2.6.1)(stylus@0.57.0)(terser@5.44.1)(yaml@2.8.2) + vite: 7.3.1(@types/node@25.0.9)(jiti@2.6.1)(stylus@0.57.0)(terser@5.45.0)(yaml@2.8.2) vue: 3.5.26(typescript@5.9.3) - '@vitest/eslint-plugin@1.6.6(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)(vitest@4.0.17(@types/node@25.0.6)(happy-dom@20.1.0)(jiti@2.6.1)(stylus@0.57.0)(terser@5.44.1)(yaml@2.8.2))': + '@vitest/eslint-plugin@1.6.6(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)(vitest@4.0.17(@types/node@25.0.9)(happy-dom@20.3.0)(jiti@2.6.1)(stylus@0.57.0)(terser@5.45.0)(yaml@2.8.2))': dependencies: '@typescript-eslint/scope-manager': 8.53.0 '@typescript-eslint/utils': 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) eslint: 9.39.2(jiti@2.6.1) optionalDependencies: typescript: 5.9.3 - vitest: 4.0.17(@types/node@25.0.6)(happy-dom@20.1.0)(jiti@2.6.1)(stylus@0.57.0)(terser@5.44.1)(yaml@2.8.2) + vitest: 4.0.17(@types/node@25.0.9)(happy-dom@20.3.0)(jiti@2.6.1)(stylus@0.57.0)(terser@5.45.0)(yaml@2.8.2) transitivePeerDependencies: - supports-color @@ -5335,13 +5379,13 @@ snapshots: chai: 6.2.2 tinyrainbow: 3.0.3 - '@vitest/mocker@4.0.17(vite@7.3.1(@types/node@25.0.6)(jiti@2.6.1)(stylus@0.57.0)(terser@5.44.1)(yaml@2.8.2))': + '@vitest/mocker@4.0.17(vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(stylus@0.57.0)(terser@5.45.0)(yaml@2.8.2))': dependencies: '@vitest/spy': 4.0.17 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 7.3.1(@types/node@25.0.6)(jiti@2.6.1)(stylus@0.57.0)(terser@5.44.1)(yaml@2.8.2) + vite: 7.3.1(@types/node@25.0.9)(jiti@2.6.1)(stylus@0.57.0)(terser@5.45.0)(yaml@2.8.2) '@vitest/pretty-format@4.0.17': dependencies: @@ -5602,8 +5646,6 @@ snapshots: array-find-index@1.0.2: {} - array-union@2.1.0: {} - asciinema-player@3.14.0: dependencies: '@babel/runtime': 7.28.6 @@ -5624,7 +5666,7 @@ snapshots: balanced-match@1.0.2: {} - balanced-match@2.0.0: {} + balanced-match@3.0.1: {} base64-js@1.5.1: {} @@ -5947,7 +5989,7 @@ snapshots: d3-quadtree: 3.0.1 d3-timer: 3.0.1 - d3-format@3.1.0: {} + d3-format@3.1.2: {} d3-geo@3.1.1: dependencies: @@ -5982,7 +6024,7 @@ snapshots: d3-scale@4.0.2: dependencies: d3-array: 3.2.4 - d3-format: 3.1.0 + d3-format: 3.1.2 d3-interpolate: 3.0.1 d3-time: 3.1.0 d3-time-format: 4.1.0 @@ -6039,7 +6081,7 @@ snapshots: d3-ease: 3.0.1 d3-fetch: 3.0.1 d3-force: 3.0.0 - d3-format: 3.1.0 + d3-format: 3.1.2 d3-geo: 3.1.1 d3-hierarchy: 3.1.2 d3-interpolate: 3.0.1 @@ -6101,10 +6143,6 @@ snapshots: didyoumean@1.2.2: {} - dir-glob@3.0.1: - dependencies: - path-type: 4.0.0 - dlv@1.1.3: {} doctrine@2.1.0: @@ -6318,11 +6356,11 @@ snapshots: eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@4.4.4)(eslint@9.39.2(jiti@2.6.1)) eslint-plugin-jsx-a11y: 6.10.2(eslint@9.39.2(jiti@2.6.1)) 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@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1))(prettier@3.7.4) + eslint-plugin-prettier: 5.5.5(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1))(prettier@3.8.0) eslint-rule-documentation: 1.0.23 globals: 16.5.0 jsx-ast-utils: 3.3.5 - prettier: 3.7.4 + prettier: 3.8.0 svg-element-attributes: 1.3.1 typescript: 5.9.3 typescript-eslint: 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) @@ -6409,12 +6447,12 @@ snapshots: eslint: 9.39.2(jiti@2.6.1) globals: 16.5.0 - eslint-plugin-prettier@5.5.4(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1))(prettier@3.7.4): + eslint-plugin-prettier@5.5.5(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1))(prettier@3.8.0): dependencies: eslint: 9.39.2(jiti@2.6.1) - prettier: 3.7.4 + prettier: 3.8.0 prettier-linter-helpers: 1.0.1 - synckit: 0.11.11 + synckit: 0.11.12 optionalDependencies: '@types/eslint': 9.6.1 eslint-config-prettier: 10.1.8(eslint@9.39.2(jiti@2.6.1)) @@ -6724,14 +6762,14 @@ snapshots: globals@17.0.0: {} - globby@11.1.0: + globby@16.1.0: dependencies: - array-union: 2.1.0 - dir-glob: 3.0.1 + '@sindresorhus/merge-streams': 4.0.0 fast-glob: 3.3.3 - ignore: 5.3.2 - merge2: 1.4.1 - slash: 3.0.0 + ignore: 7.0.5 + is-path-inside: 4.0.0 + slash: 5.1.0 + unicorn-magic: 0.4.0 globjoin@0.1.4: {} @@ -6741,9 +6779,9 @@ snapshots: hammerjs@2.0.8: {} - happy-dom@20.1.0: + happy-dom@20.3.0: dependencies: - '@types/node': 20.19.28 + '@types/node': 20.19.30 '@types/whatwg-mimetype': 3.0.2 '@types/ws': 8.18.1 whatwg-mimetype: 3.0.0 @@ -6754,6 +6792,8 @@ snapshots: has-flag@4.0.0: {} + has-flag@5.0.1: {} + hash-sum@2.0.0: {} hashery@1.4.0: @@ -6762,7 +6802,7 @@ snapshots: hookified@1.15.0: {} - html-tags@3.3.1: {} + html-tags@5.1.0: {} htmlparser2@8.0.2: dependencies: @@ -6799,6 +6839,8 @@ snapshots: pkg-dir: 4.2.0 resolve-cwd: 3.0.0 + import-meta-resolve@4.2.0: {} + imurmurhash@0.1.4: {} indent-string@5.0.0: {} @@ -6857,6 +6899,8 @@ snapshots: is-number@7.0.0: {} + is-path-inside@4.0.0: {} + is-plain-object@2.0.4: dependencies: isobject: 3.0.1 @@ -6875,7 +6919,7 @@ snapshots: jest-worker@27.5.1: dependencies: - '@types/node': 25.0.6 + '@types/node': 25.0.9 merge-stream: 2.0.0 supports-color: 8.1.1 @@ -7076,7 +7120,7 @@ snapshots: fast-deep-equal: 3.1.3 svgson: 5.3.1 - mathml-tag-names@2.1.3: {} + mathml-tag-names@4.0.0: {} mdn-data@2.0.28: {} @@ -7084,7 +7128,7 @@ snapshots: mdurl@2.0.0: {} - meow@13.2.0: {} + meow@14.0.0: {} merge-stream@2.0.0: {} @@ -7321,7 +7365,7 @@ snapshots: acorn: 8.15.0 pathe: 2.0.3 pkg-types: 1.3.1 - ufo: 1.6.2 + ufo: 1.6.3 monaco-editor-webpack-plugin@7.1.1(monaco-editor@0.55.1)(webpack@5.104.1): dependencies: @@ -7452,8 +7496,6 @@ snapshots: path-parse@1.0.7: {} - path-type@4.0.0: {} - pathe@2.0.3: {} pdfobject@2.3.1: {} @@ -7497,7 +7539,7 @@ snapshots: path-data-parser: 0.1.0 points-on-curve: 0.2.0 - postcss-html@1.8.0: + postcss-html@1.8.1: dependencies: htmlparser2: 8.0.2 js-tokens: 9.0.1 @@ -7560,8 +7602,6 @@ snapshots: postcss: 8.5.6 postcss-selector-parser: 6.1.2 - postcss-resolve-nested-selector@0.1.6: {} - postcss-safe-parser@6.0.0(postcss@8.5.6): dependencies: postcss: 8.5.6 @@ -7608,7 +7648,7 @@ snapshots: dependencies: fast-diff: 1.3.0 - prettier@3.7.4: {} + prettier@3.8.0: {} punycode.js@2.3.1: {} @@ -7773,7 +7813,7 @@ snapshots: signal-exit@4.1.0: {} - slash@3.0.0: {} + slash@5.1.0: {} slice-ansi@4.0.0: dependencies: @@ -7885,33 +7925,33 @@ snapshots: style-search@0.1.0: {} - stylelint-config-recommended@17.0.0(stylelint@16.26.1(typescript@5.9.3)): + stylelint-config-recommended@18.0.0(stylelint@17.0.0(typescript@5.9.3)): dependencies: - stylelint: 16.26.1(typescript@5.9.3) + stylelint: 17.0.0(typescript@5.9.3) - stylelint-declaration-block-no-ignored-properties@2.8.0(stylelint@16.26.1(typescript@5.9.3)): + stylelint-declaration-block-no-ignored-properties@2.8.0(stylelint@17.0.0(typescript@5.9.3)): dependencies: - stylelint: 16.26.1(typescript@5.9.3) + stylelint: 17.0.0(typescript@5.9.3) - stylelint-declaration-strict-value@1.10.11(stylelint@16.26.1(typescript@5.9.3)): + stylelint-declaration-strict-value@1.10.11(stylelint@17.0.0(typescript@5.9.3)): dependencies: - stylelint: 16.26.1(typescript@5.9.3) + stylelint: 17.0.0(typescript@5.9.3) - stylelint-value-no-unknown-custom-properties@6.1.0(stylelint@16.26.1(typescript@5.9.3)): + stylelint-value-no-unknown-custom-properties@6.1.0(stylelint@17.0.0(typescript@5.9.3)): dependencies: postcss-value-parser: 4.2.0 resolve: 1.22.11 - stylelint: 16.26.1(typescript@5.9.3) + stylelint: 17.0.0(typescript@5.9.3) - stylelint@16.26.1(typescript@5.9.3): + stylelint@17.0.0(typescript@5.9.3): dependencies: - '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) '@csstools/css-syntax-patches-for-csstree': 1.0.25 - '@csstools/css-tokenizer': 3.0.4 - '@csstools/media-query-list-parser': 4.0.3(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) - '@csstools/selector-specificity': 5.0.0(postcss-selector-parser@7.1.1) - '@dual-bundle/import-meta-resolve': 4.2.1 - balanced-match: 2.0.0 + '@csstools/css-tokenizer': 4.0.0 + '@csstools/media-query-list-parser': 5.0.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/selector-resolve-nested': 4.0.0(postcss-selector-parser@7.1.1) + '@csstools/selector-specificity': 6.0.0(postcss-selector-parser@7.1.1) + balanced-match: 3.0.1 colord: 2.9.3 cosmiconfig: 9.0.0(typescript@5.9.3) css-functions-list: 3.2.3 @@ -7921,29 +7961,28 @@ snapshots: fastest-levenshtein: 1.0.16 file-entry-cache: 11.1.1 global-modules: 2.0.0 - globby: 11.1.0 + globby: 16.1.0 globjoin: 0.1.4 - html-tags: 3.3.1 + html-tags: 5.1.0 ignore: 7.0.5 + import-meta-resolve: 4.2.0 imurmurhash: 0.1.4 is-plain-object: 5.0.0 known-css-properties: 0.37.0 - mathml-tag-names: 2.1.3 - meow: 13.2.0 + mathml-tag-names: 4.0.0 + meow: 14.0.0 micromatch: 4.0.8 normalize-path: 3.0.0 picocolors: 1.1.1 postcss: 8.5.6 - postcss-resolve-nested-selector: 0.1.6 postcss-safe-parser: 7.0.1(postcss@8.5.6) postcss-selector-parser: 7.1.1 postcss-value-parser: 4.2.0 - resolve-from: 5.0.0 - string-width: 4.2.3 - supports-hyperlinks: 3.2.0 + string-width: 8.1.0 + supports-hyperlinks: 4.4.0 svg-tags: 1.0.0 table: 6.9.0 - write-file-atomic: 5.0.1 + write-file-atomic: 7.0.0 transitivePeerDependencies: - supports-color - typescript @@ -7973,6 +8012,8 @@ snapshots: superstruct@0.10.13: {} + supports-color@10.2.2: {} + supports-color@7.2.0: dependencies: has-flag: 4.0.0 @@ -7981,10 +8022,10 @@ snapshots: dependencies: has-flag: 4.0.0 - supports-hyperlinks@3.2.0: + supports-hyperlinks@4.4.0: dependencies: - has-flag: 4.0.0 - supports-color: 7.2.0 + has-flag: 5.0.1 + supports-color: 10.2.2 supports-preserve-symlinks-flag@1.0.0: {} @@ -8018,7 +8059,7 @@ snapshots: transitivePeerDependencies: - encoding - synckit@0.11.11: + synckit@0.11.12: dependencies: '@pkgr/core': 0.2.9 @@ -8065,10 +8106,10 @@ snapshots: jest-worker: 27.5.1 schema-utils: 4.3.3 serialize-javascript: 6.0.2 - terser: 5.44.1 + terser: 5.45.0 webpack: 5.104.1(webpack-cli@6.0.1) - terser@5.44.1: + terser@5.45.0: dependencies: '@jridgewell/source-map': 0.3.11 acorn: 8.15.0 @@ -8153,7 +8194,7 @@ snapshots: uc.micro@2.1.0: {} - ufo@1.6.2: {} + ufo@1.6.3: {} uint8-to-base64@0.2.1: {} @@ -8161,6 +8202,8 @@ snapshots: undici-types@7.16.0: {} + unicorn-magic@0.4.0: {} + unrs-resolver@1.11.1: dependencies: napi-postinstall: 0.3.4 @@ -8205,7 +8248,7 @@ snapshots: vite-string-plugin@1.4.9: {} - vite@7.3.1(@types/node@25.0.6)(jiti@2.6.1)(stylus@0.57.0)(terser@5.44.1)(yaml@2.8.2): + vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(stylus@0.57.0)(terser@5.45.0)(yaml@2.8.2): dependencies: esbuild: 0.27.2 fdir: 6.5.0(picomatch@4.0.3) @@ -8214,17 +8257,17 @@ snapshots: rollup: 4.55.1 tinyglobby: 0.2.15 optionalDependencies: - '@types/node': 25.0.6 + '@types/node': 25.0.9 fsevents: 2.3.3 jiti: 2.6.1 stylus: 0.57.0 - terser: 5.44.1 + terser: 5.45.0 yaml: 2.8.2 - vitest@4.0.17(@types/node@25.0.6)(happy-dom@20.1.0)(jiti@2.6.1)(stylus@0.57.0)(terser@5.44.1)(yaml@2.8.2): + vitest@4.0.17(@types/node@25.0.9)(happy-dom@20.3.0)(jiti@2.6.1)(stylus@0.57.0)(terser@5.45.0)(yaml@2.8.2): dependencies: '@vitest/expect': 4.0.17 - '@vitest/mocker': 4.0.17(vite@7.3.1(@types/node@25.0.6)(jiti@2.6.1)(stylus@0.57.0)(terser@5.44.1)(yaml@2.8.2)) + '@vitest/mocker': 4.0.17(vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(stylus@0.57.0)(terser@5.45.0)(yaml@2.8.2)) '@vitest/pretty-format': 4.0.17 '@vitest/runner': 4.0.17 '@vitest/snapshot': 4.0.17 @@ -8241,11 +8284,11 @@ snapshots: tinyexec: 1.0.2 tinyglobby: 0.2.15 tinyrainbow: 3.0.3 - vite: 7.3.1(@types/node@25.0.6)(jiti@2.6.1)(stylus@0.57.0)(terser@5.44.1)(yaml@2.8.2) + vite: 7.3.1(@types/node@25.0.9)(jiti@2.6.1)(stylus@0.57.0)(terser@5.45.0)(yaml@2.8.2) why-is-node-running: 2.3.0 optionalDependencies: - '@types/node': 25.0.6 - happy-dom: 20.1.0 + '@types/node': 25.0.9 + happy-dom: 20.3.0 transitivePeerDependencies: - jiti - less @@ -8305,7 +8348,7 @@ snapshots: dependencies: chalk: 4.1.2 hash-sum: 2.0.0 - watchpack: 2.5.0 + watchpack: 2.5.1 webpack: 5.104.1(webpack-cli@6.0.1) optionalDependencies: vue: 3.5.26(typescript@5.9.3) @@ -8326,7 +8369,7 @@ snapshots: optionalDependencies: typescript: 5.9.3 - watchpack@2.5.0: + watchpack@2.5.1: dependencies: glob-to-regexp: 0.4.1 graceful-fs: 4.2.11 @@ -8388,7 +8431,7 @@ snapshots: schema-utils: 4.3.3 tapable: 2.3.0 terser-webpack-plugin: 5.3.16(webpack@5.104.1) - watchpack: 2.5.0 + watchpack: 2.5.1 webpack-sources: 3.3.3 optionalDependencies: webpack-cli: 6.0.1(webpack@5.104.1) @@ -8435,7 +8478,7 @@ snapshots: wrappy@1.0.2: {} - write-file-atomic@5.0.1: + write-file-atomic@7.0.0: dependencies: imurmurhash: 0.1.4 signal-exit: 4.1.0 diff --git a/public/assets/img/svg/octicon-logo-github.svg b/public/assets/img/svg/octicon-logo-github.svg index 02d92c9b13..8aae451ae5 100644 --- a/public/assets/img/svg/octicon-logo-github.svg +++ b/public/assets/img/svg/octicon-logo-github.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/public/assets/img/svg/octicon-mark-github.svg b/public/assets/img/svg/octicon-mark-github.svg index 9381053c06..6d6dc40886 100644 --- a/public/assets/img/svg/octicon-mark-github.svg +++ b/public/assets/img/svg/octicon-mark-github.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 3657feb2ce..20a10d1915 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,7 @@ requires-python = ">=3.10" [dependency-groups] dev = [ "djlint==1.36.4", - "yamllint==1.37.1", + "yamllint==1.38.0", ] [tool.djlint] diff --git a/stylelint.config.ts b/stylelint.config.js similarity index 98% rename from stylelint.config.ts rename to stylelint.config.js index 8a5b87e17c..cb3fb5b9c9 100644 --- a/stylelint.config.ts +++ b/stylelint.config.js @@ -1,5 +1,5 @@ +// TODO: Move to .ts after https://github.com/stylelint/stylelint/issues/8893 is fixed import {fileURLToPath} from 'node:url'; -import type {Config} from 'stylelint'; const cssVarFiles = [ fileURLToPath(new URL('web_src/css/base.css', import.meta.url)), @@ -146,4 +146,4 @@ export default { 'shorthand-property-no-redundant-values': true, 'value-no-vendor-prefix': [true, {ignoreValues: ['box', 'inline-box']}], }, -} satisfies Config; +}; diff --git a/types.d.ts b/types.d.ts index 5b01c2c761..ccce6c5554 100644 --- a/types.d.ts +++ b/types.d.ts @@ -17,8 +17,3 @@ declare module 'eslint-plugin-github' { const plugin: Eslint.Plugin; export = plugin; } -declare module '@eslint-community/eslint-plugin-eslint-comments' { - import type {Eslint} from 'eslint'; - const plugin: Eslint.Plugin; - export = plugin; -} diff --git a/uv.lock b/uv.lock index e6a47ec04b..33e9b64b2c 100644 --- a/uv.lock +++ b/uv.lock @@ -4,14 +4,14 @@ requires-python = ">=3.10" [[package]] name = "click" -version = "8.3.0" +version = "8.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/46/61/de6cd827efad202d7057d93e0fed9294b96952e188f7384832791c7b2254/click-8.3.0.tar.gz", hash = "sha256:e7b8232224eba16f4ebe410c25ced9f7875cb5f3263ffc93cc3e8da705e229c4", size = 276943, upload-time = "2025-09-18T17:32:23.696Z" } +sdist = { url = "https://files.pythonhosted.org/packages/3d/fa/656b739db8587d7b5dfa22e22ed02566950fbfbcdc20311993483657a5c0/click-8.3.1.tar.gz", hash = "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a", size = 295065, upload-time = "2025-11-15T20:45:42.706Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/db/d3/9dcc0f5797f070ec8edf30fbadfb200e71d9db6b84d211e3b2085a7589a0/click-8.3.0-py3-none-any.whl", hash = "sha256:9b9f285302c6e3064f4330c05f05b81945b2a39544279343e6e7c5f27a9baddc", size = 107295, upload-time = "2025-09-18T17:32:22.42Z" }, + { url = "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl", hash = "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6", size = 108274, upload-time = "2025-11-15T20:45:41.139Z" }, ] [[package]] @@ -100,7 +100,7 @@ dev = [ [package.metadata.requires-dev] dev = [ { name = "djlint", specifier = "==1.36.4" }, - { name = "yamllint", specifier = "==1.37.1" }, + { name = "yamllint", specifier = "==1.38.0" }, ] [[package]] @@ -118,20 +118,20 @@ wheels = [ [[package]] name = "json5" -version = "0.12.1" +version = "0.13.0" source = { registry = "https://pypi.org/simple" } -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" } +sdist = { url = "https://files.pythonhosted.org/packages/77/e8/a3f261a66e4663f22700bc8a17c08cb83e91fbf086726e7a228398968981/json5-0.13.0.tar.gz", hash = "sha256:b1edf8d487721c0bf64d83c28e91280781f6e21f4a797d3261c7c828d4c165bf", size = 52441, upload-time = "2026-01-01T19:42:14.99Z" } wheels = [ - { 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" }, + { url = "https://files.pythonhosted.org/packages/d7/9e/038522f50ceb7e74f1f991bf1b699f24b0c2bbe7c390dd36ad69f4582258/json5-0.13.0-py3-none-any.whl", hash = "sha256:9a08e1dd65f6a4d4c6fa82d216cf2477349ec2346a38fd70cc11d2557499fbcc", size = 36163, upload-time = "2026-01-01T19:42:13.962Z" }, ] [[package]] name = "pathspec" -version = "0.12.1" +version = "1.0.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ca/bc/f35b8446f4531a7cb215605d100cd88b7ac6f44ab3fc94870c120ab3adbf/pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712", size = 51043, upload-time = "2023-12-10T22:30:45Z" } +sdist = { url = "https://files.pythonhosted.org/packages/4c/b2/bb8e495d5262bfec41ab5cb18f522f1012933347fb5d9e62452d446baca2/pathspec-1.0.3.tar.gz", hash = "sha256:bac5cf97ae2c2876e2d25ebb15078eb04d76e4b98921ee31c6f85ade8b59444d", size = 130841, upload-time = "2026-01-09T15:46:46.009Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", size = 31191, upload-time = "2023-12-10T22:30:43.14Z" }, + { url = "https://files.pythonhosted.org/packages/32/2b/121e912bd60eebd623f873fd090de0e84f322972ab25a7f9044c056804ed/pathspec-1.0.3-py3-none-any.whl", hash = "sha256:e80767021c1cc524aa3fb14bedda9c34406591343cc42797b386ce7b9354fb6c", size = 55021, upload-time = "2026-01-09T15:46:44.652Z" }, ] [[package]] @@ -200,109 +200,123 @@ wheels = [ [[package]] name = "regex" -version = "2025.10.23" +version = "2026.1.15" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f8/c8/1d2160d36b11fbe0a61acb7c3c81ab032d9ec8ad888ac9e0a61b85ab99dd/regex-2025.10.23.tar.gz", hash = "sha256:8cbaf8ceb88f96ae2356d01b9adf5e6306fa42fa6f7eab6b97794e37c959ac26", size = 401266, upload-time = "2025-10-21T15:58:20.23Z" } +sdist = { url = "https://files.pythonhosted.org/packages/0b/86/07d5056945f9ec4590b518171c4254a5925832eb727b56d3c38a7476f316/regex-2026.1.15.tar.gz", hash = "sha256:164759aa25575cbc0651bef59a0b18353e54300d79ace8084c818ad8ac72b7d5", size = 414811, upload-time = "2026-01-14T23:18:02.775Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/88/11/849d5d23633a77047465eaae4cc0cbf24ded7aa496c02e8b9710e28b1687/regex-2025.10.23-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:17bbcde374bef1c5fad9b131f0e28a6a24856dd90368d8c0201e2b5a69533daa", size = 487957, upload-time = "2025-10-21T15:54:26.151Z" }, - { url = "https://files.pythonhosted.org/packages/87/12/5985386e7e3200a0d6a6417026d2c758d783a932428a5efc0a42ca1ddf74/regex-2025.10.23-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b4e10434279cc8567f99ca6e018e9025d14f2fded2a603380b6be2090f476426", size = 290419, upload-time = "2025-10-21T15:54:28.804Z" }, - { url = "https://files.pythonhosted.org/packages/67/cf/a8615923f962f8fdc41a3a6093a48726955e8b1993f4614b26a41d249f9b/regex-2025.10.23-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9c9bb421cbe7012c744a5a56cf4d6c80829c72edb1a2991677299c988d6339c8", size = 288285, upload-time = "2025-10-21T15:54:30.47Z" }, - { url = "https://files.pythonhosted.org/packages/4e/3d/6a3a1e12c86354cd0b3cbf8c3dd6acbe853609ee3b39d47ecd3ce95caf84/regex-2025.10.23-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:275cd1c2ed8c4a78ebfa489618d7aee762e8b4732da73573c3e38236ec5f65de", size = 781458, upload-time = "2025-10-21T15:54:31.978Z" }, - { url = "https://files.pythonhosted.org/packages/46/47/76a8da004489f2700361754859e373b87a53d043de8c47f4d1583fd39d78/regex-2025.10.23-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7b426ae7952f3dc1e73a86056d520bd4e5f021397484a6835902fc5648bcacce", size = 850605, upload-time = "2025-10-21T15:54:33.753Z" }, - { url = "https://files.pythonhosted.org/packages/67/05/fa886461f97d45a6f4b209699cb994dc6d6212d6e219d29444dac5005775/regex-2025.10.23-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c5cdaf5b6d37c7da1967dbe729d819461aab6a98a072feef65bbcff0a6e60649", size = 898563, upload-time = "2025-10-21T15:54:35.431Z" }, - { url = "https://files.pythonhosted.org/packages/2d/db/3ddd8d01455f23cabad7499f4199de0df92f5e96d39633203ff9d0b592dc/regex-2025.10.23-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3bfeff0b08f296ab28b4332a7e03ca31c437ee78b541ebc874bbf540e5932f8d", size = 791535, upload-time = "2025-10-21T15:54:37.269Z" }, - { url = "https://files.pythonhosted.org/packages/7c/ae/0fa5cbf41ca92b6ec3370222fcb6c68b240d68ab10e803d086c03a19fd9e/regex-2025.10.23-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5f97236a67307b775f30a74ef722b64b38b7ab7ba3bb4a2508518a5de545459c", size = 782461, upload-time = "2025-10-21T15:54:39.187Z" }, - { url = "https://files.pythonhosted.org/packages/d4/23/70af22a016df11af4def27870eb175c2c7235b72d411ecf75a4b4a422cb6/regex-2025.10.23-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:be19e7de499940cd72475fb8e46ab2ecb1cf5906bebdd18a89f9329afb1df82f", size = 774583, upload-time = "2025-10-21T15:54:41.018Z" }, - { url = "https://files.pythonhosted.org/packages/7a/ee/a54a6851f6905f33d3c4ed64e8737b1d85ed01b5724712530ddc0f9abdb1/regex-2025.10.23-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:883df76ee42d9ecb82b37ff8d01caea5895b3f49630a64d21111078bbf8ef64c", size = 845649, upload-time = "2025-10-21T15:54:42.615Z" }, - { url = "https://files.pythonhosted.org/packages/80/7d/c3ec1cae14e01fab00e38c41ed35f47a853359e95e9c023e9a4381bb122c/regex-2025.10.23-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:2e9117d1d35fc2addae6281019ecc70dc21c30014b0004f657558b91c6a8f1a7", size = 836037, upload-time = "2025-10-21T15:54:44.63Z" }, - { url = "https://files.pythonhosted.org/packages/15/ae/45771140dd43c4d67c87b54d3728078ed6a96599d9fc7ba6825086236782/regex-2025.10.23-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:0ff1307f531a5d8cf5c20ea517254551ff0a8dc722193aab66c656c5a900ea68", size = 779705, upload-time = "2025-10-21T15:54:46.08Z" }, - { url = "https://files.pythonhosted.org/packages/b8/95/074e2581760eafce7c816a352b7d3a322536e5b68c346d1a8bacd895545c/regex-2025.10.23-cp310-cp310-win32.whl", hash = "sha256:7888475787cbfee4a7cd32998eeffe9a28129fa44ae0f691b96cb3939183ef41", size = 265663, upload-time = "2025-10-21T15:54:47.854Z" }, - { url = "https://files.pythonhosted.org/packages/f7/c7/a25f56a718847e34d3f1608c72eadeb67653bff1a0411da023dd8f4c647b/regex-2025.10.23-cp310-cp310-win_amd64.whl", hash = "sha256:ec41a905908496ce4906dab20fb103c814558db1d69afc12c2f384549c17936a", size = 277587, upload-time = "2025-10-21T15:54:49.571Z" }, - { url = "https://files.pythonhosted.org/packages/d3/e5/63eb17c6b5deaefd93c2bbb1feae7c0a8d2157da25883a6ca2569cf7a663/regex-2025.10.23-cp310-cp310-win_arm64.whl", hash = "sha256:b2b7f19a764d5e966d5a62bf2c28a8b4093cc864c6734510bdb4aeb840aec5e6", size = 269979, upload-time = "2025-10-21T15:54:51.375Z" }, - { url = "https://files.pythonhosted.org/packages/82/e5/74b7cd5cd76b4171f9793042045bb1726f7856dd56e582fc3e058a7a8a5e/regex-2025.10.23-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6c531155bf9179345e85032052a1e5fe1a696a6abf9cea54b97e8baefff970fd", size = 487960, upload-time = "2025-10-21T15:54:53.253Z" }, - { url = "https://files.pythonhosted.org/packages/b9/08/854fa4b3b20471d1df1c71e831b6a1aa480281e37791e52a2df9641ec5c6/regex-2025.10.23-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:912e9df4e89d383681268d38ad8f5780d7cccd94ba0e9aa09ca7ab7ab4f8e7eb", size = 290425, upload-time = "2025-10-21T15:54:55.21Z" }, - { url = "https://files.pythonhosted.org/packages/ab/d3/6272b1dd3ca1271661e168762b234ad3e00dbdf4ef0c7b9b72d2d159efa7/regex-2025.10.23-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4f375c61bfc3138b13e762fe0ae76e3bdca92497816936534a0177201666f44f", size = 288278, upload-time = "2025-10-21T15:54:56.862Z" }, - { url = "https://files.pythonhosted.org/packages/14/8f/c7b365dd9d9bc0a36e018cb96f2ffb60d2ba8deb589a712b437f67de2920/regex-2025.10.23-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e248cc9446081119128ed002a3801f8031e0c219b5d3c64d3cc627da29ac0a33", size = 793289, upload-time = "2025-10-21T15:54:58.352Z" }, - { url = "https://files.pythonhosted.org/packages/d4/fb/b8fbe9aa16cf0c21f45ec5a6c74b4cecbf1a1c0deb7089d4a6f83a9c1caa/regex-2025.10.23-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b52bf9282fdf401e4f4e721f0f61fc4b159b1307244517789702407dd74e38ca", size = 860321, upload-time = "2025-10-21T15:54:59.813Z" }, - { url = "https://files.pythonhosted.org/packages/b0/81/bf41405c772324926a9bd8a640dedaa42da0e929241834dfce0733070437/regex-2025.10.23-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5c084889ab2c59765a0d5ac602fd1c3c244f9b3fcc9a65fdc7ba6b74c5287490", size = 907011, upload-time = "2025-10-21T15:55:01.968Z" }, - { url = "https://files.pythonhosted.org/packages/a4/fb/5ad6a8b92d3f88f3797b51bb4ef47499acc2d0b53d2fbe4487a892f37a73/regex-2025.10.23-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d80e8eb79009bdb0936658c44ca06e2fbbca67792013e3818eea3f5f228971c2", size = 800312, upload-time = "2025-10-21T15:55:04.15Z" }, - { url = "https://files.pythonhosted.org/packages/42/48/b4efba0168a2b57f944205d823f8e8a3a1ae6211a34508f014ec2c712f4f/regex-2025.10.23-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b6f259118ba87b814a8ec475380aee5f5ae97a75852a3507cf31d055b01b5b40", size = 782839, upload-time = "2025-10-21T15:55:05.641Z" }, - { url = "https://files.pythonhosted.org/packages/13/2a/c9efb4c6c535b0559c1fa8e431e0574d229707c9ca718600366fcfef6801/regex-2025.10.23-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:9b8c72a242683dcc72d37595c4f1278dfd7642b769e46700a8df11eab19dfd82", size = 854270, upload-time = "2025-10-21T15:55:07.27Z" }, - { url = "https://files.pythonhosted.org/packages/34/2d/68eecc1bdaee020e8ba549502291c9450d90d8590d0552247c9b543ebf7b/regex-2025.10.23-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:a8d7b7a0a3df9952f9965342159e0c1f05384c0f056a47ce8b61034f8cecbe83", size = 845771, upload-time = "2025-10-21T15:55:09.477Z" }, - { url = "https://files.pythonhosted.org/packages/a5/cd/a1ae499cf9b87afb47a67316bbf1037a7c681ffe447c510ed98c0aa2c01c/regex-2025.10.23-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:413bfea20a484c524858125e92b9ce6ffdd0a4b97d4ff96b5859aa119b0f1bdd", size = 788778, upload-time = "2025-10-21T15:55:11.396Z" }, - { url = "https://files.pythonhosted.org/packages/38/f9/70765e63f5ea7d43b2b6cd4ee9d3323f16267e530fb2a420d92d991cf0fc/regex-2025.10.23-cp311-cp311-win32.whl", hash = "sha256:f76deef1f1019a17dad98f408b8f7afc4bd007cbe835ae77b737e8c7f19ae575", size = 265666, upload-time = "2025-10-21T15:55:13.306Z" }, - { url = "https://files.pythonhosted.org/packages/9c/1a/18e9476ee1b63aaec3844d8e1cb21842dc19272c7e86d879bfc0dcc60db3/regex-2025.10.23-cp311-cp311-win_amd64.whl", hash = "sha256:59bba9f7125536f23fdab5deeea08da0c287a64c1d3acc1c7e99515809824de8", size = 277600, upload-time = "2025-10-21T15:55:15.087Z" }, - { url = "https://files.pythonhosted.org/packages/1d/1b/c019167b1f7a8ec77251457e3ff0339ed74ca8bce1ea13138dc98309c923/regex-2025.10.23-cp311-cp311-win_arm64.whl", hash = "sha256:b103a752b6f1632ca420225718d6ed83f6a6ced3016dd0a4ab9a6825312de566", size = 269974, upload-time = "2025-10-21T15:55:16.841Z" }, - { url = "https://files.pythonhosted.org/packages/f6/57/eeb274d83ab189d02d778851b1ac478477522a92b52edfa6e2ae9ff84679/regex-2025.10.23-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:7a44d9c00f7a0a02d3b777429281376370f3d13d2c75ae74eb94e11ebcf4a7fc", size = 489187, upload-time = "2025-10-21T15:55:18.322Z" }, - { url = "https://files.pythonhosted.org/packages/55/5c/7dad43a9b6ea88bf77e0b8b7729a4c36978e1043165034212fd2702880c6/regex-2025.10.23-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b83601f84fde939ae3478bb32a3aef36f61b58c3208d825c7e8ce1a735f143f2", size = 291122, upload-time = "2025-10-21T15:55:20.2Z" }, - { url = "https://files.pythonhosted.org/packages/66/21/38b71e6f2818f0f4b281c8fba8d9d57cfca7b032a648fa59696e0a54376a/regex-2025.10.23-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ec13647907bb9d15fd192bbfe89ff06612e098a5709e7d6ecabbdd8f7908fc45", size = 288797, upload-time = "2025-10-21T15:55:21.932Z" }, - { url = "https://files.pythonhosted.org/packages/be/95/888f069c89e7729732a6d7cca37f76b44bfb53a1e35dda8a2c7b65c1b992/regex-2025.10.23-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:78d76dd2957d62501084e7012ddafc5fcd406dd982b7a9ca1ea76e8eaaf73e7e", size = 798442, upload-time = "2025-10-21T15:55:23.747Z" }, - { url = "https://files.pythonhosted.org/packages/76/70/4f903c608faf786627a8ee17c06e0067b5acade473678b69c8094b248705/regex-2025.10.23-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8668e5f067e31a47699ebb354f43aeb9c0ef136f915bd864243098524482ac43", size = 864039, upload-time = "2025-10-21T15:55:25.656Z" }, - { url = "https://files.pythonhosted.org/packages/62/19/2df67b526bf25756c7f447dde554fc10a220fd839cc642f50857d01e4a7b/regex-2025.10.23-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a32433fe3deb4b2d8eda88790d2808fed0dc097e84f5e683b4cd4f42edef6cca", size = 912057, upload-time = "2025-10-21T15:55:27.309Z" }, - { url = "https://files.pythonhosted.org/packages/99/14/9a39b7c9e007968411bc3c843cc14cf15437510c0a9991f080cab654fd16/regex-2025.10.23-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d97d73818c642c938db14c0668167f8d39520ca9d983604575ade3fda193afcc", size = 803374, upload-time = "2025-10-21T15:55:28.9Z" }, - { url = "https://files.pythonhosted.org/packages/d4/f7/3495151dd3ca79949599b6d069b72a61a2c5e24fc441dccc79dcaf708fe6/regex-2025.10.23-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:bca7feecc72ee33579e9f6ddf8babbe473045717a0e7dbc347099530f96e8b9a", size = 787714, upload-time = "2025-10-21T15:55:30.628Z" }, - { url = "https://files.pythonhosted.org/packages/28/65/ee882455e051131869957ee8597faea45188c9a98c0dad724cfb302d4580/regex-2025.10.23-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:7e24af51e907d7457cc4a72691ec458320b9ae67dc492f63209f01eecb09de32", size = 858392, upload-time = "2025-10-21T15:55:32.322Z" }, - { url = "https://files.pythonhosted.org/packages/53/25/9287fef5be97529ebd3ac79d256159cb709a07eb58d4be780d1ca3885da8/regex-2025.10.23-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:d10bcde58bbdf18146f3a69ec46dd03233b94a4a5632af97aa5378da3a47d288", size = 850484, upload-time = "2025-10-21T15:55:34.037Z" }, - { url = "https://files.pythonhosted.org/packages/f3/b4/b49b88b4fea2f14dc73e5b5842755e782fc2e52f74423d6f4adc130d5880/regex-2025.10.23-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:44383bc0c933388516c2692c9a7503e1f4a67e982f20b9a29d2fb70c6494f147", size = 789634, upload-time = "2025-10-21T15:55:35.958Z" }, - { url = "https://files.pythonhosted.org/packages/b6/3c/2f8d199d0e84e78bcd6bdc2be9b62410624f6b796e2893d1837ae738b160/regex-2025.10.23-cp312-cp312-win32.whl", hash = "sha256:6040a86f95438a0114bba16e51dfe27f1bc004fd29fe725f54a586f6d522b079", size = 266060, upload-time = "2025-10-21T15:55:37.902Z" }, - { url = "https://files.pythonhosted.org/packages/d7/67/c35e80969f6ded306ad70b0698863310bdf36aca57ad792f45ddc0e2271f/regex-2025.10.23-cp312-cp312-win_amd64.whl", hash = "sha256:436b4c4352fe0762e3bfa34a5567079baa2ef22aa9c37cf4d128979ccfcad842", size = 276931, upload-time = "2025-10-21T15:55:39.502Z" }, - { url = "https://files.pythonhosted.org/packages/f5/a1/4ed147de7d2b60174f758412c87fa51ada15cd3296a0ff047f4280aaa7ca/regex-2025.10.23-cp312-cp312-win_arm64.whl", hash = "sha256:f4b1b1991617055b46aff6f6db24888c1f05f4db9801349d23f09ed0714a9335", size = 270103, upload-time = "2025-10-21T15:55:41.24Z" }, - { url = "https://files.pythonhosted.org/packages/28/c6/195a6217a43719d5a6a12cc192a22d12c40290cecfa577f00f4fb822f07d/regex-2025.10.23-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:b7690f95404a1293923a296981fd943cca12c31a41af9c21ba3edd06398fc193", size = 488956, upload-time = "2025-10-21T15:55:42.887Z" }, - { url = "https://files.pythonhosted.org/packages/4c/93/181070cd1aa2fa541ff2d3afcf763ceecd4937b34c615fa92765020a6c90/regex-2025.10.23-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1a32d77aeaea58a13230100dd8797ac1a84c457f3af2fdf0d81ea689d5a9105b", size = 290997, upload-time = "2025-10-21T15:55:44.53Z" }, - { url = "https://files.pythonhosted.org/packages/b6/c5/9d37fbe3a40ed8dda78c23e1263002497540c0d1522ed75482ef6c2000f0/regex-2025.10.23-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b24b29402f264f70a3c81f45974323b41764ff7159655360543b7cabb73e7d2f", size = 288686, upload-time = "2025-10-21T15:55:46.186Z" }, - { url = "https://files.pythonhosted.org/packages/5f/e7/db610ff9f10c2921f9b6ac0c8d8be4681b28ddd40fc0549429366967e61f/regex-2025.10.23-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:563824a08c7c03d96856d84b46fdb3bbb7cfbdf79da7ef68725cda2ce169c72a", size = 798466, upload-time = "2025-10-21T15:55:48.24Z" }, - { url = "https://files.pythonhosted.org/packages/90/10/aab883e1fa7fe2feb15ac663026e70ca0ae1411efa0c7a4a0342d9545015/regex-2025.10.23-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a0ec8bdd88d2e2659c3518087ee34b37e20bd169419ffead4240a7004e8ed03b", size = 863996, upload-time = "2025-10-21T15:55:50.478Z" }, - { url = "https://files.pythonhosted.org/packages/a2/b0/8f686dd97a51f3b37d0238cd00a6d0f9ccabe701f05b56de1918571d0d61/regex-2025.10.23-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b577601bfe1d33913fcd9276d7607bbac827c4798d9e14d04bf37d417a6c41cb", size = 912145, upload-time = "2025-10-21T15:55:52.215Z" }, - { url = "https://files.pythonhosted.org/packages/a3/ca/639f8cd5b08797bca38fc5e7e07f76641a428cf8c7fca05894caf045aa32/regex-2025.10.23-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7c9f2c68ac6cb3de94eea08a437a75eaa2bd33f9e97c84836ca0b610a5804368", size = 803370, upload-time = "2025-10-21T15:55:53.944Z" }, - { url = "https://files.pythonhosted.org/packages/0d/1e/a40725bb76959eddf8abc42a967bed6f4851b39f5ac4f20e9794d7832aa5/regex-2025.10.23-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:89f8b9ea3830c79468e26b0e21c3585f69f105157c2154a36f6b7839f8afb351", size = 787767, upload-time = "2025-10-21T15:55:56.004Z" }, - { url = "https://files.pythonhosted.org/packages/3d/d8/8ee9858062936b0f99656dce390aa667c6e7fb0c357b1b9bf76fb5e2e708/regex-2025.10.23-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:98fd84c4e4ea185b3bb5bf065261ab45867d8875032f358a435647285c722673", size = 858335, upload-time = "2025-10-21T15:55:58.185Z" }, - { url = "https://files.pythonhosted.org/packages/d8/0a/ed5faaa63fa8e3064ab670e08061fbf09e3a10235b19630cf0cbb9e48c0a/regex-2025.10.23-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:1e11d3e5887b8b096f96b4154dfb902f29c723a9556639586cd140e77e28b313", size = 850402, upload-time = "2025-10-21T15:56:00.023Z" }, - { url = "https://files.pythonhosted.org/packages/79/14/d05f617342f4b2b4a23561da500ca2beab062bfcc408d60680e77ecaf04d/regex-2025.10.23-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4f13450328a6634348d47a88367e06b64c9d84980ef6a748f717b13f8ce64e87", size = 789739, upload-time = "2025-10-21T15:56:01.967Z" }, - { url = "https://files.pythonhosted.org/packages/f9/7b/e8ce8eef42a15f2c3461f8b3e6e924bbc86e9605cb534a393aadc8d3aff8/regex-2025.10.23-cp313-cp313-win32.whl", hash = "sha256:37be9296598a30c6a20236248cb8b2c07ffd54d095b75d3a2a2ee5babdc51df1", size = 266054, upload-time = "2025-10-21T15:56:05.291Z" }, - { url = "https://files.pythonhosted.org/packages/71/2d/55184ed6be6473187868d2f2e6a0708195fc58270e62a22cbf26028f2570/regex-2025.10.23-cp313-cp313-win_amd64.whl", hash = "sha256:ea7a3c283ce0f06fe789365841e9174ba05f8db16e2fd6ae00a02df9572c04c0", size = 276917, upload-time = "2025-10-21T15:56:07.303Z" }, - { url = "https://files.pythonhosted.org/packages/9c/d4/927eced0e2bd45c45839e556f987f8c8f8683268dd3c00ad327deb3b0172/regex-2025.10.23-cp313-cp313-win_arm64.whl", hash = "sha256:d9a4953575f300a7bab71afa4cd4ac061c7697c89590a2902b536783eeb49a4f", size = 270105, upload-time = "2025-10-21T15:56:09.857Z" }, - { url = "https://files.pythonhosted.org/packages/3e/b3/95b310605285573341fc062d1d30b19a54f857530e86c805f942c4ff7941/regex-2025.10.23-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:7d6606524fa77b3912c9ef52a42ef63c6cfbfc1077e9dc6296cd5da0da286044", size = 491850, upload-time = "2025-10-21T15:56:11.685Z" }, - { url = "https://files.pythonhosted.org/packages/a4/8f/207c2cec01e34e56db1eff606eef46644a60cf1739ecd474627db90ad90b/regex-2025.10.23-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:c037aadf4d64bdc38af7db3dbd34877a057ce6524eefcb2914d6d41c56f968cc", size = 292537, upload-time = "2025-10-21T15:56:13.963Z" }, - { url = "https://files.pythonhosted.org/packages/98/3b/025240af4ada1dc0b5f10d73f3e5122d04ce7f8908ab8881e5d82b9d61b6/regex-2025.10.23-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:99018c331fb2529084a0c9b4c713dfa49fafb47c7712422e49467c13a636c656", size = 290904, upload-time = "2025-10-21T15:56:16.016Z" }, - { url = "https://files.pythonhosted.org/packages/81/8e/104ac14e2d3450c43db18ec03e1b96b445a94ae510b60138f00ce2cb7ca1/regex-2025.10.23-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fd8aba965604d70306eb90a35528f776e59112a7114a5162824d43b76fa27f58", size = 807311, upload-time = "2025-10-21T15:56:17.818Z" }, - { url = "https://files.pythonhosted.org/packages/19/63/78aef90141b7ce0be8a18e1782f764f6997ad09de0e05251f0d2503a914a/regex-2025.10.23-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:238e67264b4013e74136c49f883734f68656adf8257bfa13b515626b31b20f8e", size = 873241, upload-time = "2025-10-21T15:56:19.941Z" }, - { url = "https://files.pythonhosted.org/packages/b3/a8/80eb1201bb49ae4dba68a1b284b4211ed9daa8e74dc600018a10a90399fb/regex-2025.10.23-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b2eb48bd9848d66fd04826382f5e8491ae633de3233a3d64d58ceb4ecfa2113a", size = 914794, upload-time = "2025-10-21T15:56:22.488Z" }, - { url = "https://files.pythonhosted.org/packages/f0/d5/1984b6ee93281f360a119a5ca1af6a8ca7d8417861671388bf750becc29b/regex-2025.10.23-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d36591ce06d047d0c0fe2fc5f14bfbd5b4525d08a7b6a279379085e13f0e3d0e", size = 812581, upload-time = "2025-10-21T15:56:24.319Z" }, - { url = "https://files.pythonhosted.org/packages/c4/39/11ebdc6d9927172a64ae237d16763145db6bd45ebb4055c17b88edab72a7/regex-2025.10.23-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:b5d4ece8628d6e364302006366cea3ee887db397faebacc5dacf8ef19e064cf8", size = 795346, upload-time = "2025-10-21T15:56:26.232Z" }, - { url = "https://files.pythonhosted.org/packages/3b/b4/89a591bcc08b5e436af43315284bd233ba77daf0cf20e098d7af12f006c1/regex-2025.10.23-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:39a7e8083959cb1c4ff74e483eecb5a65d3b3e1d821b256e54baf61782c906c6", size = 868214, upload-time = "2025-10-21T15:56:28.597Z" }, - { url = "https://files.pythonhosted.org/packages/3d/ff/58ba98409c1dbc8316cdb20dafbc63ed267380a07780cafecaf5012dabc9/regex-2025.10.23-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:842d449a8fefe546f311656cf8c0d6729b08c09a185f1cad94c756210286d6a8", size = 854540, upload-time = "2025-10-21T15:56:30.875Z" }, - { url = "https://files.pythonhosted.org/packages/9a/f2/4a9e9338d67626e2071b643f828a482712ad15889d7268e11e9a63d6f7e9/regex-2025.10.23-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:d614986dc68506be8f00474f4f6960e03e4ca9883f7df47744800e7d7c08a494", size = 799346, upload-time = "2025-10-21T15:56:32.725Z" }, - { url = "https://files.pythonhosted.org/packages/63/be/543d35c46bebf6f7bf2be538cca74d6585f25714700c36f37f01b92df551/regex-2025.10.23-cp313-cp313t-win32.whl", hash = "sha256:a5b7a26b51a9df473ec16a1934d117443a775ceb7b39b78670b2e21893c330c9", size = 268657, upload-time = "2025-10-21T15:56:34.577Z" }, - { url = "https://files.pythonhosted.org/packages/14/9f/4dd6b7b612037158bb2c9bcaa710e6fb3c40ad54af441b9c53b3a137a9f1/regex-2025.10.23-cp313-cp313t-win_amd64.whl", hash = "sha256:ce81c5544a5453f61cb6f548ed358cfb111e3b23f3cd42d250a4077a6be2a7b6", size = 280075, upload-time = "2025-10-21T15:56:36.767Z" }, - { url = "https://files.pythonhosted.org/packages/81/7a/5bd0672aa65d38c8da6747c17c8b441bdb53d816c569e3261013af8e83cf/regex-2025.10.23-cp313-cp313t-win_arm64.whl", hash = "sha256:e9bf7f6699f490e4e43c44757aa179dab24d1960999c84ab5c3d5377714ed473", size = 271219, upload-time = "2025-10-21T15:56:39.033Z" }, - { url = "https://files.pythonhosted.org/packages/73/f6/0caf29fec943f201fbc8822879c99d31e59c1d51a983d9843ee5cf398539/regex-2025.10.23-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:5b5cb5b6344c4c4c24b2dc87b0bfee78202b07ef7633385df70da7fcf6f7cec6", size = 488960, upload-time = "2025-10-21T15:56:40.849Z" }, - { url = "https://files.pythonhosted.org/packages/8e/7d/ebb7085b8fa31c24ce0355107cea2b92229d9050552a01c5d291c42aecea/regex-2025.10.23-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:a6ce7973384c37bdf0f371a843f95a6e6f4e1489e10e0cf57330198df72959c5", size = 290932, upload-time = "2025-10-21T15:56:42.875Z" }, - { url = "https://files.pythonhosted.org/packages/27/41/43906867287cbb5ca4cee671c3cc8081e15deef86a8189c3aad9ac9f6b4d/regex-2025.10.23-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:2ee3663f2c334959016b56e3bd0dd187cbc73f948e3a3af14c3caaa0c3035d10", size = 288766, upload-time = "2025-10-21T15:56:44.894Z" }, - { url = "https://files.pythonhosted.org/packages/ab/9e/ea66132776700fc77a39b1056e7a5f1308032fead94507e208dc6716b7cd/regex-2025.10.23-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2003cc82a579107e70d013482acce8ba773293f2db534fb532738395c557ff34", size = 798884, upload-time = "2025-10-21T15:56:47.178Z" }, - { url = "https://files.pythonhosted.org/packages/d5/99/aed1453687ab63819a443930770db972c5c8064421f0d9f5da9ad029f26b/regex-2025.10.23-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:182c452279365a93a9f45874f7f191ec1c51e1f1eb41bf2b16563f1a40c1da3a", size = 864768, upload-time = "2025-10-21T15:56:49.793Z" }, - { url = "https://files.pythonhosted.org/packages/99/5d/732fe747a1304805eb3853ce6337eea16b169f7105a0d0dd9c6a5ffa9948/regex-2025.10.23-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b1249e9ff581c5b658c8f0437f883b01f1edcf424a16388591e7c05e5e9e8b0c", size = 911394, upload-time = "2025-10-21T15:56:52.186Z" }, - { url = "https://files.pythonhosted.org/packages/5e/48/58a1f6623466522352a6efa153b9a3714fc559d9f930e9bc947b4a88a2c3/regex-2025.10.23-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2b841698f93db3ccc36caa1900d2a3be281d9539b822dc012f08fc80b46a3224", size = 803145, upload-time = "2025-10-21T15:56:55.142Z" }, - { url = "https://files.pythonhosted.org/packages/ea/f6/7dea79be2681a5574ab3fc237aa53b2c1dfd6bd2b44d4640b6c76f33f4c1/regex-2025.10.23-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:956d89e0c92d471e8f7eee73f73fdff5ed345886378c45a43175a77538a1ffe4", size = 787831, upload-time = "2025-10-21T15:56:57.203Z" }, - { url = "https://files.pythonhosted.org/packages/3a/ad/07b76950fbbe65f88120ca2d8d845047c401450f607c99ed38862904671d/regex-2025.10.23-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:5c259cb363299a0d90d63b5c0d7568ee98419861618a95ee9d91a41cb9954462", size = 859162, upload-time = "2025-10-21T15:56:59.195Z" }, - { url = "https://files.pythonhosted.org/packages/41/87/374f3b2021b22aa6a4fc0b750d63f9721e53d1631a238f7a1c343c1cd288/regex-2025.10.23-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:185d2b18c062820b3a40d8fefa223a83f10b20a674bf6e8c4a432e8dfd844627", size = 849899, upload-time = "2025-10-21T15:57:01.747Z" }, - { url = "https://files.pythonhosted.org/packages/12/4a/7f7bb17c5a5a9747249807210e348450dab9212a46ae6d23ebce86ba6a2b/regex-2025.10.23-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:281d87fa790049c2b7c1b4253121edd80b392b19b5a3d28dc2a77579cb2a58ec", size = 789372, upload-time = "2025-10-21T15:57:04.018Z" }, - { url = "https://files.pythonhosted.org/packages/c9/dd/9c7728ff544fea09bbc8635e4c9e7c423b11c24f1a7a14e6ac4831466709/regex-2025.10.23-cp314-cp314-win32.whl", hash = "sha256:63b81eef3656072e4ca87c58084c7a9c2b81d41a300b157be635a8a675aacfb8", size = 271451, upload-time = "2025-10-21T15:57:06.266Z" }, - { url = "https://files.pythonhosted.org/packages/48/f8/ef7837ff858eb74079c4804c10b0403c0b740762e6eedba41062225f7117/regex-2025.10.23-cp314-cp314-win_amd64.whl", hash = "sha256:0967c5b86f274800a34a4ed862dfab56928144d03cb18821c5153f8777947796", size = 280173, upload-time = "2025-10-21T15:57:08.206Z" }, - { url = "https://files.pythonhosted.org/packages/8e/d0/d576e1dbd9885bfcd83d0e90762beea48d9373a6f7ed39170f44ed22e336/regex-2025.10.23-cp314-cp314-win_arm64.whl", hash = "sha256:c70dfe58b0a00b36aa04cdb0f798bf3e0adc31747641f69e191109fd8572c9a9", size = 273206, upload-time = "2025-10-21T15:57:10.367Z" }, - { url = "https://files.pythonhosted.org/packages/a6/d0/2025268315e8b2b7b660039824cb7765a41623e97d4cd421510925400487/regex-2025.10.23-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:1f5799ea1787aa6de6c150377d11afad39a38afd033f0c5247aecb997978c422", size = 491854, upload-time = "2025-10-21T15:57:12.526Z" }, - { url = "https://files.pythonhosted.org/packages/44/35/5681c2fec5e8b33454390af209c4353dfc44606bf06d714b0b8bd0454ffe/regex-2025.10.23-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:a9639ab7540cfea45ef57d16dcbea2e22de351998d614c3ad2f9778fa3bdd788", size = 292542, upload-time = "2025-10-21T15:57:15.158Z" }, - { url = "https://files.pythonhosted.org/packages/5d/17/184eed05543b724132e4a18149e900f5189001fcfe2d64edaae4fbaf36b4/regex-2025.10.23-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:08f52122c352eb44c3421dab78b9b73a8a77a282cc8314ae576fcaa92b780d10", size = 290903, upload-time = "2025-10-21T15:57:17.108Z" }, - { url = "https://files.pythonhosted.org/packages/25/d0/5e3347aa0db0de382dddfa133a7b0ae72f24b4344f3989398980b44a3924/regex-2025.10.23-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ebf1baebef1c4088ad5a5623decec6b52950f0e4d7a0ae4d48f0a99f8c9cb7d7", size = 807546, upload-time = "2025-10-21T15:57:19.179Z" }, - { url = "https://files.pythonhosted.org/packages/d2/bb/40c589bbdce1be0c55e9f8159789d58d47a22014f2f820cf2b517a5cd193/regex-2025.10.23-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:16b0f1c2e2d566c562d5c384c2b492646be0a19798532fdc1fdedacc66e3223f", size = 873322, upload-time = "2025-10-21T15:57:21.36Z" }, - { url = "https://files.pythonhosted.org/packages/fe/56/a7e40c01575ac93360e606278d359f91829781a9f7fb6e5aa435039edbda/regex-2025.10.23-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f7ada5d9dceafaab92646aa00c10a9efd9b09942dd9b0d7c5a4b73db92cc7e61", size = 914855, upload-time = "2025-10-21T15:57:24.044Z" }, - { url = "https://files.pythonhosted.org/packages/5c/4b/d55587b192763db3163c3f508b3b67b31bb6f5e7a0e08b83013d0a59500a/regex-2025.10.23-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3a36b4005770044bf08edecc798f0e41a75795b9e7c9c12fe29da8d792ef870c", size = 812724, upload-time = "2025-10-21T15:57:26.123Z" }, - { url = "https://files.pythonhosted.org/packages/33/20/18bac334955fbe99d17229f4f8e98d05e4a501ac03a442be8facbb37c304/regex-2025.10.23-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:af7b2661dcc032da1fae82069b5ebf2ac1dfcd5359ef8b35e1367bfc92181432", size = 795439, upload-time = "2025-10-21T15:57:28.497Z" }, - { url = "https://files.pythonhosted.org/packages/67/46/c57266be9df8549c7d85deb4cb82280cb0019e46fff677534c5fa1badfa4/regex-2025.10.23-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:1cb976810ac1416a67562c2e5ba0accf6f928932320fef302e08100ed681b38e", size = 868336, upload-time = "2025-10-21T15:57:30.867Z" }, - { url = "https://files.pythonhosted.org/packages/b8/f3/bd5879e41ef8187fec5e678e94b526a93f99e7bbe0437b0f2b47f9101694/regex-2025.10.23-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:1a56a54be3897d62f54290190fbcd754bff6932934529fbf5b29933da28fcd43", size = 854567, upload-time = "2025-10-21T15:57:33.062Z" }, - { url = "https://files.pythonhosted.org/packages/e6/57/2b6bbdbd2f24dfed5b028033aa17ad8f7d86bb28f1a892cac8b3bc89d059/regex-2025.10.23-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:8f3e6d202fb52c2153f532043bbcf618fd177df47b0b306741eb9b60ba96edc3", size = 799565, upload-time = "2025-10-21T15:57:35.153Z" }, - { url = "https://files.pythonhosted.org/packages/c7/ba/a6168f542ba73b151ed81237adf6b869c7b2f7f8d51618111296674e20ee/regex-2025.10.23-cp314-cp314t-win32.whl", hash = "sha256:1fa1186966b2621b1769fd467c7b22e317e6ba2d2cdcecc42ea3089ef04a8521", size = 274428, upload-time = "2025-10-21T15:57:37.996Z" }, - { url = "https://files.pythonhosted.org/packages/ef/a0/c84475e14a2829e9b0864ebf77c3f7da909df9d8acfe2bb540ff0072047c/regex-2025.10.23-cp314-cp314t-win_amd64.whl", hash = "sha256:08a15d40ce28362eac3e78e83d75475147869c1ff86bc93285f43b4f4431a741", size = 284140, upload-time = "2025-10-21T15:57:40.027Z" }, - { url = "https://files.pythonhosted.org/packages/51/33/6a08ade0eee5b8ba79386869fa6f77afeb835b60510f3525db987e2fffc4/regex-2025.10.23-cp314-cp314t-win_arm64.whl", hash = "sha256:a93e97338e1c8ea2649e130dcfbe8cd69bba5e1e163834752ab64dcb4de6d5ed", size = 274497, upload-time = "2025-10-21T15:57:42.389Z" }, + { url = "https://files.pythonhosted.org/packages/ea/d2/e6ee96b7dff201a83f650241c52db8e5bd080967cb93211f57aa448dc9d6/regex-2026.1.15-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:4e3dd93c8f9abe8aa4b6c652016da9a3afa190df5ad822907efe6b206c09896e", size = 488166, upload-time = "2026-01-14T23:13:46.408Z" }, + { url = "https://files.pythonhosted.org/packages/23/8a/819e9ce14c9f87af026d0690901b3931f3101160833e5d4c8061fa3a1b67/regex-2026.1.15-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:97499ff7862e868b1977107873dd1a06e151467129159a6ffd07b66706ba3a9f", size = 290632, upload-time = "2026-01-14T23:13:48.688Z" }, + { url = "https://files.pythonhosted.org/packages/d5/c3/23dfe15af25d1d45b07dfd4caa6003ad710dcdcb4c4b279909bdfe7a2de8/regex-2026.1.15-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0bda75ebcac38d884240914c6c43d8ab5fb82e74cde6da94b43b17c411aa4c2b", size = 288500, upload-time = "2026-01-14T23:13:50.503Z" }, + { url = "https://files.pythonhosted.org/packages/c6/31/1adc33e2f717df30d2f4d973f8776d2ba6ecf939301efab29fca57505c95/regex-2026.1.15-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7dcc02368585334f5bc81fc73a2a6a0bbade60e7d83da21cead622faf408f32c", size = 781670, upload-time = "2026-01-14T23:13:52.453Z" }, + { url = "https://files.pythonhosted.org/packages/23/ce/21a8a22d13bc4adcb927c27b840c948f15fc973e21ed2346c1bd0eae22dc/regex-2026.1.15-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:693b465171707bbe882a7a05de5e866f33c76aa449750bee94a8d90463533cc9", size = 850820, upload-time = "2026-01-14T23:13:54.894Z" }, + { url = "https://files.pythonhosted.org/packages/6c/4f/3eeacdf587a4705a44484cd0b30e9230a0e602811fb3e2cc32268c70d509/regex-2026.1.15-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b0d190e6f013ea938623a58706d1469a62103fb2a241ce2873a9906e0386582c", size = 898777, upload-time = "2026-01-14T23:13:56.908Z" }, + { url = "https://files.pythonhosted.org/packages/79/a9/1898a077e2965c35fc22796488141a22676eed2d73701e37c73ad7c0b459/regex-2026.1.15-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5ff818702440a5878a81886f127b80127f5d50563753a28211482867f8318106", size = 791750, upload-time = "2026-01-14T23:13:58.527Z" }, + { url = "https://files.pythonhosted.org/packages/4c/84/e31f9d149a178889b3817212827f5e0e8c827a049ff31b4b381e76b26e2d/regex-2026.1.15-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f052d1be37ef35a54e394de66136e30fa1191fab64f71fc06ac7bc98c9a84618", size = 782674, upload-time = "2026-01-14T23:13:59.874Z" }, + { url = "https://files.pythonhosted.org/packages/d2/ff/adf60063db24532add6a1676943754a5654dcac8237af024ede38244fd12/regex-2026.1.15-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6bfc31a37fd1592f0c4fc4bfc674b5c42e52efe45b4b7a6a14f334cca4bcebe4", size = 767906, upload-time = "2026-01-14T23:14:01.298Z" }, + { url = "https://files.pythonhosted.org/packages/af/3e/e6a216cee1e2780fec11afe7fc47b6f3925d7264e8149c607ac389fd9b1a/regex-2026.1.15-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3d6ce5ae80066b319ae3bc62fd55a557c9491baa5efd0d355f0de08c4ba54e79", size = 774798, upload-time = "2026-01-14T23:14:02.715Z" }, + { url = "https://files.pythonhosted.org/packages/0f/98/23a4a8378a9208514ed3efc7e7850c27fa01e00ed8557c958df0335edc4a/regex-2026.1.15-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:1704d204bd42b6bb80167df0e4554f35c255b579ba99616def38f69e14a5ccb9", size = 845861, upload-time = "2026-01-14T23:14:04.824Z" }, + { url = "https://files.pythonhosted.org/packages/f8/57/d7605a9d53bd07421a8785d349cd29677fe660e13674fa4c6cbd624ae354/regex-2026.1.15-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:e3174a5ed4171570dc8318afada56373aa9289eb6dc0d96cceb48e7358b0e220", size = 755648, upload-time = "2026-01-14T23:14:06.371Z" }, + { url = "https://files.pythonhosted.org/packages/6f/76/6f2e24aa192da1e299cc1101674a60579d3912391867ce0b946ba83e2194/regex-2026.1.15-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:87adf5bd6d72e3e17c9cb59ac4096b1faaf84b7eb3037a5ffa61c4b4370f0f13", size = 836250, upload-time = "2026-01-14T23:14:08.343Z" }, + { url = "https://files.pythonhosted.org/packages/11/3a/1f2a1d29453299a7858eab7759045fc3d9d1b429b088dec2dc85b6fa16a2/regex-2026.1.15-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e85dc94595f4d766bd7d872a9de5ede1ca8d3063f3bdf1e2c725f5eb411159e3", size = 779919, upload-time = "2026-01-14T23:14:09.954Z" }, + { url = "https://files.pythonhosted.org/packages/c0/67/eab9bc955c9dcc58e9b222c801e39cff7ca0b04261792a2149166ce7e792/regex-2026.1.15-cp310-cp310-win32.whl", hash = "sha256:21ca32c28c30d5d65fc9886ff576fc9b59bbca08933e844fa2363e530f4c8218", size = 265888, upload-time = "2026-01-14T23:14:11.35Z" }, + { url = "https://files.pythonhosted.org/packages/1d/62/31d16ae24e1f8803bddb0885508acecaec997fcdcde9c243787103119ae4/regex-2026.1.15-cp310-cp310-win_amd64.whl", hash = "sha256:3038a62fc7d6e5547b8915a3d927a0fbeef84cdbe0b1deb8c99bbd4a8961b52a", size = 277830, upload-time = "2026-01-14T23:14:12.908Z" }, + { url = "https://files.pythonhosted.org/packages/e5/36/5d9972bccd6417ecd5a8be319cebfd80b296875e7f116c37fb2a2deecebf/regex-2026.1.15-cp310-cp310-win_arm64.whl", hash = "sha256:505831646c945e3e63552cc1b1b9b514f0e93232972a2d5bedbcc32f15bc82e3", size = 270376, upload-time = "2026-01-14T23:14:14.782Z" }, + { url = "https://files.pythonhosted.org/packages/d0/c9/0c80c96eab96948363d270143138d671d5731c3a692b417629bf3492a9d6/regex-2026.1.15-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:1ae6020fb311f68d753b7efa9d4b9a5d47a5d6466ea0d5e3b5a471a960ea6e4a", size = 488168, upload-time = "2026-01-14T23:14:16.129Z" }, + { url = "https://files.pythonhosted.org/packages/17/f0/271c92f5389a552494c429e5cc38d76d1322eb142fb5db3c8ccc47751468/regex-2026.1.15-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:eddf73f41225942c1f994914742afa53dc0d01a6e20fe14b878a1b1edc74151f", size = 290636, upload-time = "2026-01-14T23:14:17.715Z" }, + { url = "https://files.pythonhosted.org/packages/a0/f9/5f1fd077d106ca5655a0f9ff8f25a1ab55b92128b5713a91ed7134ff688e/regex-2026.1.15-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e8cd52557603f5c66a548f69421310886b28b7066853089e1a71ee710e1cdc1", size = 288496, upload-time = "2026-01-14T23:14:19.326Z" }, + { url = "https://files.pythonhosted.org/packages/b5/e1/8f43b03a4968c748858ec77f746c286d81f896c2e437ccf050ebc5d3128c/regex-2026.1.15-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5170907244b14303edc5978f522f16c974f32d3aa92109fabc2af52411c9433b", size = 793503, upload-time = "2026-01-14T23:14:20.922Z" }, + { url = "https://files.pythonhosted.org/packages/8d/4e/a39a5e8edc5377a46a7c875c2f9a626ed3338cb3bb06931be461c3e1a34a/regex-2026.1.15-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2748c1ec0663580b4510bd89941a31560b4b439a0b428b49472a3d9944d11cd8", size = 860535, upload-time = "2026-01-14T23:14:22.405Z" }, + { url = "https://files.pythonhosted.org/packages/dc/1c/9dce667a32a9477f7a2869c1c767dc00727284a9fa3ff5c09a5c6c03575e/regex-2026.1.15-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2f2775843ca49360508d080eaa87f94fa248e2c946bbcd963bb3aae14f333413", size = 907225, upload-time = "2026-01-14T23:14:23.897Z" }, + { url = "https://files.pythonhosted.org/packages/a4/3c/87ca0a02736d16b6262921425e84b48984e77d8e4e572c9072ce96e66c30/regex-2026.1.15-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d9ea2604370efc9a174c1b5dcc81784fb040044232150f7f33756049edfc9026", size = 800526, upload-time = "2026-01-14T23:14:26.039Z" }, + { url = "https://files.pythonhosted.org/packages/4b/ff/647d5715aeea7c87bdcbd2f578f47b415f55c24e361e639fe8c0cc88878f/regex-2026.1.15-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0dcd31594264029b57bf16f37fd7248a70b3b764ed9e0839a8f271b2d22c0785", size = 773446, upload-time = "2026-01-14T23:14:28.109Z" }, + { url = "https://files.pythonhosted.org/packages/af/89/bf22cac25cb4ba0fe6bff52ebedbb65b77a179052a9d6037136ae93f42f4/regex-2026.1.15-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c08c1f3e34338256732bd6938747daa3c0d5b251e04b6e43b5813e94d503076e", size = 783051, upload-time = "2026-01-14T23:14:29.929Z" }, + { url = "https://files.pythonhosted.org/packages/1e/f4/6ed03e71dca6348a5188363a34f5e26ffd5db1404780288ff0d79513bce4/regex-2026.1.15-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e43a55f378df1e7a4fa3547c88d9a5a9b7113f653a66821bcea4718fe6c58763", size = 854485, upload-time = "2026-01-14T23:14:31.366Z" }, + { url = "https://files.pythonhosted.org/packages/d9/9a/8e8560bd78caded8eb137e3e47612430a05b9a772caf60876435192d670a/regex-2026.1.15-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:f82110ab962a541737bd0ce87978d4c658f06e7591ba899192e2712a517badbb", size = 762195, upload-time = "2026-01-14T23:14:32.802Z" }, + { url = "https://files.pythonhosted.org/packages/38/6b/61fc710f9aa8dfcd764fe27d37edfaa023b1a23305a0d84fccd5adb346ea/regex-2026.1.15-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:27618391db7bdaf87ac6c92b31e8f0dfb83a9de0075855152b720140bda177a2", size = 845986, upload-time = "2026-01-14T23:14:34.898Z" }, + { url = "https://files.pythonhosted.org/packages/fd/2e/fbee4cb93f9d686901a7ca8d94285b80405e8c34fe4107f63ffcbfb56379/regex-2026.1.15-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bfb0d6be01fbae8d6655c8ca21b3b72458606c4aec9bbc932db758d47aba6db1", size = 788992, upload-time = "2026-01-14T23:14:37.116Z" }, + { url = "https://files.pythonhosted.org/packages/ed/14/3076348f3f586de64b1ab75a3fbabdaab7684af7f308ad43be7ef1849e55/regex-2026.1.15-cp311-cp311-win32.whl", hash = "sha256:b10e42a6de0e32559a92f2f8dc908478cc0fa02838d7dbe764c44dca3fa13569", size = 265893, upload-time = "2026-01-14T23:14:38.426Z" }, + { url = "https://files.pythonhosted.org/packages/0f/19/772cf8b5fc803f5c89ba85d8b1870a1ca580dc482aa030383a9289c82e44/regex-2026.1.15-cp311-cp311-win_amd64.whl", hash = "sha256:e9bf3f0bbdb56633c07d7116ae60a576f846efdd86a8848f8d62b749e1209ca7", size = 277840, upload-time = "2026-01-14T23:14:39.785Z" }, + { url = "https://files.pythonhosted.org/packages/78/84/d05f61142709474da3c0853222d91086d3e1372bcdab516c6fd8d80f3297/regex-2026.1.15-cp311-cp311-win_arm64.whl", hash = "sha256:41aef6f953283291c4e4e6850607bd71502be67779586a61472beacb315c97ec", size = 270374, upload-time = "2026-01-14T23:14:41.592Z" }, + { url = "https://files.pythonhosted.org/packages/92/81/10d8cf43c807d0326efe874c1b79f22bfb0fb226027b0b19ebc26d301408/regex-2026.1.15-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:4c8fcc5793dde01641a35905d6731ee1548f02b956815f8f1cab89e515a5bdf1", size = 489398, upload-time = "2026-01-14T23:14:43.741Z" }, + { url = "https://files.pythonhosted.org/packages/90/b0/7c2a74e74ef2a7c32de724658a69a862880e3e4155cba992ba04d1c70400/regex-2026.1.15-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:bfd876041a956e6a90ad7cdb3f6a630c07d491280bfeed4544053cd434901681", size = 291339, upload-time = "2026-01-14T23:14:45.183Z" }, + { url = "https://files.pythonhosted.org/packages/19/4d/16d0773d0c818417f4cc20aa0da90064b966d22cd62a8c46765b5bd2d643/regex-2026.1.15-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9250d087bc92b7d4899ccd5539a1b2334e44eee85d848c4c1aef8e221d3f8c8f", size = 289003, upload-time = "2026-01-14T23:14:47.25Z" }, + { url = "https://files.pythonhosted.org/packages/c6/e4/1fc4599450c9f0863d9406e944592d968b8d6dfd0d552a7d569e43bceada/regex-2026.1.15-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c8a154cf6537ebbc110e24dabe53095e714245c272da9c1be05734bdad4a61aa", size = 798656, upload-time = "2026-01-14T23:14:48.77Z" }, + { url = "https://files.pythonhosted.org/packages/b2/e6/59650d73a73fa8a60b3a590545bfcf1172b4384a7df2e7fe7b9aab4e2da9/regex-2026.1.15-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8050ba2e3ea1d8731a549e83c18d2f0999fbc99a5f6bd06b4c91449f55291804", size = 864252, upload-time = "2026-01-14T23:14:50.528Z" }, + { url = "https://files.pythonhosted.org/packages/6e/ab/1d0f4d50a1638849a97d731364c9a80fa304fec46325e48330c170ee8e80/regex-2026.1.15-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0bf065240704cb8951cc04972cf107063917022511273e0969bdb34fc173456c", size = 912268, upload-time = "2026-01-14T23:14:52.952Z" }, + { url = "https://files.pythonhosted.org/packages/dd/df/0d722c030c82faa1d331d1921ee268a4e8fb55ca8b9042c9341c352f17fa/regex-2026.1.15-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c32bef3e7aeee75746748643667668ef941d28b003bfc89994ecf09a10f7a1b5", size = 803589, upload-time = "2026-01-14T23:14:55.182Z" }, + { url = "https://files.pythonhosted.org/packages/66/23/33289beba7ccb8b805c6610a8913d0131f834928afc555b241caabd422a9/regex-2026.1.15-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d5eaa4a4c5b1906bd0d2508d68927f15b81821f85092e06f1a34a4254b0e1af3", size = 775700, upload-time = "2026-01-14T23:14:56.707Z" }, + { url = "https://files.pythonhosted.org/packages/e7/65/bf3a42fa6897a0d3afa81acb25c42f4b71c274f698ceabd75523259f6688/regex-2026.1.15-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:86c1077a3cc60d453d4084d5b9649065f3bf1184e22992bd322e1f081d3117fb", size = 787928, upload-time = "2026-01-14T23:14:58.312Z" }, + { url = "https://files.pythonhosted.org/packages/f4/f5/13bf65864fc314f68cdd6d8ca94adcab064d4d39dbd0b10fef29a9da48fc/regex-2026.1.15-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:2b091aefc05c78d286657cd4db95f2e6313375ff65dcf085e42e4c04d9c8d410", size = 858607, upload-time = "2026-01-14T23:15:00.657Z" }, + { url = "https://files.pythonhosted.org/packages/a3/31/040e589834d7a439ee43fb0e1e902bc81bd58a5ba81acffe586bb3321d35/regex-2026.1.15-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:57e7d17f59f9ebfa9667e6e5a1c0127b96b87cb9cede8335482451ed00788ba4", size = 763729, upload-time = "2026-01-14T23:15:02.248Z" }, + { url = "https://files.pythonhosted.org/packages/9b/84/6921e8129687a427edf25a34a5594b588b6d88f491320b9de5b6339a4fcb/regex-2026.1.15-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:c6c4dcdfff2c08509faa15d36ba7e5ef5fcfab25f1e8f85a0c8f45bc3a30725d", size = 850697, upload-time = "2026-01-14T23:15:03.878Z" }, + { url = "https://files.pythonhosted.org/packages/8a/87/3d06143d4b128f4229158f2de5de6c8f2485170c7221e61bf381313314b2/regex-2026.1.15-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:cf8ff04c642716a7f2048713ddc6278c5fd41faa3b9cab12607c7abecd012c22", size = 789849, upload-time = "2026-01-14T23:15:06.102Z" }, + { url = "https://files.pythonhosted.org/packages/77/69/c50a63842b6bd48850ebc7ab22d46e7a2a32d824ad6c605b218441814639/regex-2026.1.15-cp312-cp312-win32.whl", hash = "sha256:82345326b1d8d56afbe41d881fdf62f1926d7264b2fc1537f99ae5da9aad7913", size = 266279, upload-time = "2026-01-14T23:15:07.678Z" }, + { url = "https://files.pythonhosted.org/packages/f2/36/39d0b29d087e2b11fd8191e15e81cce1b635fcc845297c67f11d0d19274d/regex-2026.1.15-cp312-cp312-win_amd64.whl", hash = "sha256:4def140aa6156bc64ee9912383d4038f3fdd18fee03a6f222abd4de6357ce42a", size = 277166, upload-time = "2026-01-14T23:15:09.257Z" }, + { url = "https://files.pythonhosted.org/packages/28/32/5b8e476a12262748851fa8ab1b0be540360692325975b094e594dfebbb52/regex-2026.1.15-cp312-cp312-win_arm64.whl", hash = "sha256:c6c565d9a6e1a8d783c1948937ffc377dd5771e83bd56de8317c450a954d2056", size = 270415, upload-time = "2026-01-14T23:15:10.743Z" }, + { url = "https://files.pythonhosted.org/packages/f8/2e/6870bb16e982669b674cce3ee9ff2d1d46ab80528ee6bcc20fb2292efb60/regex-2026.1.15-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:e69d0deeb977ffe7ed3d2e4439360089f9c3f217ada608f0f88ebd67afb6385e", size = 489164, upload-time = "2026-01-14T23:15:13.962Z" }, + { url = "https://files.pythonhosted.org/packages/dc/67/9774542e203849b0286badf67199970a44ebdb0cc5fb739f06e47ada72f8/regex-2026.1.15-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:3601ffb5375de85a16f407854d11cca8fe3f5febbe3ac78fb2866bb220c74d10", size = 291218, upload-time = "2026-01-14T23:15:15.647Z" }, + { url = "https://files.pythonhosted.org/packages/b2/87/b0cda79f22b8dee05f774922a214da109f9a4c0eca5da2c9d72d77ea062c/regex-2026.1.15-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4c5ef43b5c2d4114eb8ea424bb8c9cec01d5d17f242af88b2448f5ee81caadbc", size = 288895, upload-time = "2026-01-14T23:15:17.788Z" }, + { url = "https://files.pythonhosted.org/packages/3b/6a/0041f0a2170d32be01ab981d6346c83a8934277d82c780d60b127331f264/regex-2026.1.15-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:968c14d4f03e10b2fd960f1d5168c1f0ac969381d3c1fcc973bc45fb06346599", size = 798680, upload-time = "2026-01-14T23:15:19.342Z" }, + { url = "https://files.pythonhosted.org/packages/58/de/30e1cfcdbe3e891324aa7568b7c968771f82190df5524fabc1138cb2d45a/regex-2026.1.15-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:56a5595d0f892f214609c9f76b41b7428bed439d98dc961efafdd1354d42baae", size = 864210, upload-time = "2026-01-14T23:15:22.005Z" }, + { url = "https://files.pythonhosted.org/packages/64/44/4db2f5c5ca0ccd40ff052ae7b1e9731352fcdad946c2b812285a7505ca75/regex-2026.1.15-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0bf650f26087363434c4e560011f8e4e738f6f3e029b85d4904c50135b86cfa5", size = 912358, upload-time = "2026-01-14T23:15:24.569Z" }, + { url = "https://files.pythonhosted.org/packages/79/b6/e6a5665d43a7c42467138c8a2549be432bad22cbd206f5ec87162de74bd7/regex-2026.1.15-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:18388a62989c72ac24de75f1449d0fb0b04dfccd0a1a7c1c43af5eb503d890f6", size = 803583, upload-time = "2026-01-14T23:15:26.526Z" }, + { url = "https://files.pythonhosted.org/packages/e7/53/7cd478222169d85d74d7437e74750005e993f52f335f7c04ff7adfda3310/regex-2026.1.15-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6d220a2517f5893f55daac983bfa9fe998a7dbcaee4f5d27a88500f8b7873788", size = 775782, upload-time = "2026-01-14T23:15:29.352Z" }, + { url = "https://files.pythonhosted.org/packages/ca/b5/75f9a9ee4b03a7c009fe60500fe550b45df94f0955ca29af16333ef557c5/regex-2026.1.15-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c9c08c2fbc6120e70abff5d7f28ffb4d969e14294fb2143b4b5c7d20e46d1714", size = 787978, upload-time = "2026-01-14T23:15:31.295Z" }, + { url = "https://files.pythonhosted.org/packages/72/b3/79821c826245bbe9ccbb54f6eadb7879c722fd3e0248c17bfc90bf54e123/regex-2026.1.15-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:7ef7d5d4bd49ec7364315167a4134a015f61e8266c6d446fc116a9ac4456e10d", size = 858550, upload-time = "2026-01-14T23:15:33.558Z" }, + { url = "https://files.pythonhosted.org/packages/4a/85/2ab5f77a1c465745bfbfcb3ad63178a58337ae8d5274315e2cc623a822fa/regex-2026.1.15-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:6e42844ad64194fa08d5ccb75fe6a459b9b08e6d7296bd704460168d58a388f3", size = 763747, upload-time = "2026-01-14T23:15:35.206Z" }, + { url = "https://files.pythonhosted.org/packages/6d/84/c27df502d4bfe2873a3e3a7cf1bdb2b9cc10284d1a44797cf38bed790470/regex-2026.1.15-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:cfecdaa4b19f9ca534746eb3b55a5195d5c95b88cac32a205e981ec0a22b7d31", size = 850615, upload-time = "2026-01-14T23:15:37.523Z" }, + { url = "https://files.pythonhosted.org/packages/7d/b7/658a9782fb253680aa8ecb5ccbb51f69e088ed48142c46d9f0c99b46c575/regex-2026.1.15-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:08df9722d9b87834a3d701f3fca570b2be115654dbfd30179f30ab2f39d606d3", size = 789951, upload-time = "2026-01-14T23:15:39.582Z" }, + { url = "https://files.pythonhosted.org/packages/fc/2a/5928af114441e059f15b2f63e188bd00c6529b3051c974ade7444b85fcda/regex-2026.1.15-cp313-cp313-win32.whl", hash = "sha256:d426616dae0967ca225ab12c22274eb816558f2f99ccb4a1d52ca92e8baf180f", size = 266275, upload-time = "2026-01-14T23:15:42.108Z" }, + { url = "https://files.pythonhosted.org/packages/4f/16/5bfbb89e435897bff28cf0352a992ca719d9e55ebf8b629203c96b6ce4f7/regex-2026.1.15-cp313-cp313-win_amd64.whl", hash = "sha256:febd38857b09867d3ed3f4f1af7d241c5c50362e25ef43034995b77a50df494e", size = 277145, upload-time = "2026-01-14T23:15:44.244Z" }, + { url = "https://files.pythonhosted.org/packages/56/c1/a09ff7392ef4233296e821aec5f78c51be5e91ffde0d163059e50fd75835/regex-2026.1.15-cp313-cp313-win_arm64.whl", hash = "sha256:8e32f7896f83774f91499d239e24cebfadbc07639c1494bb7213983842348337", size = 270411, upload-time = "2026-01-14T23:15:45.858Z" }, + { url = "https://files.pythonhosted.org/packages/3c/38/0cfd5a78e5c6db00e6782fdae70458f89850ce95baa5e8694ab91d89744f/regex-2026.1.15-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:ec94c04149b6a7b8120f9f44565722c7ae31b7a6d2275569d2eefa76b83da3be", size = 492068, upload-time = "2026-01-14T23:15:47.616Z" }, + { url = "https://files.pythonhosted.org/packages/50/72/6c86acff16cb7c959c4355826bbf06aad670682d07c8f3998d9ef4fee7cd/regex-2026.1.15-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:40c86d8046915bb9aeb15d3f3f15b6fd500b8ea4485b30e1bbc799dab3fe29f8", size = 292756, upload-time = "2026-01-14T23:15:49.307Z" }, + { url = "https://files.pythonhosted.org/packages/4e/58/df7fb69eadfe76526ddfce28abdc0af09ffe65f20c2c90932e89d705153f/regex-2026.1.15-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:726ea4e727aba21643205edad8f2187ec682d3305d790f73b7a51c7587b64bdd", size = 291114, upload-time = "2026-01-14T23:15:51.484Z" }, + { url = "https://files.pythonhosted.org/packages/ed/6c/a4011cd1cf96b90d2cdc7e156f91efbd26531e822a7fbb82a43c1016678e/regex-2026.1.15-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1cb740d044aff31898804e7bf1181cc72c03d11dfd19932b9911ffc19a79070a", size = 807524, upload-time = "2026-01-14T23:15:53.102Z" }, + { url = "https://files.pythonhosted.org/packages/1d/25/a53ffb73183f69c3e9f4355c4922b76d2840aee160af6af5fac229b6201d/regex-2026.1.15-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:05d75a668e9ea16f832390d22131fe1e8acc8389a694c8febc3e340b0f810b93", size = 873455, upload-time = "2026-01-14T23:15:54.956Z" }, + { url = "https://files.pythonhosted.org/packages/66/0b/8b47fc2e8f97d9b4a851736f3890a5f786443aa8901061c55f24c955f45b/regex-2026.1.15-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d991483606f3dbec93287b9f35596f41aa2e92b7c2ebbb935b63f409e243c9af", size = 915007, upload-time = "2026-01-14T23:15:57.041Z" }, + { url = "https://files.pythonhosted.org/packages/c2/fa/97de0d681e6d26fabe71968dbee06dd52819e9a22fdce5dac7256c31ed84/regex-2026.1.15-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:194312a14819d3e44628a44ed6fea6898fdbecb0550089d84c403475138d0a09", size = 812794, upload-time = "2026-01-14T23:15:58.916Z" }, + { url = "https://files.pythonhosted.org/packages/22/38/e752f94e860d429654aa2b1c51880bff8dfe8f084268258adf9151cf1f53/regex-2026.1.15-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fe2fda4110a3d0bc163c2e0664be44657431440722c5c5315c65155cab92f9e5", size = 781159, upload-time = "2026-01-14T23:16:00.817Z" }, + { url = "https://files.pythonhosted.org/packages/e9/a7/d739ffaef33c378fc888302a018d7f81080393d96c476b058b8c64fd2b0d/regex-2026.1.15-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:124dc36c85d34ef2d9164da41a53c1c8c122cfb1f6e1ec377a1f27ee81deb794", size = 795558, upload-time = "2026-01-14T23:16:03.267Z" }, + { url = "https://files.pythonhosted.org/packages/3e/c4/542876f9a0ac576100fc73e9c75b779f5c31e3527576cfc9cb3009dcc58a/regex-2026.1.15-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:a1774cd1981cd212506a23a14dba7fdeaee259f5deba2df6229966d9911e767a", size = 868427, upload-time = "2026-01-14T23:16:05.646Z" }, + { url = "https://files.pythonhosted.org/packages/fc/0f/d5655bea5b22069e32ae85a947aa564912f23758e112cdb74212848a1a1b/regex-2026.1.15-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:b5f7d8d2867152cdb625e72a530d2ccb48a3d199159144cbdd63870882fb6f80", size = 769939, upload-time = "2026-01-14T23:16:07.542Z" }, + { url = "https://files.pythonhosted.org/packages/20/06/7e18a4fa9d326daeda46d471a44ef94201c46eaa26dbbb780b5d92cbfdda/regex-2026.1.15-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:492534a0ab925d1db998defc3c302dae3616a2fc3fe2e08db1472348f096ddf2", size = 854753, upload-time = "2026-01-14T23:16:10.395Z" }, + { url = "https://files.pythonhosted.org/packages/3b/67/dc8946ef3965e166f558ef3b47f492bc364e96a265eb4a2bb3ca765c8e46/regex-2026.1.15-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c661fc820cfb33e166bf2450d3dadbda47c8d8981898adb9b6fe24e5e582ba60", size = 799559, upload-time = "2026-01-14T23:16:12.347Z" }, + { url = "https://files.pythonhosted.org/packages/a5/61/1bba81ff6d50c86c65d9fd84ce9699dd106438ee4cdb105bf60374ee8412/regex-2026.1.15-cp313-cp313t-win32.whl", hash = "sha256:99ad739c3686085e614bf77a508e26954ff1b8f14da0e3765ff7abbf7799f952", size = 268879, upload-time = "2026-01-14T23:16:14.049Z" }, + { url = "https://files.pythonhosted.org/packages/e9/5e/cef7d4c5fb0ea3ac5c775fd37db5747f7378b29526cc83f572198924ff47/regex-2026.1.15-cp313-cp313t-win_amd64.whl", hash = "sha256:32655d17905e7ff8ba5c764c43cb124e34a9245e45b83c22e81041e1071aee10", size = 280317, upload-time = "2026-01-14T23:16:15.718Z" }, + { url = "https://files.pythonhosted.org/packages/b4/52/4317f7a5988544e34ab57b4bde0f04944c4786128c933fb09825924d3e82/regex-2026.1.15-cp313-cp313t-win_arm64.whl", hash = "sha256:b2a13dd6a95e95a489ca242319d18fc02e07ceb28fa9ad146385194d95b3c829", size = 271551, upload-time = "2026-01-14T23:16:17.533Z" }, + { url = "https://files.pythonhosted.org/packages/52/0a/47fa888ec7cbbc7d62c5f2a6a888878e76169170ead271a35239edd8f0e8/regex-2026.1.15-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:d920392a6b1f353f4aa54328c867fec3320fa50657e25f64abf17af054fc97ac", size = 489170, upload-time = "2026-01-14T23:16:19.835Z" }, + { url = "https://files.pythonhosted.org/packages/ac/c4/d000e9b7296c15737c9301708e9e7fbdea009f8e93541b6b43bdb8219646/regex-2026.1.15-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:b5a28980a926fa810dbbed059547b02783952e2efd9c636412345232ddb87ff6", size = 291146, upload-time = "2026-01-14T23:16:21.541Z" }, + { url = "https://files.pythonhosted.org/packages/f9/b6/921cc61982e538682bdf3bdf5b2c6ab6b34368da1f8e98a6c1ddc503c9cf/regex-2026.1.15-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:621f73a07595d83f28952d7bd1e91e9d1ed7625fb7af0064d3516674ec93a2a2", size = 288986, upload-time = "2026-01-14T23:16:23.381Z" }, + { url = "https://files.pythonhosted.org/packages/ca/33/eb7383dde0bbc93f4fb9d03453aab97e18ad4024ac7e26cef8d1f0a2cff0/regex-2026.1.15-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3d7d92495f47567a9b1669c51fc8d6d809821849063d168121ef801bbc213846", size = 799098, upload-time = "2026-01-14T23:16:25.088Z" }, + { url = "https://files.pythonhosted.org/packages/27/56/b664dccae898fc8d8b4c23accd853f723bde0f026c747b6f6262b688029c/regex-2026.1.15-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8dd16fba2758db7a3780a051f245539c4451ca20910f5a5e6ea1c08d06d4a76b", size = 864980, upload-time = "2026-01-14T23:16:27.297Z" }, + { url = "https://files.pythonhosted.org/packages/16/40/0999e064a170eddd237bae9ccfcd8f28b3aa98a38bf727a086425542a4fc/regex-2026.1.15-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:1e1808471fbe44c1a63e5f577a1d5f02fe5d66031dcbdf12f093ffc1305a858e", size = 911607, upload-time = "2026-01-14T23:16:29.235Z" }, + { url = "https://files.pythonhosted.org/packages/07/78/c77f644b68ab054e5a674fb4da40ff7bffb2c88df58afa82dbf86573092d/regex-2026.1.15-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0751a26ad39d4f2ade8fe16c59b2bf5cb19eb3d2cd543e709e583d559bd9efde", size = 803358, upload-time = "2026-01-14T23:16:31.369Z" }, + { url = "https://files.pythonhosted.org/packages/27/31/d4292ea8566eaa551fafc07797961c5963cf5235c797cc2ae19b85dfd04d/regex-2026.1.15-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0f0c7684c7f9ca241344ff95a1de964f257a5251968484270e91c25a755532c5", size = 775833, upload-time = "2026-01-14T23:16:33.141Z" }, + { url = "https://files.pythonhosted.org/packages/ce/b2/cff3bf2fea4133aa6fb0d1e370b37544d18c8350a2fa118c7e11d1db0e14/regex-2026.1.15-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:74f45d170a21df41508cb67165456538425185baaf686281fa210d7e729abc34", size = 788045, upload-time = "2026-01-14T23:16:35.005Z" }, + { url = "https://files.pythonhosted.org/packages/8d/99/2cb9b69045372ec877b6f5124bda4eb4253bc58b8fe5848c973f752bc52c/regex-2026.1.15-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:f1862739a1ffb50615c0fde6bae6569b5efbe08d98e59ce009f68a336f64da75", size = 859374, upload-time = "2026-01-14T23:16:36.919Z" }, + { url = "https://files.pythonhosted.org/packages/09/16/710b0a5abe8e077b1729a562d2f297224ad079f3a66dce46844c193416c8/regex-2026.1.15-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:453078802f1b9e2b7303fb79222c054cb18e76f7bdc220f7530fdc85d319f99e", size = 763940, upload-time = "2026-01-14T23:16:38.685Z" }, + { url = "https://files.pythonhosted.org/packages/dd/d1/7585c8e744e40eb3d32f119191969b91de04c073fca98ec14299041f6e7e/regex-2026.1.15-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:a30a68e89e5a218b8b23a52292924c1f4b245cb0c68d1cce9aec9bbda6e2c160", size = 850112, upload-time = "2026-01-14T23:16:40.646Z" }, + { url = "https://files.pythonhosted.org/packages/af/d6/43e1dd85df86c49a347aa57c1f69d12c652c7b60e37ec162e3096194a278/regex-2026.1.15-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:9479cae874c81bf610d72b85bb681a94c95722c127b55445285fb0e2c82db8e1", size = 789586, upload-time = "2026-01-14T23:16:42.799Z" }, + { url = "https://files.pythonhosted.org/packages/93/38/77142422f631e013f316aaae83234c629555729a9fbc952b8a63ac91462a/regex-2026.1.15-cp314-cp314-win32.whl", hash = "sha256:d639a750223132afbfb8f429c60d9d318aeba03281a5f1ab49f877456448dcf1", size = 271691, upload-time = "2026-01-14T23:16:44.671Z" }, + { url = "https://files.pythonhosted.org/packages/4a/a9/ab16b4649524ca9e05213c1cdbb7faa85cc2aa90a0230d2f796cbaf22736/regex-2026.1.15-cp314-cp314-win_amd64.whl", hash = "sha256:4161d87f85fa831e31469bfd82c186923070fc970b9de75339b68f0c75b51903", size = 280422, upload-time = "2026-01-14T23:16:46.607Z" }, + { url = "https://files.pythonhosted.org/packages/be/2a/20fd057bf3521cb4791f69f869635f73e0aaf2b9ad2d260f728144f9047c/regex-2026.1.15-cp314-cp314-win_arm64.whl", hash = "sha256:91c5036ebb62663a6b3999bdd2e559fd8456d17e2b485bf509784cd31a8b1705", size = 273467, upload-time = "2026-01-14T23:16:48.967Z" }, + { url = "https://files.pythonhosted.org/packages/ad/77/0b1e81857060b92b9cad239104c46507dd481b3ff1fa79f8e7f865aae38a/regex-2026.1.15-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:ee6854c9000a10938c79238de2379bea30c82e4925a371711af45387df35cab8", size = 492073, upload-time = "2026-01-14T23:16:51.154Z" }, + { url = "https://files.pythonhosted.org/packages/70/f3/f8302b0c208b22c1e4f423147e1913fd475ddd6230565b299925353de644/regex-2026.1.15-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2c2b80399a422348ce5de4fe40c418d6299a0fa2803dd61dc0b1a2f28e280fcf", size = 292757, upload-time = "2026-01-14T23:16:53.08Z" }, + { url = "https://files.pythonhosted.org/packages/bf/f0/ef55de2460f3b4a6da9d9e7daacd0cb79d4ef75c64a2af316e68447f0df0/regex-2026.1.15-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:dca3582bca82596609959ac39e12b7dad98385b4fefccb1151b937383cec547d", size = 291122, upload-time = "2026-01-14T23:16:55.383Z" }, + { url = "https://files.pythonhosted.org/packages/cf/55/bb8ccbacabbc3a11d863ee62a9f18b160a83084ea95cdfc5d207bfc3dd75/regex-2026.1.15-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ef71d476caa6692eea743ae5ea23cde3260677f70122c4d258ca952e5c2d4e84", size = 807761, upload-time = "2026-01-14T23:16:57.251Z" }, + { url = "https://files.pythonhosted.org/packages/8f/84/f75d937f17f81e55679a0509e86176e29caa7298c38bd1db7ce9c0bf6075/regex-2026.1.15-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c243da3436354f4af6c3058a3f81a97d47ea52c9bd874b52fd30274853a1d5df", size = 873538, upload-time = "2026-01-14T23:16:59.349Z" }, + { url = "https://files.pythonhosted.org/packages/b8/d9/0da86327df70349aa8d86390da91171bd3ca4f0e7c1d1d453a9c10344da3/regex-2026.1.15-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8355ad842a7c7e9e5e55653eade3b7d1885ba86f124dd8ab1f722f9be6627434", size = 915066, upload-time = "2026-01-14T23:17:01.607Z" }, + { url = "https://files.pythonhosted.org/packages/2a/5e/f660fb23fc77baa2a61aa1f1fe3a4eea2bbb8a286ddec148030672e18834/regex-2026.1.15-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f192a831d9575271a22d804ff1a5355355723f94f31d9eef25f0d45a152fdc1a", size = 812938, upload-time = "2026-01-14T23:17:04.366Z" }, + { url = "https://files.pythonhosted.org/packages/69/33/a47a29bfecebbbfd1e5cd3f26b28020a97e4820f1c5148e66e3b7d4b4992/regex-2026.1.15-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:166551807ec20d47ceaeec380081f843e88c8949780cd42c40f18d16168bed10", size = 781314, upload-time = "2026-01-14T23:17:06.378Z" }, + { url = "https://files.pythonhosted.org/packages/65/ec/7ec2bbfd4c3f4e494a24dec4c6943a668e2030426b1b8b949a6462d2c17b/regex-2026.1.15-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:f9ca1cbdc0fbfe5e6e6f8221ef2309988db5bcede52443aeaee9a4ad555e0dac", size = 795652, upload-time = "2026-01-14T23:17:08.521Z" }, + { url = "https://files.pythonhosted.org/packages/46/79/a5d8651ae131fe27d7c521ad300aa7f1c7be1dbeee4d446498af5411b8a9/regex-2026.1.15-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:b30bcbd1e1221783c721483953d9e4f3ab9c5d165aa709693d3f3946747b1aea", size = 868550, upload-time = "2026-01-14T23:17:10.573Z" }, + { url = "https://files.pythonhosted.org/packages/06/b7/25635d2809664b79f183070786a5552dd4e627e5aedb0065f4e3cf8ee37d/regex-2026.1.15-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:2a8d7b50c34578d0d3bf7ad58cde9652b7d683691876f83aedc002862a35dc5e", size = 769981, upload-time = "2026-01-14T23:17:12.871Z" }, + { url = "https://files.pythonhosted.org/packages/16/8b/fc3fcbb2393dcfa4a6c5ffad92dc498e842df4581ea9d14309fcd3c55fb9/regex-2026.1.15-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:9d787e3310c6a6425eb346be4ff2ccf6eece63017916fd77fe8328c57be83521", size = 854780, upload-time = "2026-01-14T23:17:14.837Z" }, + { url = "https://files.pythonhosted.org/packages/d0/38/dde117c76c624713c8a2842530be9c93ca8b606c0f6102d86e8cd1ce8bea/regex-2026.1.15-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:619843841e220adca114118533a574a9cd183ed8a28b85627d2844c500a2b0db", size = 799778, upload-time = "2026-01-14T23:17:17.369Z" }, + { url = "https://files.pythonhosted.org/packages/e3/0d/3a6cfa9ae99606afb612d8fb7a66b245a9d5ff0f29bb347c8a30b6ad561b/regex-2026.1.15-cp314-cp314t-win32.whl", hash = "sha256:e90b8db97f6f2c97eb045b51a6b2c5ed69cedd8392459e0642d4199b94fabd7e", size = 274667, upload-time = "2026-01-14T23:17:19.301Z" }, + { url = "https://files.pythonhosted.org/packages/5b/b2/297293bb0742fd06b8d8e2572db41a855cdf1cae0bf009b1cb74fe07e196/regex-2026.1.15-cp314-cp314t-win_amd64.whl", hash = "sha256:5ef19071f4ac9f0834793af85bd04a920b4407715624e40cb7a0631a11137cdf", size = 284386, upload-time = "2026-01-14T23:17:21.231Z" }, + { url = "https://files.pythonhosted.org/packages/95/e4/a3b9480c78cf8ee86626cb06f8d931d74d775897d44201ccb813097ae697/regex-2026.1.15-cp314-cp314t-win_arm64.whl", hash = "sha256:ca89c5e596fc05b015f27561b3793dc2fa0917ea0d7507eebb448efd35274a70", size = 274837, upload-time = "2026-01-14T23:17:23.146Z" }, ] [[package]] @@ -316,51 +330,56 @@ wheels = [ [[package]] name = "tomli" -version = "2.3.0" +version = "2.4.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/52/ed/3f73f72945444548f33eba9a87fc7a6e969915e7b1acc8260b30e1f76a2f/tomli-2.3.0.tar.gz", hash = "sha256:64be704a875d2a59753d80ee8a533c3fe183e3f06807ff7dc2232938ccb01549", size = 17392, upload-time = "2025-10-08T22:01:47.119Z" } +sdist = { url = "https://files.pythonhosted.org/packages/82/30/31573e9457673ab10aa432461bee537ce6cef177667deca369efb79df071/tomli-2.4.0.tar.gz", hash = "sha256:aa89c3f6c277dd275d8e243ad24f3b5e701491a860d5121f2cdd399fbb31fc9c", size = 17477, upload-time = "2026-01-11T11:22:38.165Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b3/2e/299f62b401438d5fe1624119c723f5d877acc86a4c2492da405626665f12/tomli-2.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:88bd15eb972f3664f5ed4b57c1634a97153b4bac4479dcb6a495f41921eb7f45", size = 153236, upload-time = "2025-10-08T22:01:00.137Z" }, - { url = "https://files.pythonhosted.org/packages/86/7f/d8fffe6a7aefdb61bced88fcb5e280cfd71e08939da5894161bd71bea022/tomli-2.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:883b1c0d6398a6a9d29b508c331fa56adbcdff647f6ace4dfca0f50e90dfd0ba", size = 148084, upload-time = "2025-10-08T22:01:01.63Z" }, - { url = "https://files.pythonhosted.org/packages/47/5c/24935fb6a2ee63e86d80e4d3b58b222dafaf438c416752c8b58537c8b89a/tomli-2.3.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d1381caf13ab9f300e30dd8feadb3de072aeb86f1d34a8569453ff32a7dea4bf", size = 234832, upload-time = "2025-10-08T22:01:02.543Z" }, - { url = "https://files.pythonhosted.org/packages/89/da/75dfd804fc11e6612846758a23f13271b76d577e299592b4371a4ca4cd09/tomli-2.3.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a0e285d2649b78c0d9027570d4da3425bdb49830a6156121360b3f8511ea3441", size = 242052, upload-time = "2025-10-08T22:01:03.836Z" }, - { url = "https://files.pythonhosted.org/packages/70/8c/f48ac899f7b3ca7eb13af73bacbc93aec37f9c954df3c08ad96991c8c373/tomli-2.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0a154a9ae14bfcf5d8917a59b51ffd5a3ac1fd149b71b47a3a104ca4edcfa845", size = 239555, upload-time = "2025-10-08T22:01:04.834Z" }, - { url = "https://files.pythonhosted.org/packages/ba/28/72f8afd73f1d0e7829bfc093f4cb98ce0a40ffc0cc997009ee1ed94ba705/tomli-2.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:74bf8464ff93e413514fefd2be591c3b0b23231a77f901db1eb30d6f712fc42c", size = 245128, upload-time = "2025-10-08T22:01:05.84Z" }, - { url = "https://files.pythonhosted.org/packages/b6/eb/a7679c8ac85208706d27436e8d421dfa39d4c914dcf5fa8083a9305f58d9/tomli-2.3.0-cp311-cp311-win32.whl", hash = "sha256:00b5f5d95bbfc7d12f91ad8c593a1659b6387b43f054104cda404be6bda62456", size = 96445, upload-time = "2025-10-08T22:01:06.896Z" }, - { url = "https://files.pythonhosted.org/packages/0a/fe/3d3420c4cb1ad9cb462fb52967080575f15898da97e21cb6f1361d505383/tomli-2.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:4dc4ce8483a5d429ab602f111a93a6ab1ed425eae3122032db7e9acf449451be", size = 107165, upload-time = "2025-10-08T22:01:08.107Z" }, - { url = "https://files.pythonhosted.org/packages/ff/b7/40f36368fcabc518bb11c8f06379a0fd631985046c038aca08c6d6a43c6e/tomli-2.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d7d86942e56ded512a594786a5ba0a5e521d02529b3826e7761a05138341a2ac", size = 154891, upload-time = "2025-10-08T22:01:09.082Z" }, - { url = "https://files.pythonhosted.org/packages/f9/3f/d9dd692199e3b3aab2e4e4dd948abd0f790d9ded8cd10cbaae276a898434/tomli-2.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:73ee0b47d4dad1c5e996e3cd33b8a76a50167ae5f96a2607cbe8cc773506ab22", size = 148796, upload-time = "2025-10-08T22:01:10.266Z" }, - { url = "https://files.pythonhosted.org/packages/60/83/59bff4996c2cf9f9387a0f5a3394629c7efa5ef16142076a23a90f1955fa/tomli-2.3.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:792262b94d5d0a466afb5bc63c7daa9d75520110971ee269152083270998316f", size = 242121, upload-time = "2025-10-08T22:01:11.332Z" }, - { url = "https://files.pythonhosted.org/packages/45/e5/7c5119ff39de8693d6baab6c0b6dcb556d192c165596e9fc231ea1052041/tomli-2.3.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4f195fe57ecceac95a66a75ac24d9d5fbc98ef0962e09b2eddec5d39375aae52", size = 250070, upload-time = "2025-10-08T22:01:12.498Z" }, - { url = "https://files.pythonhosted.org/packages/45/12/ad5126d3a278f27e6701abde51d342aa78d06e27ce2bb596a01f7709a5a2/tomli-2.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e31d432427dcbf4d86958c184b9bfd1e96b5b71f8eb17e6d02531f434fd335b8", size = 245859, upload-time = "2025-10-08T22:01:13.551Z" }, - { url = "https://files.pythonhosted.org/packages/fb/a1/4d6865da6a71c603cfe6ad0e6556c73c76548557a8d658f9e3b142df245f/tomli-2.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7b0882799624980785240ab732537fcfc372601015c00f7fc367c55308c186f6", size = 250296, upload-time = "2025-10-08T22:01:14.614Z" }, - { url = "https://files.pythonhosted.org/packages/a0/b7/a7a7042715d55c9ba6e8b196d65d2cb662578b4d8cd17d882d45322b0d78/tomli-2.3.0-cp312-cp312-win32.whl", hash = "sha256:ff72b71b5d10d22ecb084d345fc26f42b5143c5533db5e2eaba7d2d335358876", size = 97124, upload-time = "2025-10-08T22:01:15.629Z" }, - { url = "https://files.pythonhosted.org/packages/06/1e/f22f100db15a68b520664eb3328fb0ae4e90530887928558112c8d1f4515/tomli-2.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:1cb4ed918939151a03f33d4242ccd0aa5f11b3547d0cf30f7c74a408a5b99878", size = 107698, upload-time = "2025-10-08T22:01:16.51Z" }, - { url = "https://files.pythonhosted.org/packages/89/48/06ee6eabe4fdd9ecd48bf488f4ac783844fd777f547b8d1b61c11939974e/tomli-2.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5192f562738228945d7b13d4930baffda67b69425a7f0da96d360b0a3888136b", size = 154819, upload-time = "2025-10-08T22:01:17.964Z" }, - { url = "https://files.pythonhosted.org/packages/f1/01/88793757d54d8937015c75dcdfb673c65471945f6be98e6a0410fba167ed/tomli-2.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:be71c93a63d738597996be9528f4abe628d1adf5e6eb11607bc8fe1a510b5dae", size = 148766, upload-time = "2025-10-08T22:01:18.959Z" }, - { url = "https://files.pythonhosted.org/packages/42/17/5e2c956f0144b812e7e107f94f1cc54af734eb17b5191c0bbfb72de5e93e/tomli-2.3.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c4665508bcbac83a31ff8ab08f424b665200c0e1e645d2bd9ab3d3e557b6185b", size = 240771, upload-time = "2025-10-08T22:01:20.106Z" }, - { url = "https://files.pythonhosted.org/packages/d5/f4/0fbd014909748706c01d16824eadb0307115f9562a15cbb012cd9b3512c5/tomli-2.3.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4021923f97266babc6ccab9f5068642a0095faa0a51a246a6a02fccbb3514eaf", size = 248586, upload-time = "2025-10-08T22:01:21.164Z" }, - { url = "https://files.pythonhosted.org/packages/30/77/fed85e114bde5e81ecf9bc5da0cc69f2914b38f4708c80ae67d0c10180c5/tomli-2.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4ea38c40145a357d513bffad0ed869f13c1773716cf71ccaa83b0fa0cc4e42f", size = 244792, upload-time = "2025-10-08T22:01:22.417Z" }, - { url = "https://files.pythonhosted.org/packages/55/92/afed3d497f7c186dc71e6ee6d4fcb0acfa5f7d0a1a2878f8beae379ae0cc/tomli-2.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ad805ea85eda330dbad64c7ea7a4556259665bdf9d2672f5dccc740eb9d3ca05", size = 248909, upload-time = "2025-10-08T22:01:23.859Z" }, - { url = "https://files.pythonhosted.org/packages/f8/84/ef50c51b5a9472e7265ce1ffc7f24cd4023d289e109f669bdb1553f6a7c2/tomli-2.3.0-cp313-cp313-win32.whl", hash = "sha256:97d5eec30149fd3294270e889b4234023f2c69747e555a27bd708828353ab606", size = 96946, upload-time = "2025-10-08T22:01:24.893Z" }, - { url = "https://files.pythonhosted.org/packages/b2/b7/718cd1da0884f281f95ccfa3a6cc572d30053cba64603f79d431d3c9b61b/tomli-2.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:0c95ca56fbe89e065c6ead5b593ee64b84a26fca063b5d71a1122bf26e533999", size = 107705, upload-time = "2025-10-08T22:01:26.153Z" }, - { url = "https://files.pythonhosted.org/packages/19/94/aeafa14a52e16163008060506fcb6aa1949d13548d13752171a755c65611/tomli-2.3.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:cebc6fe843e0733ee827a282aca4999b596241195f43b4cc371d64fc6639da9e", size = 154244, upload-time = "2025-10-08T22:01:27.06Z" }, - { url = "https://files.pythonhosted.org/packages/db/e4/1e58409aa78eefa47ccd19779fc6f36787edbe7d4cd330eeeedb33a4515b/tomli-2.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:4c2ef0244c75aba9355561272009d934953817c49f47d768070c3c94355c2aa3", size = 148637, upload-time = "2025-10-08T22:01:28.059Z" }, - { url = "https://files.pythonhosted.org/packages/26/b6/d1eccb62f665e44359226811064596dd6a366ea1f985839c566cd61525ae/tomli-2.3.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c22a8bf253bacc0cf11f35ad9808b6cb75ada2631c2d97c971122583b129afbc", size = 241925, upload-time = "2025-10-08T22:01:29.066Z" }, - { url = "https://files.pythonhosted.org/packages/70/91/7cdab9a03e6d3d2bb11beae108da5bdc1c34bdeb06e21163482544ddcc90/tomli-2.3.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0eea8cc5c5e9f89c9b90c4896a8deefc74f518db5927d0e0e8d4a80953d774d0", size = 249045, upload-time = "2025-10-08T22:01:31.98Z" }, - { url = "https://files.pythonhosted.org/packages/15/1b/8c26874ed1f6e4f1fcfeb868db8a794cbe9f227299402db58cfcc858766c/tomli-2.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:b74a0e59ec5d15127acdabd75ea17726ac4c5178ae51b85bfe39c4f8a278e879", size = 245835, upload-time = "2025-10-08T22:01:32.989Z" }, - { url = "https://files.pythonhosted.org/packages/fd/42/8e3c6a9a4b1a1360c1a2a39f0b972cef2cc9ebd56025168c4137192a9321/tomli-2.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b5870b50c9db823c595983571d1296a6ff3e1b88f734a4c8f6fc6188397de005", size = 253109, upload-time = "2025-10-08T22:01:34.052Z" }, - { url = "https://files.pythonhosted.org/packages/22/0c/b4da635000a71b5f80130937eeac12e686eefb376b8dee113b4a582bba42/tomli-2.3.0-cp314-cp314-win32.whl", hash = "sha256:feb0dacc61170ed7ab602d3d972a58f14ee3ee60494292d384649a3dc38ef463", size = 97930, upload-time = "2025-10-08T22:01:35.082Z" }, - { url = "https://files.pythonhosted.org/packages/b9/74/cb1abc870a418ae99cd5c9547d6bce30701a954e0e721821df483ef7223c/tomli-2.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:b273fcbd7fc64dc3600c098e39136522650c49bca95df2d11cf3b626422392c8", size = 107964, upload-time = "2025-10-08T22:01:36.057Z" }, - { url = "https://files.pythonhosted.org/packages/54/78/5c46fff6432a712af9f792944f4fcd7067d8823157949f4e40c56b8b3c83/tomli-2.3.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:940d56ee0410fa17ee1f12b817b37a4d4e4dc4d27340863cc67236c74f582e77", size = 163065, upload-time = "2025-10-08T22:01:37.27Z" }, - { url = "https://files.pythonhosted.org/packages/39/67/f85d9bd23182f45eca8939cd2bc7050e1f90c41f4a2ecbbd5963a1d1c486/tomli-2.3.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:f85209946d1fe94416debbb88d00eb92ce9cd5266775424ff81bc959e001acaf", size = 159088, upload-time = "2025-10-08T22:01:38.235Z" }, - { url = "https://files.pythonhosted.org/packages/26/5a/4b546a0405b9cc0659b399f12b6adb750757baf04250b148d3c5059fc4eb/tomli-2.3.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a56212bdcce682e56b0aaf79e869ba5d15a6163f88d5451cbde388d48b13f530", size = 268193, upload-time = "2025-10-08T22:01:39.712Z" }, - { url = "https://files.pythonhosted.org/packages/42/4f/2c12a72ae22cf7b59a7fe75b3465b7aba40ea9145d026ba41cb382075b0e/tomli-2.3.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c5f3ffd1e098dfc032d4d3af5c0ac64f6d286d98bc148698356847b80fa4de1b", size = 275488, upload-time = "2025-10-08T22:01:40.773Z" }, - { url = "https://files.pythonhosted.org/packages/92/04/a038d65dbe160c3aa5a624e93ad98111090f6804027d474ba9c37c8ae186/tomli-2.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5e01decd096b1530d97d5d85cb4dff4af2d8347bd35686654a004f8dea20fc67", size = 272669, upload-time = "2025-10-08T22:01:41.824Z" }, - { url = "https://files.pythonhosted.org/packages/be/2f/8b7c60a9d1612a7cbc39ffcca4f21a73bf368a80fc25bccf8253e2563267/tomli-2.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:8a35dd0e643bb2610f156cca8db95d213a90015c11fee76c946aa62b7ae7e02f", size = 279709, upload-time = "2025-10-08T22:01:43.177Z" }, - { url = "https://files.pythonhosted.org/packages/7e/46/cc36c679f09f27ded940281c38607716c86cf8ba4a518d524e349c8b4874/tomli-2.3.0-cp314-cp314t-win32.whl", hash = "sha256:a1f7f282fe248311650081faafa5f4732bdbfef5d45fe3f2e702fbc6f2d496e0", size = 107563, upload-time = "2025-10-08T22:01:44.233Z" }, - { url = "https://files.pythonhosted.org/packages/84/ff/426ca8683cf7b753614480484f6437f568fd2fda2edbdf57a2d3d8b27a0b/tomli-2.3.0-cp314-cp314t-win_amd64.whl", hash = "sha256:70a251f8d4ba2d9ac2542eecf008b3c8a9fc5c3f9f02c56a9d7952612be2fdba", size = 119756, upload-time = "2025-10-08T22:01:45.234Z" }, - { url = "https://files.pythonhosted.org/packages/77/b8/0135fadc89e73be292b473cb820b4f5a08197779206b33191e801feeae40/tomli-2.3.0-py3-none-any.whl", hash = "sha256:e95b1af3c5b07d9e643909b5abbec77cd9f1217e6d0bca72b0234736b9fb1f1b", size = 14408, upload-time = "2025-10-08T22:01:46.04Z" }, + { url = "https://files.pythonhosted.org/packages/3c/d9/3dc2289e1f3b32eb19b9785b6a006b28ee99acb37d1d47f78d4c10e28bf8/tomli-2.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b5ef256a3fd497d4973c11bf142e9ed78b150d36f5773f1ca6088c230ffc5867", size = 153663, upload-time = "2026-01-11T11:21:45.27Z" }, + { url = "https://files.pythonhosted.org/packages/51/32/ef9f6845e6b9ca392cd3f64f9ec185cc6f09f0a2df3db08cbe8809d1d435/tomli-2.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5572e41282d5268eb09a697c89a7bee84fae66511f87533a6f88bd2f7b652da9", size = 148469, upload-time = "2026-01-11T11:21:46.873Z" }, + { url = "https://files.pythonhosted.org/packages/d6/c2/506e44cce89a8b1b1e047d64bd495c22c9f71f21e05f380f1a950dd9c217/tomli-2.4.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:551e321c6ba03b55676970b47cb1b73f14a0a4dce6a3e1a9458fd6d921d72e95", size = 236039, upload-time = "2026-01-11T11:21:48.503Z" }, + { url = "https://files.pythonhosted.org/packages/b3/40/e1b65986dbc861b7e986e8ec394598187fa8aee85b1650b01dd925ca0be8/tomli-2.4.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5e3f639a7a8f10069d0e15408c0b96a2a828cfdec6fca05296ebcdcc28ca7c76", size = 243007, upload-time = "2026-01-11T11:21:49.456Z" }, + { url = "https://files.pythonhosted.org/packages/9c/6f/6e39ce66b58a5b7ae572a0f4352ff40c71e8573633deda43f6a379d56b3e/tomli-2.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1b168f2731796b045128c45982d3a4874057626da0e2ef1fdd722848b741361d", size = 240875, upload-time = "2026-01-11T11:21:50.755Z" }, + { url = "https://files.pythonhosted.org/packages/aa/ad/cb089cb190487caa80204d503c7fd0f4d443f90b95cf4ef5cf5aa0f439b0/tomli-2.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:133e93646ec4300d651839d382d63edff11d8978be23da4cc106f5a18b7d0576", size = 246271, upload-time = "2026-01-11T11:21:51.81Z" }, + { url = "https://files.pythonhosted.org/packages/0b/63/69125220e47fd7a3a27fd0de0c6398c89432fec41bc739823bcc66506af6/tomli-2.4.0-cp311-cp311-win32.whl", hash = "sha256:b6c78bdf37764092d369722d9946cb65b8767bfa4110f902a1b2542d8d173c8a", size = 96770, upload-time = "2026-01-11T11:21:52.647Z" }, + { url = "https://files.pythonhosted.org/packages/1e/0d/a22bb6c83f83386b0008425a6cd1fa1c14b5f3dd4bad05e98cf3dbbf4a64/tomli-2.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:d3d1654e11d724760cdb37a3d7691f0be9db5fbdaef59c9f532aabf87006dbaa", size = 107626, upload-time = "2026-01-11T11:21:53.459Z" }, + { url = "https://files.pythonhosted.org/packages/2f/6d/77be674a3485e75cacbf2ddba2b146911477bd887dda9d8c9dfb2f15e871/tomli-2.4.0-cp311-cp311-win_arm64.whl", hash = "sha256:cae9c19ed12d4e8f3ebf46d1a75090e4c0dc16271c5bce1c833ac168f08fb614", size = 94842, upload-time = "2026-01-11T11:21:54.831Z" }, + { url = "https://files.pythonhosted.org/packages/3c/43/7389a1869f2f26dba52404e1ef13b4784b6b37dac93bac53457e3ff24ca3/tomli-2.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:920b1de295e72887bafa3ad9f7a792f811847d57ea6b1215154030cf131f16b1", size = 154894, upload-time = "2026-01-11T11:21:56.07Z" }, + { url = "https://files.pythonhosted.org/packages/e9/05/2f9bf110b5294132b2edf13fe6ca6ae456204f3d749f623307cbb7a946f2/tomli-2.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7d6d9a4aee98fac3eab4952ad1d73aee87359452d1c086b5ceb43ed02ddb16b8", size = 149053, upload-time = "2026-01-11T11:21:57.467Z" }, + { url = "https://files.pythonhosted.org/packages/e8/41/1eda3ca1abc6f6154a8db4d714a4d35c4ad90adc0bcf700657291593fbf3/tomli-2.4.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:36b9d05b51e65b254ea6c2585b59d2c4cb91c8a3d91d0ed0f17591a29aaea54a", size = 243481, upload-time = "2026-01-11T11:21:58.661Z" }, + { url = "https://files.pythonhosted.org/packages/d2/6d/02ff5ab6c8868b41e7d4b987ce2b5f6a51d3335a70aa144edd999e055a01/tomli-2.4.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1c8a885b370751837c029ef9bc014f27d80840e48bac415f3412e6593bbc18c1", size = 251720, upload-time = "2026-01-11T11:22:00.178Z" }, + { url = "https://files.pythonhosted.org/packages/7b/57/0405c59a909c45d5b6f146107c6d997825aa87568b042042f7a9c0afed34/tomli-2.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8768715ffc41f0008abe25d808c20c3d990f42b6e2e58305d5da280ae7d1fa3b", size = 247014, upload-time = "2026-01-11T11:22:01.238Z" }, + { url = "https://files.pythonhosted.org/packages/2c/0e/2e37568edd944b4165735687cbaf2fe3648129e440c26d02223672ee0630/tomli-2.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7b438885858efd5be02a9a133caf5812b8776ee0c969fea02c45e8e3f296ba51", size = 251820, upload-time = "2026-01-11T11:22:02.727Z" }, + { url = "https://files.pythonhosted.org/packages/5a/1c/ee3b707fdac82aeeb92d1a113f803cf6d0f37bdca0849cb489553e1f417a/tomli-2.4.0-cp312-cp312-win32.whl", hash = "sha256:0408e3de5ec77cc7f81960c362543cbbd91ef883e3138e81b729fc3eea5b9729", size = 97712, upload-time = "2026-01-11T11:22:03.777Z" }, + { url = "https://files.pythonhosted.org/packages/69/13/c07a9177d0b3bab7913299b9278845fc6eaaca14a02667c6be0b0a2270c8/tomli-2.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:685306e2cc7da35be4ee914fd34ab801a6acacb061b6a7abca922aaf9ad368da", size = 108296, upload-time = "2026-01-11T11:22:04.86Z" }, + { url = "https://files.pythonhosted.org/packages/18/27/e267a60bbeeee343bcc279bb9e8fbed0cbe224bc7b2a3dc2975f22809a09/tomli-2.4.0-cp312-cp312-win_arm64.whl", hash = "sha256:5aa48d7c2356055feef06a43611fc401a07337d5b006be13a30f6c58f869e3c3", size = 94553, upload-time = "2026-01-11T11:22:05.854Z" }, + { url = "https://files.pythonhosted.org/packages/34/91/7f65f9809f2936e1f4ce6268ae1903074563603b2a2bd969ebbda802744f/tomli-2.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:84d081fbc252d1b6a982e1870660e7330fb8f90f676f6e78b052ad4e64714bf0", size = 154915, upload-time = "2026-01-11T11:22:06.703Z" }, + { url = "https://files.pythonhosted.org/packages/20/aa/64dd73a5a849c2e8f216b755599c511badde80e91e9bc2271baa7b2cdbb1/tomli-2.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9a08144fa4cba33db5255f9b74f0b89888622109bd2776148f2597447f92a94e", size = 149038, upload-time = "2026-01-11T11:22:07.56Z" }, + { url = "https://files.pythonhosted.org/packages/9e/8a/6d38870bd3d52c8d1505ce054469a73f73a0fe62c0eaf5dddf61447e32fa/tomli-2.4.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c73add4bb52a206fd0c0723432db123c0c75c280cbd67174dd9d2db228ebb1b4", size = 242245, upload-time = "2026-01-11T11:22:08.344Z" }, + { url = "https://files.pythonhosted.org/packages/59/bb/8002fadefb64ab2669e5b977df3f5e444febea60e717e755b38bb7c41029/tomli-2.4.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1fb2945cbe303b1419e2706e711b7113da57b7db31ee378d08712d678a34e51e", size = 250335, upload-time = "2026-01-11T11:22:09.951Z" }, + { url = "https://files.pythonhosted.org/packages/a5/3d/4cdb6f791682b2ea916af2de96121b3cb1284d7c203d97d92d6003e91c8d/tomli-2.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bbb1b10aa643d973366dc2cb1ad94f99c1726a02343d43cbc011edbfac579e7c", size = 245962, upload-time = "2026-01-11T11:22:11.27Z" }, + { url = "https://files.pythonhosted.org/packages/f2/4a/5f25789f9a460bd858ba9756ff52d0830d825b458e13f754952dd15fb7bb/tomli-2.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4cbcb367d44a1f0c2be408758b43e1ffb5308abe0ea222897d6bfc8e8281ef2f", size = 250396, upload-time = "2026-01-11T11:22:12.325Z" }, + { url = "https://files.pythonhosted.org/packages/aa/2f/b73a36fea58dfa08e8b3a268750e6853a6aac2a349241a905ebd86f3047a/tomli-2.4.0-cp313-cp313-win32.whl", hash = "sha256:7d49c66a7d5e56ac959cb6fc583aff0651094ec071ba9ad43df785abc2320d86", size = 97530, upload-time = "2026-01-11T11:22:13.865Z" }, + { url = "https://files.pythonhosted.org/packages/3b/af/ca18c134b5d75de7e8dc551c5234eaba2e8e951f6b30139599b53de9c187/tomli-2.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:3cf226acb51d8f1c394c1b310e0e0e61fecdd7adcb78d01e294ac297dd2e7f87", size = 108227, upload-time = "2026-01-11T11:22:15.224Z" }, + { url = "https://files.pythonhosted.org/packages/22/c3/b386b832f209fee8073c8138ec50f27b4460db2fdae9ffe022df89a57f9b/tomli-2.4.0-cp313-cp313-win_arm64.whl", hash = "sha256:d20b797a5c1ad80c516e41bc1fb0443ddb5006e9aaa7bda2d71978346aeb9132", size = 94748, upload-time = "2026-01-11T11:22:16.009Z" }, + { url = "https://files.pythonhosted.org/packages/f3/c4/84047a97eb1004418bc10bdbcfebda209fca6338002eba2dc27cc6d13563/tomli-2.4.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:26ab906a1eb794cd4e103691daa23d95c6919cc2fa9160000ac02370cc9dd3f6", size = 154725, upload-time = "2026-01-11T11:22:17.269Z" }, + { url = "https://files.pythonhosted.org/packages/a8/5d/d39038e646060b9d76274078cddf146ced86dc2b9e8bbf737ad5983609a0/tomli-2.4.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:20cedb4ee43278bc4f2fee6cb50daec836959aadaf948db5172e776dd3d993fc", size = 148901, upload-time = "2026-01-11T11:22:18.287Z" }, + { url = "https://files.pythonhosted.org/packages/73/e5/383be1724cb30f4ce44983d249645684a48c435e1cd4f8b5cded8a816d3c/tomli-2.4.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:39b0b5d1b6dd03684b3fb276407ebed7090bbec989fa55838c98560c01113b66", size = 243375, upload-time = "2026-01-11T11:22:19.154Z" }, + { url = "https://files.pythonhosted.org/packages/31/f0/bea80c17971c8d16d3cc109dc3585b0f2ce1036b5f4a8a183789023574f2/tomli-2.4.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a26d7ff68dfdb9f87a016ecfd1e1c2bacbe3108f4e0f8bcd2228ef9a766c787d", size = 250639, upload-time = "2026-01-11T11:22:20.168Z" }, + { url = "https://files.pythonhosted.org/packages/2c/8f/2853c36abbb7608e3f945d8a74e32ed3a74ee3a1f468f1ffc7d1cb3abba6/tomli-2.4.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:20ffd184fb1df76a66e34bd1b36b4a4641bd2b82954befa32fe8163e79f1a702", size = 246897, upload-time = "2026-01-11T11:22:21.544Z" }, + { url = "https://files.pythonhosted.org/packages/49/f0/6c05e3196ed5337b9fe7ea003e95fd3819a840b7a0f2bf5a408ef1dad8ed/tomli-2.4.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:75c2f8bbddf170e8effc98f5e9084a8751f8174ea6ccf4fca5398436e0320bc8", size = 254697, upload-time = "2026-01-11T11:22:23.058Z" }, + { url = "https://files.pythonhosted.org/packages/f3/f5/2922ef29c9f2951883525def7429967fc4d8208494e5ab524234f06b688b/tomli-2.4.0-cp314-cp314-win32.whl", hash = "sha256:31d556d079d72db7c584c0627ff3a24c5d3fb4f730221d3444f3efb1b2514776", size = 98567, upload-time = "2026-01-11T11:22:24.033Z" }, + { url = "https://files.pythonhosted.org/packages/7b/31/22b52e2e06dd2a5fdbc3ee73226d763b184ff21fc24e20316a44ccc4d96b/tomli-2.4.0-cp314-cp314-win_amd64.whl", hash = "sha256:43e685b9b2341681907759cf3a04e14d7104b3580f808cfde1dfdb60ada85475", size = 108556, upload-time = "2026-01-11T11:22:25.378Z" }, + { url = "https://files.pythonhosted.org/packages/48/3d/5058dff3255a3d01b705413f64f4306a141a8fd7a251e5a495e3f192a998/tomli-2.4.0-cp314-cp314-win_arm64.whl", hash = "sha256:3d895d56bd3f82ddd6faaff993c275efc2ff38e52322ea264122d72729dca2b2", size = 96014, upload-time = "2026-01-11T11:22:26.138Z" }, + { url = "https://files.pythonhosted.org/packages/b8/4e/75dab8586e268424202d3a1997ef6014919c941b50642a1682df43204c22/tomli-2.4.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:5b5807f3999fb66776dbce568cc9a828544244a8eb84b84b9bafc080c99597b9", size = 163339, upload-time = "2026-01-11T11:22:27.143Z" }, + { url = "https://files.pythonhosted.org/packages/06/e3/b904d9ab1016829a776d97f163f183a48be6a4deb87304d1e0116a349519/tomli-2.4.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c084ad935abe686bd9c898e62a02a19abfc9760b5a79bc29644463eaf2840cb0", size = 159490, upload-time = "2026-01-11T11:22:28.399Z" }, + { url = "https://files.pythonhosted.org/packages/e3/5a/fc3622c8b1ad823e8ea98a35e3c632ee316d48f66f80f9708ceb4f2a0322/tomli-2.4.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0f2e3955efea4d1cfbcb87bc321e00dc08d2bcb737fd1d5e398af111d86db5df", size = 269398, upload-time = "2026-01-11T11:22:29.345Z" }, + { url = "https://files.pythonhosted.org/packages/fd/33/62bd6152c8bdd4c305ad9faca48f51d3acb2df1f8791b1477d46ff86e7f8/tomli-2.4.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0e0fe8a0b8312acf3a88077a0802565cb09ee34107813bba1c7cd591fa6cfc8d", size = 276515, upload-time = "2026-01-11T11:22:30.327Z" }, + { url = "https://files.pythonhosted.org/packages/4b/ff/ae53619499f5235ee4211e62a8d7982ba9e439a0fb4f2f351a93d67c1dd2/tomli-2.4.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:413540dce94673591859c4c6f794dfeaa845e98bf35d72ed59636f869ef9f86f", size = 273806, upload-time = "2026-01-11T11:22:32.56Z" }, + { url = "https://files.pythonhosted.org/packages/47/71/cbca7787fa68d4d0a9f7072821980b39fbb1b6faeb5f5cf02f4a5559fa28/tomli-2.4.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:0dc56fef0e2c1c470aeac5b6ca8cc7b640bb93e92d9803ddaf9ea03e198f5b0b", size = 281340, upload-time = "2026-01-11T11:22:33.505Z" }, + { url = "https://files.pythonhosted.org/packages/f5/00/d595c120963ad42474cf6ee7771ad0d0e8a49d0f01e29576ee9195d9ecdf/tomli-2.4.0-cp314-cp314t-win32.whl", hash = "sha256:d878f2a6707cc9d53a1be1414bbb419e629c3d6e67f69230217bb663e76b5087", size = 108106, upload-time = "2026-01-11T11:22:34.451Z" }, + { url = "https://files.pythonhosted.org/packages/de/69/9aa0c6a505c2f80e519b43764f8b4ba93b5a0bbd2d9a9de6e2b24271b9a5/tomli-2.4.0-cp314-cp314t-win_amd64.whl", hash = "sha256:2add28aacc7425117ff6364fe9e06a183bb0251b03f986df0e78e974047571fd", size = 120504, upload-time = "2026-01-11T11:22:35.764Z" }, + { url = "https://files.pythonhosted.org/packages/b3/9f/f1668c281c58cfae01482f7114a4b88d345e4c140386241a1a24dcc9e7bc/tomli-2.4.0-cp314-cp314t-win_arm64.whl", hash = "sha256:2b1e3b80e1d5e52e40e9b924ec43d81570f0e7d09d11081b797bc4692765a3d4", size = 99561, upload-time = "2026-01-11T11:22:36.624Z" }, + { url = "https://files.pythonhosted.org/packages/23/d1/136eb2cb77520a31e1f64cbae9d33ec6df0d78bdf4160398e86eec8a8754/tomli-2.4.0-py3-none-any.whl", hash = "sha256:1f776e7d669ebceb01dee46484485f43a4048746235e683bcdffacdf1fb4785a", size = 14477, upload-time = "2026-01-11T11:22:37.446Z" }, ] [[package]] @@ -386,13 +405,13 @@ wheels = [ [[package]] name = "yamllint" -version = "1.37.1" +version = "1.38.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pathspec" }, { name = "pyyaml" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/46/f2/cd8b7584a48ee83f0bc94f8a32fea38734cefcdc6f7324c4d3bfc699457b/yamllint-1.37.1.tar.gz", hash = "sha256:81f7c0c5559becc8049470d86046b36e96113637bcbe4753ecef06977c00245d", size = 141613, upload-time = "2025-05-04T08:25:54.355Z" } +sdist = { url = "https://files.pythonhosted.org/packages/28/a0/8fc2d68e132cf918f18273fdc8a1b8432b60d75ac12fdae4b0ef5c9d2e8d/yamllint-1.38.0.tar.gz", hash = "sha256:09e5f29531daab93366bb061e76019d5e91691ef0a40328f04c927387d1d364d", size = 142446, upload-time = "2026-01-13T07:47:53.276Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/dd/b9/be7a4cfdf47e03785f657f94daea8123e838d817be76c684298305bd789f/yamllint-1.37.1-py3-none-any.whl", hash = "sha256:364f0d79e81409f591e323725e6a9f4504c8699ddf2d7263d8d2b539cd66a583", size = 68813, upload-time = "2025-05-04T08:25:52.552Z" }, + { url = "https://files.pythonhosted.org/packages/05/92/aed08e68de6e6a3d7c2328ce7388072cd6affc26e2917197430b646aed02/yamllint-1.38.0-py3-none-any.whl", hash = "sha256:fc394a5b3be980a4062607b8fdddc0843f4fa394152b6da21722f5d59013c220", size = 68940, upload-time = "2026-01-13T07:47:51.343Z" }, ]