From 5a3d8d322498bea99cb15dfef92e2f4c21e5ccb6 Mon Sep 17 00:00:00 2001 From: silverwind Date: Mon, 20 Apr 2026 09:10:46 +0200 Subject: [PATCH 01/66] Fix vite manifest update masking build errors (#37279) Moves the manifest patching from `closeBundle` to `writeBundle`. Thrown errors in `writeBundle` work correctly and exit the build. Signed-off-by: silverwind Signed-off-by: wxiaoguang Co-authored-by: Claude (Opus 4.7) Co-authored-by: wxiaoguang --- vite.config.ts | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/vite.config.ts b/vite.config.ts index 731726c3183..d3080a5d12b 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -86,7 +86,7 @@ function iifeBuildOpts({sourceFileName, write}: {sourceFileName: string, write?: } // Build iife.js as a blocking IIFE bundle. In dev mode, serves it from memory -// and rebuilds on file changes. In prod mode, writes to disk during closeBundle. +// and rebuilds on file changes. In prod mode, writes to disk and updates "manifest.json". function iifePlugin(sourceFileName: string): Plugin { let iifeCode = '', iifeMap = ''; const iifeModules = new Set(); @@ -143,7 +143,7 @@ function iifePlugin(sourceFileName: string): Plugin { } }); }, - async closeBundle() { + async writeBundle() { for (const file of globSync(`js/${sourceBaseName}.*.js*`, {cwd: outDir})) unlinkSync(join(outDir, file)); const result = await build(iifeBuildOpts({sourceFileName})); @@ -152,15 +152,9 @@ function iifePlugin(sourceFileName: string): Plugin { if (!entry) throw new Error('IIFE build produced no output'); const manifestPath = join(outDir, '.vite', 'manifest.json'); - try { - const manifestData = JSON.parse(readFileSync(manifestPath, 'utf8')); - manifestData[`web_src/js/${sourceFileName}`] = {file: entry.fileName, name: sourceBaseName, isEntry: true}; - writeFileSync(manifestPath, JSON.stringify(manifestData, null, 2)); - } catch { - // FIXME: if it throws error here, the real Vite compilation error will be hidden, and makes the debug very difficult - // Need to find a correct way to handle errors. - console.error(`Failed to update manifest for ${sourceFileName}`); - } + const manifestData = JSON.parse(readFileSync(manifestPath, 'utf8')); + manifestData[`web_src/js/${sourceFileName}`] = {file: entry.fileName, name: sourceBaseName, isEntry: true}; + writeFileSync(manifestPath, JSON.stringify(manifestData, null, 2)); }, }; } From f6960096f36d40218b0e0a212f6ed99c7b3f20e3 Mon Sep 17 00:00:00 2001 From: silverwind Date: Mon, 20 Apr 2026 09:22:05 +0200 Subject: [PATCH 02/66] Enable strict TypeScript, add `errorMessage` helper (#37292) Enable full TypeScript `strict` mode and fix issues discovered during this refactor. Introduced a `errorMessage` helper function to cleanly extract a error messages from the `unknown` type. Signed-off-by: silverwind Co-authored-by: Claude (claude-opus-4-7) Co-authored-by: wxiaoguang --- tsconfig.json | 2 -- web_src/js/components/RepoCodeFrequency.vue | 3 ++- web_src/js/components/RepoContributors.vue | 3 ++- web_src/js/components/RepoRecentCommits.vue | 3 ++- web_src/js/features/admin/config.ts | 3 ++- web_src/js/features/citation.ts | 3 ++- web_src/js/features/common-fetch-action.ts | 9 ++++---- .../js/features/comp/ComboMarkdownEditor.ts | 22 +++++++++---------- web_src/js/features/dropzone.ts | 3 ++- web_src/js/features/file-view.ts | 3 ++- web_src/js/features/imagediff.ts | 4 ++-- web_src/js/features/repo-common.ts | 3 ++- web_src/js/features/repo-diff.ts | 3 ++- web_src/js/features/repo-issue-edit.ts | 3 ++- web_src/js/features/repo-issue-list.ts | 5 ++++- .../features/repo-issue-sidebar-combolist.ts | 5 +++-- web_src/js/features/repo-issue.ts | 3 ++- web_src/js/features/repo-settings-branches.ts | 4 ++-- web_src/js/features/user-auth-webauthn.ts | 9 ++++---- web_src/js/markup/common.ts | 6 +++-- web_src/js/markup/render-iframe.ts | 3 ++- web_src/js/modules/errors.ts | 4 ++++ web_src/js/utils/match.ts | 3 ++- web_src/js/webcomponents/overflow-menu.ts | 16 +++++++------- 24 files changed, 74 insertions(+), 51 deletions(-) diff --git a/tsconfig.json b/tsconfig.json index 92cf43fbf82..bcecb172172 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -35,8 +35,6 @@ "skipLibCheck": true, "sourceMap": true, "strict": true, - "strictPropertyInitialization": false, - "useUnknownInCatchVariables": false, "stripInternal": true, "verbatimModuleSyntax": true, "types": [ diff --git a/web_src/js/components/RepoCodeFrequency.vue b/web_src/js/components/RepoCodeFrequency.vue index 97ce07cc350..146a65995a6 100644 --- a/web_src/js/components/RepoCodeFrequency.vue +++ b/web_src/js/components/RepoCodeFrequency.vue @@ -21,6 +21,7 @@ import { type DayDataObject, } from '../utils/time.ts'; import {chartJsColors} from '../utils/color.ts'; +import {errorMessage} from '../modules/errors.ts'; import {sleep} from '../utils.ts'; import 'chartjs-adapter-dayjs-4/dist/chartjs-adapter-dayjs-4.esm'; import {onMounted, shallowRef} from 'vue'; @@ -78,7 +79,7 @@ async function fetchGraphData() { errorText.value = response.statusText; } } catch (err) { - errorText.value = err.message; + errorText.value = errorMessage(err); } finally { isLoading.value = false; } diff --git a/web_src/js/components/RepoContributors.vue b/web_src/js/components/RepoContributors.vue index db2f84ecde4..3fd34081e04 100644 --- a/web_src/js/components/RepoContributors.vue +++ b/web_src/js/components/RepoContributors.vue @@ -24,6 +24,7 @@ import { fillEmptyStartDaysWithZeroes, } from '../utils/time.ts'; import {chartJsColors} from '../utils/color.ts'; +import {errorMessage} from '../modules/errors.ts'; import {sleep} from '../utils.ts'; import 'chartjs-adapter-dayjs-4/dist/chartjs-adapter-dayjs-4.esm'; import {fomanticQuery} from '../modules/fomantic/base.ts'; @@ -166,7 +167,7 @@ export default defineComponent({ this.errorText = response.statusText; } } catch (err) { - this.errorText = err.message; + this.errorText = errorMessage(err); } finally { this.isLoading = false; } diff --git a/web_src/js/components/RepoRecentCommits.vue b/web_src/js/components/RepoRecentCommits.vue index 7eb5c7f289b..b58e84e55d6 100644 --- a/web_src/js/components/RepoRecentCommits.vue +++ b/web_src/js/components/RepoRecentCommits.vue @@ -20,6 +20,7 @@ import { type DayDataObject, } from '../utils/time.ts'; import {chartJsColors} from '../utils/color.ts'; +import {errorMessage} from '../modules/errors.ts'; import {sleep} from '../utils.ts'; import 'chartjs-adapter-dayjs-4/dist/chartjs-adapter-dayjs-4.esm'; import {onMounted, ref, shallowRef} from 'vue'; @@ -74,7 +75,7 @@ async function fetchGraphData() { errorText.value = response.statusText; } } catch (err) { - errorText.value = err.message; + errorText.value = errorMessage(err); } finally { isLoading.value = false; } diff --git a/web_src/js/features/admin/config.ts b/web_src/js/features/admin/config.ts index 5df81412f9b..96c7dcf84bb 100644 --- a/web_src/js/features/admin/config.ts +++ b/web_src/js/features/admin/config.ts @@ -2,6 +2,7 @@ import {showTemporaryTooltip} from '../../modules/tippy.ts'; import {POST} from '../../modules/fetch.ts'; import {registerGlobalInitFunc} from '../../modules/observer.ts'; import {queryElems} from '../../utils/dom.ts'; +import {errorMessage} from '../../modules/errors.ts'; import {submitFormFetchAction} from '../common-fetch-action.ts'; const {appSubUrl} = window.config; @@ -26,7 +27,7 @@ function initSystemConfigAutoCheckbox(el: HTMLInputElement) { const json: Record = await resp.json(); if (json.errorMessage) throw new Error(json.errorMessage); } catch (ex) { - showTemporaryTooltip(el, ex.toString()); + showTemporaryTooltip(el, errorMessage(ex)); el.checked = !el.checked; } }); diff --git a/web_src/js/features/citation.ts b/web_src/js/features/citation.ts index 1abd960366e..80eaabcc585 100644 --- a/web_src/js/features/citation.ts +++ b/web_src/js/features/citation.ts @@ -1,4 +1,5 @@ import {getCurrentLocale} from '../utils.ts'; +import {errorMessage} from '../modules/errors.ts'; import {fomanticQuery} from '../modules/fomantic/base.ts'; import {localUserSettings} from '../modules/user-settings.ts'; @@ -46,7 +47,7 @@ export async function initCitationFileCopyContent() { try { await initInputCitationValue(citationCopyApa, citationCopyBibtex); } catch (e) { - console.error(`initCitationFileCopyContent error: ${e}`, e); + console.error(`initCitationFileCopyContent error: ${errorMessage(e)}`, e); return; } updateUi(); diff --git a/web_src/js/features/common-fetch-action.ts b/web_src/js/features/common-fetch-action.ts index 24f4ad2e02f..595bb96c854 100644 --- a/web_src/js/features/common-fetch-action.ts +++ b/web_src/js/features/common-fetch-action.ts @@ -1,6 +1,7 @@ import {GET, request} from '../modules/fetch.ts'; import {hideToastsAll, showErrorToast} from '../modules/toast.ts'; import {addDelegatedEventListener, createElementFromHTML} from '../utils/dom.ts'; +import {errorMessage} from '../modules/errors.ts'; import {confirmModal, createConfirmModal} from './comp/ConfirmModal.ts'; import {ignoreAreYouSure} from '../vendor/jquery.are-you-sure.ts'; import {registerGlobalSelectorFunc} from '../modules/observer.ts'; @@ -134,10 +135,10 @@ async function performActionRequest(el: HTMLElement, opt: FetchActionOpts) { return; } await handleFetchActionError(resp); - } catch (e) { - if (e.name !== 'AbortError') { - console.error(`Fetch action request error:`, e); - showErrorToast(`Error: ${e.message ?? e}`); + } catch (err) { + if ((err as Error).name !== 'AbortError') { + console.error(`Fetch action request error:`, err); + showErrorToast(`Error: ${errorMessage(err)}`); } } finally { toggleLoadingIndicator(el, opt, false); diff --git a/web_src/js/features/comp/ComboMarkdownEditor.ts b/web_src/js/features/comp/ComboMarkdownEditor.ts index f16a71a6c57..da7fcd85861 100644 --- a/web_src/js/features/comp/ComboMarkdownEditor.ts +++ b/web_src/js/features/comp/ComboMarkdownEditor.ts @@ -71,26 +71,26 @@ export class ComboMarkdownEditor { options: ComboMarkdownEditorOptions; - tabEditor: HTMLElement; - tabPreviewer: HTMLElement; + tabEditor?: HTMLElement; + tabPreviewer?: HTMLElement; - supportEasyMDE: boolean; + supportEasyMDE!: boolean; easyMDE: any; easyMDEToolbarActions: any; easyMDEToolbarDefault: any; - textarea: ComboMarkdownEditorTextarea; - textareaMarkdownToolbar: HTMLElement; + textarea!: ComboMarkdownEditorTextarea; + textareaMarkdownToolbar!: HTMLElement; textareaAutosize: any; - buttonMonospace: HTMLButtonElement; + buttonMonospace!: HTMLButtonElement; - dropzone: HTMLElement | null; + dropzone: HTMLElement | null = null; attachedDropzoneInst: any; - previewMode: string; - previewUrl: string; - previewContext: string; + previewMode!: string; + previewUrl!: string; + previewContext!: string; constructor(container: ComboMarkdownEditorContainer, options:ComboMarkdownEditorOptions = {}) { if (container._giteaComboMarkdownEditor) throw new Error('ComboMarkdownEditor already initialized'); @@ -291,7 +291,7 @@ export class ComboMarkdownEditor { } switchTabToEditor() { - this.tabEditor.click(); + this.tabEditor!.click(); // when this function is called, the tab must exist } prepareEasyMDEToolbarActions() { diff --git a/web_src/js/features/dropzone.ts b/web_src/js/features/dropzone.ts index 6ff0cc5a3ae..84076dc93b8 100644 --- a/web_src/js/features/dropzone.ts +++ b/web_src/js/features/dropzone.ts @@ -5,6 +5,7 @@ import {showTemporaryTooltip} from '../modules/tippy.ts'; import {GET, POST} from '../modules/fetch.ts'; import {showErrorToast} from '../modules/toast.ts'; import {createElementFromHTML, createElementFromAttrs} from '../utils/dom.ts'; +import {errorMessage} from '../modules/errors.ts'; import {isImageFile, isVideoFile} from '../utils.ts'; import type Dropzone from '@deltablot/dropzone'; @@ -149,7 +150,7 @@ export async function initDropzone(dropzoneEl: HTMLElement) { } catch (error) { // TODO: if listing the existing attachments failed, it should stop from operating the content or attachments, // otherwise the attachments might be lost. - showErrorToast(`Failed to load attachments: ${error}`); + showErrorToast(`Failed to load attachments: ${errorMessage(error)}`); console.error(error); } }); diff --git a/web_src/js/features/file-view.ts b/web_src/js/features/file-view.ts index b9a5dd5094f..eed4ba0cd31 100644 --- a/web_src/js/features/file-view.ts +++ b/web_src/js/features/file-view.ts @@ -2,6 +2,7 @@ import type {InplaceRenderPlugin} from '../render/plugin.ts'; import {newInplacePluginPdfViewer} from '../render/plugins/inplace-pdf-viewer.ts'; import {registerGlobalInitFunc} from '../modules/observer.ts'; import {createElementFromHTML} from '../utils/dom.ts'; +import {errorMessage} from '../modules/errors.ts'; import {html} from '../utils/html.ts'; import {basename} from '../utils.ts'; @@ -30,7 +31,7 @@ async function renderRawFileToContainer(container: HTMLElement, rawFileLink: str rendered = true; } } catch (e) { - errorMsg = `${e}`; + errorMsg = errorMessage(e); } finally { container.classList.remove('is-loading'); } diff --git a/web_src/js/features/imagediff.ts b/web_src/js/features/imagediff.ts index 1e89aa8b6ec..5351d35ffe0 100644 --- a/web_src/js/features/imagediff.ts +++ b/web_src/js/features/imagediff.ts @@ -94,8 +94,8 @@ function createContext(imageAfter: HTMLImageElement, imageBefore: HTMLImageEleme } class ImageDiff { - containerEl: HTMLElement; - diffContainerWidth: number; + containerEl!: HTMLElement; + diffContainerWidth!: number; async init(containerEl: HTMLElement) { this.containerEl = containerEl; diff --git a/web_src/js/features/repo-common.ts b/web_src/js/features/repo-common.ts index e8fb257c185..65b89cf2612 100644 --- a/web_src/js/features/repo-common.ts +++ b/web_src/js/features/repo-common.ts @@ -1,4 +1,5 @@ import {queryElems} from '../utils/dom.ts'; +import {errorMessage} from '../modules/errors.ts'; import {POST} from '../modules/fetch.ts'; import {showErrorToast} from '../modules/toast.ts'; import {sleep} from '../utils.ts'; @@ -26,7 +27,7 @@ async function onDownloadArchive(e: Event) { window.location.href = el.href; // the archive is ready, start real downloading } catch (e) { console.error(e); - showErrorToast(`Failed to download the archive: ${e}`, {duration: 2500}); + showErrorToast(`Failed to download the archive: ${errorMessage(e)}`, {duration: 2500}); } finally { targetLoading.classList.remove('is-loading', 'loading-icon-2px'); } diff --git a/web_src/js/features/repo-diff.ts b/web_src/js/features/repo-diff.ts index 500c86fec6a..f866df3526d 100644 --- a/web_src/js/features/repo-diff.ts +++ b/web_src/js/features/repo-diff.ts @@ -6,6 +6,7 @@ import {initViewedCheckboxListenerFor, initExpandAndCollapseFilesButton} from '. import {initImageDiff} from './imagediff.ts'; import {showErrorToast} from '../modules/toast.ts'; import {queryElemSiblings, hideElem, showElem, animateOnce, addDelegatedEventListener, createElementFromHTML, queryElems} from '../utils/dom.ts'; +import {errorMessage} from '../modules/errors.ts'; import {POST, GET} from '../modules/fetch.ts'; import {createTippy} from '../modules/tippy.ts'; import {invertFileFolding} from './file-fold.ts'; @@ -85,7 +86,7 @@ function initRepoDiffConversationForm() { } } catch (error) { console.error('Error:', error); - showErrorToast(`Submit form failed: ${error}`); + showErrorToast(`Submit form failed: ${errorMessage(error)}`); } finally { form?.classList.remove('is-loading'); } diff --git a/web_src/js/features/repo-issue-edit.ts b/web_src/js/features/repo-issue-edit.ts index 4a112368f46..198951d41f4 100644 --- a/web_src/js/features/repo-issue-edit.ts +++ b/web_src/js/features/repo-issue-edit.ts @@ -3,6 +3,7 @@ import {getComboMarkdownEditor, initComboMarkdownEditor, ComboMarkdownEditor} fr import {POST} from '../modules/fetch.ts'; import {showErrorToast} from '../modules/toast.ts'; import {hideElem, querySingleVisibleElem, showElem} from '../utils/dom.ts'; +import {errorMessage} from '../modules/errors.ts'; import {triggerUploadStateChanged} from './comp/EditorUpload.ts'; import {convertHtmlToMarkdown} from '../markup/html2markdown.ts'; import {applyAreYouSure, reinitializeAreYouSure} from '../vendor/jquery.are-you-sure.ts'; @@ -73,7 +74,7 @@ async function tryOnEditContent(e: Event) { } comboMarkdownEditor.dropzoneSubmitReload(); } catch (error) { - showErrorToast(`Failed to save the content: ${error}`); + showErrorToast(`Failed to save the content: ${errorMessage(error)}`); console.error(error); } finally { renderContent.classList.remove('is-loading'); diff --git a/web_src/js/features/repo-issue-list.ts b/web_src/js/features/repo-issue-list.ts index c0cd3c7f22c..046c1beee56 100644 --- a/web_src/js/features/repo-issue-list.ts +++ b/web_src/js/features/repo-issue-list.ts @@ -2,6 +2,7 @@ import {updateIssuesMeta} from './repo-common.ts'; import {toggleElem, queryElems, isElemVisible} from '../utils/dom.ts'; import {html, htmlRaw} from '../utils/html.ts'; import {confirmModal} from './comp/ConfirmModal.ts'; +import {errorMessage} from '../modules/errors.ts'; import {showErrorToast} from '../modules/toast.ts'; import {createSortable} from '../modules/sortable.ts'; import {DELETE, POST} from '../modules/fetch.ts'; @@ -87,7 +88,9 @@ function initRepoIssueListCheckboxes() { await updateIssuesMeta(url, action, issueIDs, elementId); window.location.reload(); } catch (err) { - showErrorToast(err.responseJSON?.error ?? err.message); + // FIXME: this logic (including updateIssuesMeta) is not right, should refactor to our JSONError framework + const e = err as {responseJSON?: {error: string}}; + showErrorToast(e.responseJSON?.error ?? errorMessage(err)); } }, )); diff --git a/web_src/js/features/repo-issue-sidebar-combolist.ts b/web_src/js/features/repo-issue-sidebar-combolist.ts index ab29a18f923..0cea54bbbdb 100644 --- a/web_src/js/features/repo-issue-sidebar-combolist.ts +++ b/web_src/js/features/repo-issue-sidebar-combolist.ts @@ -2,6 +2,7 @@ import {fomanticQuery} from '../modules/fomantic/base.ts'; import {GET, POST} from '../modules/fetch.ts'; import {showErrorToast} from '../modules/toast.ts'; import {addDelegatedEventListener, queryElemChildren, queryElems, toggleElem} from '../utils/dom.ts'; +import {errorMessage} from '../modules/errors.ts'; import {parseDom} from '../utils.ts'; export function syncIssueMainContentTimelineItems(oldMainContent: Element, newMainContent: Element) { @@ -42,7 +43,7 @@ export class IssueSidebarComboList { elDropdown: HTMLElement; elList: HTMLElement | null; elComboValue: HTMLInputElement; - initialValues: string[]; + initialValues: string[] = []; container: HTMLElement; elIssueMainContent: HTMLElement; @@ -129,7 +130,7 @@ export class IssueSidebarComboList { await this.reloadPagePartially(); } catch (e) { console.error('Failed to update to backend', e); - showErrorToast(`Failed to update to backend: ${e}`); + showErrorToast(`Failed to update to backend: ${errorMessage(e)}`); } finally { this.elIssueSidebar.classList.remove('is-loading'); } diff --git a/web_src/js/features/repo-issue.ts b/web_src/js/features/repo-issue.ts index 03b0c93d85f..7322432fe87 100644 --- a/web_src/js/features/repo-issue.ts +++ b/web_src/js/features/repo-issue.ts @@ -1,3 +1,4 @@ +import {errorMessage} from '../modules/errors.ts'; import {htmlEscape} from '../utils/html.ts'; import {createTippy} from '../modules/tippy.ts'; import { @@ -425,7 +426,7 @@ export function initRepoIssueTitleEdit() { window.location.reload(); } catch (error) { console.error(error); - showErrorToast(error.message); + showErrorToast(errorMessage(error)); } }); } diff --git a/web_src/js/features/repo-settings-branches.ts b/web_src/js/features/repo-settings-branches.ts index 858140adc2f..4e7e74cbc77 100644 --- a/web_src/js/features/repo-settings-branches.ts +++ b/web_src/js/features/repo-settings-branches.ts @@ -2,6 +2,7 @@ import {createSortable} from '../modules/sortable.ts'; import {POST} from '../modules/fetch.ts'; import {showErrorToast} from '../modules/toast.ts'; import {queryElemChildren} from '../utils/dom.ts'; +import {errorMessage} from '../modules/errors.ts'; export function initRepoSettingsBranchesDrag() { const protectedBranchesList = document.querySelector('#protected-branches-list'); @@ -23,8 +24,7 @@ export function initRepoSettingsBranchesDrag() { }, }); } catch (err) { - const errorMessage = String(err); - showErrorToast(`Failed to update branch protection rule priority:, error: ${errorMessage}`); + showErrorToast(`Failed to update branch protection rule priority: ${errorMessage(err)}`); } })(); }, diff --git a/web_src/js/features/user-auth-webauthn.ts b/web_src/js/features/user-auth-webauthn.ts index 774d41dce0f..f30f4a7f5f4 100644 --- a/web_src/js/features/user-auth-webauthn.ts +++ b/web_src/js/features/user-auth-webauthn.ts @@ -1,5 +1,6 @@ import {encodeURLEncodedBase64, decodeURLEncodedBase64} from '../utils.ts'; import {hideElem, showElem} from '../utils/dom.ts'; +import {errorMessage} from '../modules/errors.ts'; import {GET, POST} from '../modules/fetch.ts'; const {appSubUrl} = window.config; @@ -80,7 +81,7 @@ async function loginPasskey() { window.location.href = reply?.redirect ?? `${appSubUrl}/`; } catch (err) { - webAuthnError('general', err.message); + webAuthnError('general', errorMessage(err)); } } @@ -104,7 +105,7 @@ async function login2FA() { await verifyAssertion(credential); } catch (err) { if (!options.publicKey.extensions?.appid) { - webAuthnError('general', err.message); + webAuthnError('general', errorMessage(err)); return; } delete options.publicKey.extensions.appid; @@ -114,7 +115,7 @@ async function login2FA() { }); await verifyAssertion(credential); } catch (err) { - webAuthnError('general', err.message); + webAuthnError('general', errorMessage(err)); } } } @@ -262,6 +263,6 @@ async function webAuthnRegisterRequest() { }); await webauthnRegistered(credential); } catch (err) { - webAuthnError('unknown', err); + webAuthnError('unknown', errorMessage(err)); } } diff --git a/web_src/js/markup/common.ts b/web_src/js/markup/common.ts index e826c8fd863..096d8ddf667 100644 --- a/web_src/js/markup/common.ts +++ b/web_src/js/markup/common.ts @@ -1,8 +1,10 @@ -export function displayError(el: Element, err: Error): void { +import {errorMessage} from '../modules/errors.ts'; + +export function displayError(el: Element, err: unknown): void { el.classList.remove('is-loading'); const errorNode = document.createElement('pre'); errorNode.setAttribute('class', 'ui message error markup-block-error'); - errorNode.textContent = err.message || String(err); + errorNode.textContent = errorMessage(err); el.before(errorNode); el.setAttribute('data-render-done', 'true'); } diff --git a/web_src/js/markup/render-iframe.ts b/web_src/js/markup/render-iframe.ts index 2b1b06e5c0b..f05523943a8 100644 --- a/web_src/js/markup/render-iframe.ts +++ b/web_src/js/markup/render-iframe.ts @@ -1,4 +1,5 @@ import {generateElemId} from '../utils/dom.ts'; +import {errorMessage} from '../modules/errors.ts'; import {isDarkTheme} from '../utils.ts'; import {GET} from '../modules/fetch.ts'; @@ -11,7 +12,7 @@ function safeRenderIframeLink(link: any): string | null { } return url.href; } catch (e) { - console.error(`Failed to parse link: ${link}, error: ${e}`); + console.error(`Failed to parse link: ${link}, error: ${errorMessage(e)}`); return null; } } diff --git a/web_src/js/modules/errors.ts b/web_src/js/modules/errors.ts index ddda0ebe42b..276b498ead7 100644 --- a/web_src/js/modules/errors.ts +++ b/web_src/js/modules/errors.ts @@ -2,6 +2,10 @@ import {html} from '../utils/html.ts'; import type {Intent} from '../types.ts'; +export function errorMessage(err: unknown): string { + return (err as Error)?.message || String(err); +} + export function showGlobalErrorMessage(msg: string, msgType: Intent = 'error') { const msgContainer = document.querySelector('.page-content') ?? document.body; if (!msgContainer) { diff --git a/web_src/js/utils/match.ts b/web_src/js/utils/match.ts index f364481f468..41333d9fa46 100644 --- a/web_src/js/utils/match.ts +++ b/web_src/js/utils/match.ts @@ -2,6 +2,7 @@ import emojis from '../../../assets/emoji.json' with {type: 'json'}; import {GET} from '../modules/fetch.ts'; import {showErrorToast} from '../modules/toast.ts'; import {parseIssuePageInfo} from '../utils.ts'; +import {errorMessage} from '../modules/errors.ts'; import type {Issue, Mention} from '../types.ts'; const maxMatches = 6; @@ -47,7 +48,7 @@ export function fetchMentions(mentionsUrl: string): Promise { if (!res.ok) throw new Error(res.statusText); return await res.json() as Mention[]; } catch (e) { - showErrorToast(`Failed to load mentions: ${e}`); + showErrorToast(`Failed to load mentions: ${errorMessage(e)}`); return []; } })(); diff --git a/web_src/js/webcomponents/overflow-menu.ts b/web_src/js/webcomponents/overflow-menu.ts index 879ce36e6e3..b20d11e2433 100644 --- a/web_src/js/webcomponents/overflow-menu.ts +++ b/web_src/js/webcomponents/overflow-menu.ts @@ -3,13 +3,13 @@ import {addDelegatedEventListener, generateElemId, isDocumentFragmentOrElementNo import octiconKebabHorizontal from '../../../public/assets/img/svg/octicon-kebab-horizontal.svg'; window.customElements.define('overflow-menu', class extends HTMLElement { - popup: HTMLDivElement; - overflowItems: Array; - button: HTMLButtonElement | null; - menuItemsEl: HTMLElement; - resizeObserver: ResizeObserver; - mutationObserver: MutationObserver; - lastWidth: number; + popup!: HTMLDivElement; + overflowItems: Array = []; + button: HTMLButtonElement | null = null; + menuItemsEl!: HTMLElement; + resizeObserver!: ResizeObserver; + mutationObserver!: MutationObserver; + lastWidth!: number; updateButtonActivationState() { if (!this.button || !this.popup) return; @@ -100,7 +100,7 @@ window.customElements.define('overflow-menu', class extends HTMLElement { const itemOverFlowMenuButton = this.querySelector('.overflow-menu-button'); // move items in popup back into the menu items for subsequent measurement - for (const item of this.overflowItems || []) { + for (const item of this.overflowItems) { if (!itemFlexSpace || item.getAttribute('data-after-flex-space')) { this.menuItemsEl.append(item); } else { From aba87285f020e9982d7a207c7093fd95ed2d1b85 Mon Sep 17 00:00:00 2001 From: silverwind Date: Mon, 20 Apr 2026 09:52:48 +0200 Subject: [PATCH 03/66] Remove dead code identified by `deadcode` tool (#37271) Ran [`deadcode`](https://pkg.go.dev/golang.org/x/tools/cmd/deadcode) (`-test ./...`) to find functions, methods and error types unreachable from any call path (including tests), and removed the truly-dead ones. Co-authored-by: Claude (Opus 4.7) --- models/actions/run_list.go | 19 ---------- models/actions/schedule_list.go | 49 -------------------------- models/activities/action_list.go | 6 ---- models/asymkey/error.go | 22 ------------ models/asymkey/ssh_key_deploy.go | 8 ----- models/auth/webauthn.go | 10 ------ models/git/branch_list.go | 19 ---------- models/issues/dependency.go | 6 ---- models/issues/issue.go | 15 -------- models/issues/issue_pin.go | 21 ----------- models/issues/issue_update.go | 8 +---- models/issues/pull.go | 2 +- models/organization/team_unit.go | 16 --------- models/organization/team_user.go | 8 ----- models/project/column.go | 14 -------- models/repo/topic.go | 6 ---- models/system/notice.go | 13 ------- models/user/badge.go | 19 ---------- models/user/email_address.go | 5 --- models/user/error.go | 21 ----------- models/user/external_login_user.go | 12 ------- models/user/setting.go | 6 ---- modules/actions/jobparser/jobparser.go | 6 ---- modules/eventsource/event.go | 7 ---- modules/gitrepo/commit.go | 17 --------- modules/gitrepo/config.go | 10 ------ modules/hostmatcher/hostmatcher.go | 5 --- modules/markup/markdown/markdown.go | 4 --- modules/storage/storage.go | 19 ---------- modules/web/middleware/locale.go | 6 ---- routers/api/v1/user/gpg_key.go | 8 +---- routers/web/auth/auth.go | 9 ----- routers/web/auth/linkaccount.go | 10 ------ routers/web/home.go | 6 ---- routers/web/org/projects.go | 8 ----- routers/web/shared/actions/runners.go | 4 --- services/context/user.go | 21 ----------- services/convert/secret.go | 18 ---------- services/forms/repo_form.go | 11 ------ services/repository/files/content.go | 5 --- services/repository/files/tree.go | 6 ---- 41 files changed, 3 insertions(+), 482 deletions(-) delete mode 100644 services/convert/secret.go diff --git a/models/actions/run_list.go b/models/actions/run_list.go index 2628c4712f5..8b8c132a482 100644 --- a/models/actions/run_list.go +++ b/models/actions/run_list.go @@ -7,7 +7,6 @@ import ( "context" "code.gitea.io/gitea/models/db" - repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/container" "code.gitea.io/gitea/modules/translation" @@ -25,12 +24,6 @@ func (runs RunList) GetUserIDs() []int64 { }) } -func (runs RunList) GetRepoIDs() []int64 { - return container.FilterSlice(runs, func(run *ActionRun) (int64, bool) { - return run.RepoID, true - }) -} - func (runs RunList) LoadTriggerUser(ctx context.Context) error { userIDs := runs.GetUserIDs() users := make(map[int64]*user_model.User, len(userIDs)) @@ -50,18 +43,6 @@ func (runs RunList) LoadTriggerUser(ctx context.Context) error { return nil } -func (runs RunList) LoadRepos(ctx context.Context) error { - repoIDs := runs.GetRepoIDs() - repos, err := repo_model.GetRepositoriesMapByIDs(ctx, repoIDs) - if err != nil { - return err - } - for _, run := range runs { - run.Repo = repos[run.RepoID] - } - return nil -} - type FindRunOptions struct { db.ListOptions RepoID int64 diff --git a/models/actions/schedule_list.go b/models/actions/schedule_list.go index 5361b94801a..6b5cae94fe9 100644 --- a/models/actions/schedule_list.go +++ b/models/actions/schedule_list.go @@ -4,62 +4,13 @@ package actions import ( - "context" - "code.gitea.io/gitea/models/db" - repo_model "code.gitea.io/gitea/models/repo" - user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/container" "xorm.io/builder" ) type ScheduleList []*ActionSchedule -// GetUserIDs returns a slice of user's id -func (schedules ScheduleList) GetUserIDs() []int64 { - return container.FilterSlice(schedules, func(schedule *ActionSchedule) (int64, bool) { - return schedule.TriggerUserID, true - }) -} - -func (schedules ScheduleList) GetRepoIDs() []int64 { - return container.FilterSlice(schedules, func(schedule *ActionSchedule) (int64, bool) { - return schedule.RepoID, true - }) -} - -func (schedules ScheduleList) LoadTriggerUser(ctx context.Context) error { - userIDs := schedules.GetUserIDs() - users := make(map[int64]*user_model.User, len(userIDs)) - if err := db.GetEngine(ctx).In("id", userIDs).Find(&users); err != nil { - return err - } - for _, schedule := range schedules { - if schedule.TriggerUserID == user_model.ActionsUserID { - schedule.TriggerUser = user_model.NewActionsUser() - } else { - schedule.TriggerUser = users[schedule.TriggerUserID] - if schedule.TriggerUser == nil { - schedule.TriggerUser = user_model.NewGhostUser() - } - } - } - return nil -} - -func (schedules ScheduleList) LoadRepos(ctx context.Context) error { - repoIDs := schedules.GetRepoIDs() - repos, err := repo_model.GetRepositoriesMapByIDs(ctx, repoIDs) - if err != nil { - return err - } - for _, schedule := range schedules { - schedule.Repo = repos[schedule.RepoID] - } - return nil -} - type FindScheduleOptions struct { db.ListOptions RepoID int64 diff --git a/models/activities/action_list.go b/models/activities/action_list.go index 29ff2fdf7a2..5b07a8e080a 100644 --- a/models/activities/action_list.go +++ b/models/activities/action_list.go @@ -282,9 +282,3 @@ func GetFeeds(ctx context.Context, opts GetFeedsOptions) (ActionList, int64, err return actions, count, nil } - -func CountUserFeeds(ctx context.Context, userID int64) (int64, error) { - return db.GetEngine(ctx).Where("user_id = ?", userID). - And("is_deleted = ?", false). - Count(&Action{}) -} diff --git a/models/asymkey/error.go b/models/asymkey/error.go index b7656245791..5df7beb8cd7 100644 --- a/models/asymkey/error.go +++ b/models/asymkey/error.go @@ -192,28 +192,6 @@ func (err ErrGPGKeyIDAlreadyUsed) Unwrap() error { return util.ErrAlreadyExist } -// ErrGPGKeyAccessDenied represents a "GPGKeyAccessDenied" kind of Error. -type ErrGPGKeyAccessDenied struct { - UserID int64 - KeyID int64 -} - -// IsErrGPGKeyAccessDenied checks if an error is a ErrGPGKeyAccessDenied. -func IsErrGPGKeyAccessDenied(err error) bool { - _, ok := err.(ErrGPGKeyAccessDenied) - return ok -} - -// Error pretty-prints an error of type ErrGPGKeyAccessDenied. -func (err ErrGPGKeyAccessDenied) Error() string { - return fmt.Sprintf("user does not have access to the key [user_id: %d, key_id: %d]", - err.UserID, err.KeyID) -} - -func (err ErrGPGKeyAccessDenied) Unwrap() error { - return util.ErrPermissionDenied -} - // ErrKeyAccessDenied represents a "KeyAccessDenied" kind of error. type ErrKeyAccessDenied struct { UserID int64 diff --git a/models/asymkey/ssh_key_deploy.go b/models/asymkey/ssh_key_deploy.go index 4ab84eabcf6..ea3d93e8c81 100644 --- a/models/asymkey/ssh_key_deploy.go +++ b/models/asymkey/ssh_key_deploy.go @@ -105,14 +105,6 @@ func addDeployKey(ctx context.Context, keyID, repoID int64, name, fingerprint st return key, db.Insert(ctx, key) } -// HasDeployKey returns true if public key is a deploy key of given repository. -func HasDeployKey(ctx context.Context, keyID, repoID int64) bool { - has, _ := db.GetEngine(ctx). - Where("key_id = ? AND repo_id = ?", keyID, repoID). - Get(new(DeployKey)) - return has -} - // AddDeployKey add new deploy key to database and authorized_keys file. func AddDeployKey(ctx context.Context, repoID int64, name, content string, readOnly bool) (*DeployKey, error) { fingerprint, err := CalcFingerprint(content) diff --git a/models/auth/webauthn.go b/models/auth/webauthn.go index 6d8b5429579..7bd79ed3f52 100644 --- a/models/auth/webauthn.go +++ b/models/auth/webauthn.go @@ -200,13 +200,3 @@ func DeleteCredential(ctx context.Context, id, userID int64) (bool, error) { had, err := db.GetEngine(ctx).ID(id).Where("user_id = ?", userID).Delete(&WebAuthnCredential{}) return had > 0, err } - -// WebAuthnCredentials implements the webauthn.User interface -func WebAuthnCredentials(ctx context.Context, userID int64) ([]webauthn.Credential, error) { - dbCreds, err := GetWebAuthnCredentialsByUID(ctx, userID) - if err != nil { - return nil, err - } - - return dbCreds.ToCredentials(), nil -} diff --git a/models/git/branch_list.go b/models/git/branch_list.go index 25e84526d29..1445f3a5a02 100644 --- a/models/git/branch_list.go +++ b/models/git/branch_list.go @@ -7,7 +7,6 @@ import ( "context" "code.gitea.io/gitea/models/db" - repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/container" "code.gitea.io/gitea/modules/optional" @@ -60,24 +59,6 @@ func (branches BranchList) LoadPusher(ctx context.Context) error { return nil } -func (branches BranchList) LoadRepo(ctx context.Context) error { - ids := container.FilterSlice(branches, func(branch *Branch) (int64, bool) { - return branch.RepoID, branch.RepoID > 0 && branch.Repo == nil - }) - - reposMap := make(map[int64]*repo_model.Repository, len(ids)) - if err := db.GetEngine(ctx).In("id", ids).Find(&reposMap); err != nil { - return err - } - for _, branch := range branches { - if branch.RepoID <= 0 || branch.Repo != nil { - continue - } - branch.Repo = reposMap[branch.RepoID] - } - return nil -} - type FindBranchOptions struct { db.ListOptions RepoID int64 diff --git a/models/issues/dependency.go b/models/issues/dependency.go index 0eaa47e3593..db8054e1618 100644 --- a/models/issues/dependency.go +++ b/models/issues/dependency.go @@ -89,12 +89,6 @@ type ErrUnknownDependencyType struct { Type DependencyType } -// IsErrUnknownDependencyType checks if an error is ErrUnknownDependencyType -func IsErrUnknownDependencyType(err error) bool { - _, ok := err.(ErrUnknownDependencyType) - return ok -} - func (err ErrUnknownDependencyType) Error() string { return fmt.Sprintf("unknown dependency type [type: %d]", err.Type) } diff --git a/models/issues/issue.go b/models/issues/issue.go index 838d41a3005..ec58cd04f6e 100644 --- a/models/issues/issue.go +++ b/models/issues/issue.go @@ -48,21 +48,6 @@ func (err ErrIssueNotExist) Unwrap() error { return util.ErrNotExist } -// ErrNewIssueInsert is used when the INSERT statement in newIssue fails -type ErrNewIssueInsert struct { - OriginalError error -} - -// IsErrNewIssueInsert checks if an error is a ErrNewIssueInsert. -func IsErrNewIssueInsert(err error) bool { - _, ok := err.(ErrNewIssueInsert) - return ok -} - -func (err ErrNewIssueInsert) Error() string { - return err.OriginalError.Error() -} - var ErrIssueAlreadyChanged = util.NewInvalidArgumentErrorf("the issue is already changed") // Issue represents an issue or pull request of repository. diff --git a/models/issues/issue_pin.go b/models/issues/issue_pin.go index ae6195b05dd..753c96ed180 100644 --- a/models/issues/issue_pin.go +++ b/models/issues/issue_pin.go @@ -165,27 +165,6 @@ func MovePin(ctx context.Context, issue *Issue, newPosition int) error { }) } -func GetPinnedIssueIDs(ctx context.Context, repoID int64, isPull bool) ([]int64, error) { - var issuePins []IssuePin - if err := db.GetEngine(ctx). - Table("issue_pin"). - Where("repo_id = ?", repoID). - And("is_pull = ?", isPull). - Find(&issuePins); err != nil { - return nil, err - } - - sort.Slice(issuePins, func(i, j int) bool { - return issuePins[i].PinOrder < issuePins[j].PinOrder - }) - - var ids []int64 - for _, pin := range issuePins { - ids = append(ids, pin.IssueID) - } - return ids, nil -} - func GetIssuePinsByRepoID(ctx context.Context, repoID int64, isPull bool) ([]*IssuePin, error) { var pins []*IssuePin if err := db.GetEngine(ctx).Where("repo_id = ? AND is_pull = ?", repoID, isPull).Find(&pins); err != nil { diff --git a/models/issues/issue_update.go b/models/issues/issue_update.go index 01a3eb9a2af..c58a2f319dd 100644 --- a/models/issues/issue_update.go +++ b/models/issues/issue_update.go @@ -93,12 +93,6 @@ type ErrIssueIsOpen struct { Index int64 } -// IsErrIssueIsOpen checks if an error is a ErrIssueIsOpen. -func IsErrIssueIsOpen(err error) bool { - _, ok := err.(ErrIssueIsOpen) - return ok -} - func (err ErrIssueIsOpen) Error() string { return fmt.Sprintf("%s [id: %d, repo_id: %d, index: %d] is already open", util.Iif(err.IsPull, "Pull Request", "Issue"), err.ID, err.RepoID, err.Index) } @@ -441,7 +435,7 @@ func NewIssue(ctx context.Context, repo *repo_model.Repository, issue *Issue, la LabelIDs: labelIDs, Attachments: uuids, }); err != nil { - if repo_model.IsErrUserDoesNotHaveAccessToRepo(err) || IsErrNewIssueInsert(err) { + if repo_model.IsErrUserDoesNotHaveAccessToRepo(err) { return err } return fmt.Errorf("newIssue: %w", err) diff --git a/models/issues/pull.go b/models/issues/pull.go index 1b883f29810..1fb42915f60 100644 --- a/models/issues/pull.go +++ b/models/issues/pull.go @@ -475,7 +475,7 @@ func NewPullRequest(ctx context.Context, repo *repo_model.Repository, issue *Iss LabelIDs: labelIDs, Attachments: uuids, }); err != nil { - if repo_model.IsErrUserDoesNotHaveAccessToRepo(err) || IsErrNewIssueInsert(err) { + if repo_model.IsErrUserDoesNotHaveAccessToRepo(err) { return err } return fmt.Errorf("newIssue: %w", err) diff --git a/models/organization/team_unit.go b/models/organization/team_unit.go index c6ec6b39b2c..b5237c2c587 100644 --- a/models/organization/team_unit.go +++ b/models/organization/team_unit.go @@ -28,19 +28,3 @@ func (t *TeamUnit) Unit() unit.Unit { func getUnitsByTeamID(ctx context.Context, teamID int64) (units []*TeamUnit, err error) { return units, db.GetEngine(ctx).Where("team_id = ?", teamID).Find(&units) } - -// UpdateTeamUnits updates a teams's units -func UpdateTeamUnits(ctx context.Context, team *Team, units []TeamUnit) (err error) { - return db.WithTx(ctx, func(ctx context.Context) error { - if _, err = db.GetEngine(ctx).Where("team_id = ?", team.ID).Delete(new(TeamUnit)); err != nil { - return err - } - - if len(units) > 0 { - if err = db.Insert(ctx, units); err != nil { - return err - } - } - return nil - }) -} diff --git a/models/organization/team_user.go b/models/organization/team_user.go index d6d0a5054dd..d24a4c51263 100644 --- a/models/organization/team_user.go +++ b/models/organization/team_user.go @@ -36,14 +36,6 @@ type SearchMembersOptions struct { TeamID int64 } -func (opts SearchMembersOptions) ToConds() builder.Cond { - cond := builder.NewCond() - if opts.TeamID > 0 { - cond = cond.And(builder.Eq{"": opts.TeamID}) - } - return cond -} - // GetTeamMembers returns all members in given team of organization. func GetTeamMembers(ctx context.Context, opts *SearchMembersOptions) ([]*user_model.User, error) { var members []*user_model.User diff --git a/models/project/column.go b/models/project/column.go index 997e82ddf90..9c9abb4599d 100644 --- a/models/project/column.go +++ b/models/project/column.go @@ -337,20 +337,6 @@ func SetDefaultColumn(ctx context.Context, projectID, columnID int64) error { }) } -// UpdateColumnSorting update project column sorting -func UpdateColumnSorting(ctx context.Context, cl ColumnList) error { - return db.WithTx(ctx, func(ctx context.Context) error { - for i := range cl { - if _, err := db.GetEngine(ctx).ID(cl[i].ID).Cols( - "sorting", - ).Update(cl[i]); err != nil { - return err - } - } - return nil - }) -} - func GetColumnsByIDs(ctx context.Context, projectID int64, columnsIDs []int64) (ColumnList, error) { columns := make([]*Column, 0, 5) if len(columnsIDs) == 0 { diff --git a/models/repo/topic.go b/models/repo/topic.go index 6d5209d8210..14017da2d0b 100644 --- a/models/repo/topic.go +++ b/models/repo/topic.go @@ -44,12 +44,6 @@ type ErrTopicNotExist struct { Name string } -// IsErrTopicNotExist checks if an error is an ErrTopicNotExist. -func IsErrTopicNotExist(err error) bool { - _, ok := err.(ErrTopicNotExist) - return ok -} - // Error implements error interface func (err ErrTopicNotExist) Error() string { return fmt.Sprintf("topic is not exist [name: %s]", err.Name) diff --git a/models/system/notice.go b/models/system/notice.go index f39188f8fb3..4b919dffc92 100644 --- a/models/system/notice.go +++ b/models/system/notice.go @@ -13,7 +13,6 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/storage" "code.gitea.io/gitea/modules/timeutil" - "code.gitea.io/gitea/modules/util" ) // NoticeType describes the notice type @@ -60,18 +59,6 @@ func CreateRepositoryNotice(desc string, args ...any) error { return CreateNotice(graceful.GetManager().ShutdownContext(), NoticeRepository, desc, args...) } -// RemoveAllWithNotice removes all directories in given path and -// creates a system notice when error occurs. -func RemoveAllWithNotice(ctx context.Context, title, path string) { - if err := util.RemoveAll(path); err != nil { - desc := fmt.Sprintf("%s [%s]: %v", title, path, err) - log.Warn(title+" [%s]: %v", path, err) - if err = CreateNotice(graceful.GetManager().ShutdownContext(), NoticeRepository, desc); err != nil { - log.Error("CreateRepositoryNotice: %v", err) - } - } -} - // RemoveStorageWithNotice removes a file from the storage and // creates a system notice when error occurs. func RemoveStorageWithNotice(ctx context.Context, bucket storage.ObjectStorage, title, path string) { diff --git a/models/user/badge.go b/models/user/badge.go index fbba8659261..a41eda07b5e 100644 --- a/models/user/badge.go +++ b/models/user/badge.go @@ -212,12 +212,6 @@ func RemoveUserBadges(ctx context.Context, u *User, badges []*Badge) error { }) } -// RemoveAllUserBadges removes all badges from a user. -func RemoveAllUserBadges(ctx context.Context, u *User) error { - _, err := db.GetEngine(ctx).Where("user_id=?", u.ID).Delete(&UserBadge{}) - return err -} - // SearchBadgeOptions represents the options when finding badges type SearchBadgeOptions struct { db.ListOptions @@ -258,16 +252,3 @@ func (opts *SearchBadgeOptions) ToOrders() string { func SearchBadges(ctx context.Context, opts *SearchBadgeOptions) ([]*Badge, int64, error) { return db.FindAndCount[Badge](ctx, opts) } - -// GetBadgeByID returns a specific badge by ID -func GetBadgeByID(ctx context.Context, id int64) (*Badge, error) { - badge := new(Badge) - has, err := db.GetEngine(ctx).ID(id).Get(badge) - if err != nil { - return nil, err - } - if !has { - return nil, util.NewNotExistErrorf("badge does not exist [id: %d]", id) - } - return badge, nil -} diff --git a/models/user/email_address.go b/models/user/email_address.go index aa483d5f005..670d417f9e6 100644 --- a/models/user/email_address.go +++ b/models/user/email_address.go @@ -147,11 +147,6 @@ func InsertEmailAddress(ctx context.Context, email *EmailAddress) (*EmailAddress return email, nil } -func UpdateEmailAddress(ctx context.Context, email *EmailAddress) error { - _, err := db.GetEngine(ctx).ID(email.ID).AllCols().Update(email) - return err -} - // ValidateEmail check if email is a valid & allowed address func ValidateEmail(email string) error { if err := validateEmailBasic(email); err != nil { diff --git a/models/user/error.go b/models/user/error.go index cbf19998d10..5a956a2afe1 100644 --- a/models/user/error.go +++ b/models/user/error.go @@ -71,27 +71,6 @@ func (err ErrUserProhibitLogin) Unwrap() error { return util.ErrPermissionDenied } -// ErrUserInactive represents a "ErrUserInactive" kind of error. -type ErrUserInactive struct { - UID int64 - Name string -} - -// IsErrUserInactive checks if an error is a ErrUserInactive -func IsErrUserInactive(err error) bool { - _, ok := err.(ErrUserInactive) - return ok -} - -func (err ErrUserInactive) Error() string { - return fmt.Sprintf("user is inactive [uid: %d, name: %s]", err.UID, err.Name) -} - -// Unwrap unwraps this error as a ErrPermission error -func (err ErrUserInactive) Unwrap() error { - return util.ErrPermissionDenied -} - // ErrUserIsNotLocal represents a "ErrUserIsNotLocal" kind of error. type ErrUserIsNotLocal struct { UID int64 diff --git a/models/user/external_login_user.go b/models/user/external_login_user.go index 0e764efb9fe..636a2007ee8 100644 --- a/models/user/external_login_user.go +++ b/models/user/external_login_user.go @@ -21,12 +21,6 @@ type ErrExternalLoginUserAlreadyExist struct { LoginSourceID int64 } -// IsErrExternalLoginUserAlreadyExist checks if an error is a ExternalLoginUserAlreadyExist. -func IsErrExternalLoginUserAlreadyExist(err error) bool { - _, ok := err.(ErrExternalLoginUserAlreadyExist) - return ok -} - func (err ErrExternalLoginUserAlreadyExist) Error() string { return fmt.Sprintf("external login user already exists [externalID: %s, userID: %d, loginSourceID: %d]", err.ExternalID, err.UserID, err.LoginSourceID) } @@ -41,12 +35,6 @@ type ErrExternalLoginUserNotExist struct { LoginSourceID int64 } -// IsErrExternalLoginUserNotExist checks if an error is a ExternalLoginUserNotExist. -func IsErrExternalLoginUserNotExist(err error) bool { - _, ok := err.(ErrExternalLoginUserNotExist) - return ok -} - func (err ErrExternalLoginUserNotExist) Error() string { return fmt.Sprintf("external login user link does not exists [userID: %d, loginSourceID: %d]", err.UserID, err.LoginSourceID) } diff --git a/models/user/setting.go b/models/user/setting.go index a16fc86e55e..67b45208fcf 100644 --- a/models/user/setting.go +++ b/models/user/setting.go @@ -50,12 +50,6 @@ func (err ErrUserSettingIsNotExist) Unwrap() error { return util.ErrNotExist } -// IsErrUserSettingIsNotExist return true if err is ErrSettingIsNotExist -func IsErrUserSettingIsNotExist(err error) bool { - _, ok := err.(ErrUserSettingIsNotExist) - return ok -} - // genSettingCacheKey returns the cache key for some configuration func genSettingCacheKey(userID int64, key string) string { return fmt.Sprintf("user_%d.setting.%s", userID, key) diff --git a/modules/actions/jobparser/jobparser.go b/modules/actions/jobparser/jobparser.go index 1d4c4c1756a..76f229a54b3 100644 --- a/modules/actions/jobparser/jobparser.go +++ b/modules/actions/jobparser/jobparser.go @@ -83,12 +83,6 @@ func Parse(content []byte, options ...ParseOption) ([]*SingleWorkflow, error) { return ret, nil } -func WithJobResults(results map[string]string) ParseOption { - return func(c *parseContext) { - c.jobResults = results - } -} - func WithGitContext(context *model.GithubContext) ParseOption { return func(c *parseContext) { c.gitContext = context diff --git a/modules/eventsource/event.go b/modules/eventsource/event.go index ebcca509034..c72cc466a03 100644 --- a/modules/eventsource/event.go +++ b/modules/eventsource/event.go @@ -7,7 +7,6 @@ import ( "bytes" "fmt" "io" - "strings" "time" "code.gitea.io/gitea/modules/json" @@ -110,9 +109,3 @@ func (e *Event) WriteTo(w io.Writer) (int64, error) { return sum, err } - -func (e *Event) String() string { - buf := new(strings.Builder) - _, _ = e.WriteTo(buf) - return buf.String() -} diff --git a/modules/gitrepo/commit.go b/modules/gitrepo/commit.go index 0ab17862fee..0a8cb0544cb 100644 --- a/modules/gitrepo/commit.go +++ b/modules/gitrepo/commit.go @@ -44,23 +44,6 @@ func CommitsCount(ctx context.Context, repo Repository, opts CommitsCountOptions return strconv.ParseInt(strings.TrimSpace(stdout), 10, 64) } -// CommitsCountBetween return numbers of commits between two commits -func CommitsCountBetween(ctx context.Context, repo Repository, start, end string) (int64, error) { - count, err := CommitsCount(ctx, repo, CommitsCountOptions{ - Revision: []string{start + ".." + end}, - }) - - if err != nil && strings.Contains(err.Error(), "no merge base") { - // future versions of git >= 2.28 are likely to return an error if before and last have become unrelated. - // previously it would return the results of git rev-list before last so let's try that... - return CommitsCount(ctx, repo, CommitsCountOptions{ - Revision: []string{start, end}, - }) - } - - return count, err -} - // FileCommitsCount return the number of files at a revision func FileCommitsCount(ctx context.Context, repo Repository, revision, file string) (int64, error) { return CommitsCount(ctx, repo, diff --git a/modules/gitrepo/config.go b/modules/gitrepo/config.go index 9be3ef94aeb..4940f1c0788 100644 --- a/modules/gitrepo/config.go +++ b/modules/gitrepo/config.go @@ -5,21 +5,11 @@ package gitrepo import ( "context" - "strings" "code.gitea.io/gitea/modules/git/gitcmd" "code.gitea.io/gitea/modules/globallock" ) -func GitConfigGet(ctx context.Context, repo Repository, key string) (string, error) { - result, _, err := RunCmdString(ctx, repo, gitcmd.NewCommand("config", "--get"). - AddDynamicArguments(key)) - if err != nil { - return "", err - } - return strings.TrimSpace(result), nil -} - func getRepoConfigLockKey(repoStoragePath string) string { return "repo-config:" + repoStoragePath } diff --git a/modules/hostmatcher/hostmatcher.go b/modules/hostmatcher/hostmatcher.go index 15c63714222..044dba679a1 100644 --- a/modules/hostmatcher/hostmatcher.go +++ b/modules/hostmatcher/hostmatcher.go @@ -78,11 +78,6 @@ func (hl *HostMatchList) AppendBuiltin(builtin string) { hl.builtins = append(hl.builtins, builtin) } -// AppendPattern appends more pattern to match -func (hl *HostMatchList) AppendPattern(pattern string) { - hl.patterns = append(hl.patterns, pattern) -} - // IsEmpty checks if the checklist is empty func (hl *HostMatchList) IsEmpty() bool { return hl == nil || (len(hl.builtins) == 0 && len(hl.patterns) == 0 && len(hl.ipNets) == 0) diff --git a/modules/markup/markdown/markdown.go b/modules/markup/markdown/markdown.go index f6a6cb26c6d..1cc75d763d1 100644 --- a/modules/markup/markdown/markdown.go +++ b/modules/markup/markdown/markdown.go @@ -74,10 +74,6 @@ func (r *GlodmarkRender) Convert(source []byte, writer io.Writer, opts ...parser return r.goldmarkMarkdown.Convert(source, writer, opts...) } -func (r *GlodmarkRender) Renderer() renderer.Renderer { - return r.goldmarkMarkdown.Renderer() -} - func (r *GlodmarkRender) highlightingRenderer(w util.BufWriter, c highlighting.CodeBlockContext, entering bool) { if entering { languageBytes, _ := c.Language() diff --git a/modules/storage/storage.go b/modules/storage/storage.go index e19c421ba82..1271440e5a8 100644 --- a/modules/storage/storage.go +++ b/modules/storage/storage.go @@ -21,25 +21,6 @@ import ( // ErrURLNotSupported represents url is not supported var ErrURLNotSupported = errors.New("url method not supported") -// ErrInvalidConfiguration is called when there is invalid configuration for a storage -type ErrInvalidConfiguration struct { - cfg any - err error -} - -func (err ErrInvalidConfiguration) Error() string { - if err.err != nil { - return fmt.Sprintf("Invalid Configuration Argument: %v: Error: %v", err.cfg, err.err) - } - return fmt.Sprintf("Invalid Configuration Argument: %v", err.cfg) -} - -// IsErrInvalidConfiguration checks if an error is an ErrInvalidConfiguration -func IsErrInvalidConfiguration(err error) bool { - _, ok := err.(ErrInvalidConfiguration) - return ok -} - type Type = setting.StorageType // NewStorageFunc is a function that creates a storage diff --git a/modules/web/middleware/locale.go b/modules/web/middleware/locale.go index 34a16f04e7f..fc396f08081 100644 --- a/modules/web/middleware/locale.go +++ b/modules/web/middleware/locale.go @@ -51,9 +51,3 @@ func Locale(resp http.ResponseWriter, req *http.Request) translation.Locale { func SetLocaleCookie(resp http.ResponseWriter, lang string, maxAge int) { SetSiteCookie(resp, "lang", lang, maxAge) } - -// DeleteLocaleCookie convenience function to delete the locale cookie consistently -// Setting the lang cookie will trigger the middleware to reset the language to previous state. -func DeleteLocaleCookie(resp http.ResponseWriter) { - SetSiteCookie(resp, "lang", "", -1) -} diff --git a/routers/api/v1/user/gpg_key.go b/routers/api/v1/user/gpg_key.go index 9ec4d2c938a..39ded31bf48 100644 --- a/routers/api/v1/user/gpg_key.go +++ b/routers/api/v1/user/gpg_key.go @@ -281,11 +281,7 @@ func DeleteGPGKey(ctx *context.APIContext) { } if err := asymkey_model.DeleteGPGKey(ctx, ctx.Doer, ctx.PathParamInt64("id")); err != nil { - if asymkey_model.IsErrGPGKeyAccessDenied(err) { - ctx.APIError(http.StatusForbidden, "You do not have access to this key") - } else { - ctx.APIErrorInternal(err) - } + ctx.APIErrorInternal(err) return } @@ -295,8 +291,6 @@ func DeleteGPGKey(ctx *context.APIContext) { // HandleAddGPGKeyError handle add GPGKey error func HandleAddGPGKeyError(ctx *context.APIContext, err error, token string) { switch { - case asymkey_model.IsErrGPGKeyAccessDenied(err): - ctx.APIError(http.StatusUnprocessableEntity, "You do not have access to this GPG key") case asymkey_model.IsErrGPGKeyIDAlreadyUsed(err): ctx.APIError(http.StatusUnprocessableEntity, "A key with the same id already exists") case asymkey_model.IsErrGPGKeyParsing(err): diff --git a/routers/web/auth/auth.go b/routers/web/auth/auth.go index d705062b3d8..eb2045781dd 100644 --- a/routers/web/auth/auth.go +++ b/routers/web/auth/auth.go @@ -314,15 +314,6 @@ func SignInPost(ctx *context.Context) { log.Warn("Failed authentication attempt for %s from %s: %v", form.UserName, ctx.RemoteAddr(), err) ctx.Data["Title"] = ctx.Tr("auth.prohibit_login") ctx.HTML(http.StatusOK, "user/auth/prohibit_login") - } else if user_model.IsErrUserInactive(err) { - if setting.Service.RegisterEmailConfirm { - ctx.Data["Title"] = ctx.Tr("auth.active_your_account") - ctx.HTML(http.StatusOK, TplActivate) - } else { - log.Warn("Failed authentication attempt for %s from %s: %v", form.UserName, ctx.RemoteAddr(), err) - ctx.Data["Title"] = ctx.Tr("auth.prohibit_login") - ctx.HTML(http.StatusOK, "user/auth/prohibit_login") - } } else { ctx.ServerError("UserSignIn", err) } diff --git a/routers/web/auth/linkaccount.go b/routers/web/auth/linkaccount.go index 02e1b7acd2f..ea3aa3f7cae 100644 --- a/routers/web/auth/linkaccount.go +++ b/routers/web/auth/linkaccount.go @@ -105,16 +105,6 @@ func handleSignInError(ctx *context.Context, userName string, ptrForm any, tmpl log.Info("Failed authentication attempt for %s from %s: %v", userName, ctx.RemoteAddr(), err) ctx.Data["Title"] = ctx.Tr("auth.prohibit_login") ctx.HTML(http.StatusOK, "user/auth/prohibit_login") - } else if user_model.IsErrUserInactive(err) { - ctx.Data["user_exists"] = true - if setting.Service.RegisterEmailConfirm { - ctx.Data["Title"] = ctx.Tr("auth.active_your_account") - ctx.HTML(http.StatusOK, TplActivate) - } else { - log.Info("Failed authentication attempt for %s from %s: %v", userName, ctx.RemoteAddr(), err) - ctx.Data["Title"] = ctx.Tr("auth.prohibit_login") - ctx.HTML(http.StatusOK, "user/auth/prohibit_login") - } } else { ctx.ServerError(invoker, err) } diff --git a/routers/web/home.go b/routers/web/home.go index 7efa5f344e3..d14a7bab13f 100644 --- a/routers/web/home.go +++ b/routers/web/home.go @@ -109,9 +109,3 @@ func HomeSitemap(ctx *context.Context) { log.Error("Failed writing sitemap: %v", err) } } - -// NotFound render 404 page -func NotFound(ctx *context.Context) { - ctx.Data["Title"] = "Page Not Found" - ctx.NotFound(nil) -} diff --git a/routers/web/org/projects.go b/routers/web/org/projects.go index 4cdf81c1559..59aee819742 100644 --- a/routers/web/org/projects.go +++ b/routers/web/org/projects.go @@ -35,14 +35,6 @@ const ( tplProjectsView templates.TplName = "org/projects/view" ) -// MustEnableProjects check if projects are enabled in settings -func MustEnableProjects(ctx *context.Context) { - if unit.TypeProjects.UnitGlobalDisabled() { - ctx.NotFound(nil) - return - } -} - // Projects renders the home page of projects func Projects(ctx *context.Context) { if _, err := shared_user.RenderUserOrgHeader(ctx); err != nil { diff --git a/routers/web/shared/actions/runners.go b/routers/web/shared/actions/runners.go index 3609258440c..9d8b2f08eb1 100644 --- a/routers/web/shared/actions/runners.go +++ b/routers/web/shared/actions/runners.go @@ -362,10 +362,6 @@ func RunnerUpdatePost(ctx *context.Context) { ctx.JSONRedirect("") } -func RedirectToDefaultSetting(ctx *context.Context) { - ctx.Redirect(ctx.Repo.RepoLink + "/settings/actions/runners") -} - func findActionsRunner(ctx *context.Context, rCtx *runnersCtx) *actions_model.ActionRunner { runnerID := ctx.PathParamInt64("runnerid") opts := &actions_model.FindRunnerOptions{ diff --git a/services/context/user.go b/services/context/user.go index 19c055e2a30..138cdeae937 100644 --- a/services/context/user.go +++ b/services/context/user.go @@ -30,27 +30,6 @@ func UserAssignmentWeb() func(ctx *Context) { } } -// UserIDAssignmentAPI returns a middleware to handle context-user assignment for api routes -func UserIDAssignmentAPI() func(ctx *APIContext) { - return func(ctx *APIContext) { - userID := ctx.PathParamInt64("user-id") - - if ctx.IsSigned && ctx.Doer.ID == userID { - ctx.ContextUser = ctx.Doer - } else { - var err error - ctx.ContextUser, err = user_model.GetUserByID(ctx, userID) - if err != nil { - if user_model.IsErrUserNotExist(err) { - ctx.APIError(http.StatusNotFound, err) - } else { - ctx.APIErrorInternal(err) - } - } - } - } -} - // UserAssignmentAPI returns a middleware to handle context-user assignment for api routes func UserAssignmentAPI() func(ctx *APIContext) { return func(ctx *APIContext) { diff --git a/services/convert/secret.go b/services/convert/secret.go deleted file mode 100644 index dd7b9f0a6a9..00000000000 --- a/services/convert/secret.go +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2023 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package convert - -import ( - secret_model "code.gitea.io/gitea/models/secret" - api "code.gitea.io/gitea/modules/structs" -) - -// ToSecret converts Secret to API format -func ToSecret(secret *secret_model.Secret) *api.Secret { - result := &api.Secret{ - Name: secret.Name, - } - - return result -} diff --git a/services/forms/repo_form.go b/services/forms/repo_form.go index 01e57a596ef..09b9b2690c4 100644 --- a/services/forms/repo_form.go +++ b/services/forms/repo_form.go @@ -740,14 +740,3 @@ func (f *AddTimeManuallyForm) Validate(req *http.Request, errs binding.Errors) b type SaveTopicForm struct { Topics []string `binding:"topics;Required;"` } - -// DeadlineForm hold the validation rules for deadlines -type DeadlineForm struct { - DateString string `form:"date" binding:"Required;Size(10)"` -} - -// Validate validates the fields -func (f *DeadlineForm) Validate(req *http.Request, errs binding.Errors) binding.Errors { - ctx := context.GetValidateContext(req) - return middleware.Validate(errs, ctx.Data, f, ctx.Locale) -} diff --git a/services/repository/files/content.go b/services/repository/files/content.go index fc0e00a1a72..9b042f9e67a 100644 --- a/services/repository/files/content.go +++ b/services/repository/files/content.go @@ -32,11 +32,6 @@ const ( ContentTypeSubmodule ContentType = "submodule" // submodule content type (submodule) ) -// String gets the string of ContentType -func (ct *ContentType) String() string { - return string(*ct) -} - type GetContentsOrListOptions struct { TreePath string IncludeSingleFileContent bool // include the file's content when the tree path is a file diff --git a/services/repository/files/tree.go b/services/repository/files/tree.go index e678b07f565..fc361273388 100644 --- a/services/repository/files/tree.go +++ b/services/repository/files/tree.go @@ -26,12 +26,6 @@ type ErrSHANotFound struct { SHA string } -// IsErrSHANotFound checks if an error is a ErrSHANotFound. -func IsErrSHANotFound(err error) bool { - _, ok := err.(ErrSHANotFound) - return ok -} - func (err ErrSHANotFound) Error() string { return fmt.Sprintf("sha not found [%s]", err.SHA) } From 019d85039cb7891ed03699f6c51fc647706ac345 Mon Sep 17 00:00:00 2001 From: techknowlogick Date: Mon, 20 Apr 2026 13:02:29 -0400 Subject: [PATCH 04/66] Use updated yaml fields for snapcraft (#37318) --- snap/snapcraft.yaml | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 51647e27335..9cad252e670 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -11,10 +11,16 @@ confinement: strict base: core24 adopt-info: gitea -architectures: - - build-on: armhf - - build-on: amd64 - - build-on: arm64 +platforms: + armhf: + build-on: [armhf] + build-for: [armhf] + amd64: + build-on: [amd64] + build-for: [amd64] + arm64: + build-on: [arm64] + build-for: [arm64] environment: GITEA_CUSTOM: "$SNAP_COMMON" From 1d25bb22f4049a0ca755249e3d057b7e5a74ce2a Mon Sep 17 00:00:00 2001 From: silverwind Date: Mon, 20 Apr 2026 20:15:45 +0200 Subject: [PATCH 05/66] Move heatmap to first-party code (#37262) Replaces `@silverwind/vue3-calendar-heatmap` with an inlined SVG implementation. Renders pixel-identically to `main`, drops the `onMounted` legend viewBox workaround, and uses tippy's `createSingleton` for the hover tooltip. Adds an e2e test for tooltip display. This is a prereq for migrating tippy.js to [floating-ui](https://github.com/floating-ui/floating-ui) to avoid having two tooltip libs active. image --- This PR was written with the help of Claude Opus 4.7 --------- Co-authored-by: Claude (Opus 4.7) Co-authored-by: Nicolas --- package.json | 1 - pnpm-lock.yaml | 15 -- tests/e2e/heatmap.test.ts | 9 + web_src/css/features/heatmap.css | 17 +- web_src/js/components/ActivityHeatmap.vue | 196 ++++++++++++++++++---- 5 files changed, 187 insertions(+), 51 deletions(-) create mode 100644 tests/e2e/heatmap.test.ts diff --git a/package.json b/package.json index b090b320980..9dcbf411d38 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,6 @@ "@replit/codemirror-lang-svelte": "6.0.0", "@replit/codemirror-vscode-keymap": "6.0.2", "@resvg/resvg-wasm": "2.6.2", - "@silverwind/vue3-calendar-heatmap": "2.1.1", "@vitejs/plugin-vue": "6.0.6", "ansi_up": "6.0.6", "asciinema-player": "3.15.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a05156011e8..fdc569187a5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -112,9 +112,6 @@ importers: '@resvg/resvg-wasm': specifier: 2.6.2 version: 2.6.2 - '@silverwind/vue3-calendar-heatmap': - specifier: 2.1.1 - version: 2.1.1(tippy.js@6.3.7)(vue@3.5.32(typescript@6.0.2)) '@vitejs/plugin-vue': specifier: 6.0.6 version: 6.0.6(vite@8.0.8(@types/node@25.6.0)(esbuild@0.28.0)(jiti@2.6.1))(vue@3.5.32(typescript@6.0.2)) @@ -1249,13 +1246,6 @@ packages: '@scarf/scarf@1.4.0': resolution: {integrity: sha512-xxeapPiUXdZAE3che6f3xogoJPeZgig6omHEy1rIY5WVsB3H2BHNnZH+gHG6x91SCWyQCzWGsuL2Hh3ClO5/qQ==} - '@silverwind/vue3-calendar-heatmap@2.1.1': - resolution: {integrity: sha512-RQtLOpkysm0LR3PbUoc+aDcYxzy7xboygb1SQEwrUm2/XB2nmt0BEra2ADXpu4kwFxtk0+IyNwzFvbBai/wvTg==} - engines: {node: '>=16'} - peerDependencies: - tippy.js: ^6.3.7 - vue: ^3.2.29 - '@simonwep/pickr@1.9.0': resolution: {integrity: sha512-oEYvv15PyfZzjoAzvXYt3UyNGwzsrpFxLaZKzkOSd0WYBVwLd19iJerePDONxC1iF6+DpcswPdLIM2KzCJuYFg==} @@ -5052,11 +5042,6 @@ snapshots: '@scarf/scarf@1.4.0': {} - '@silverwind/vue3-calendar-heatmap@2.1.1(tippy.js@6.3.7)(vue@3.5.32(typescript@6.0.2))': - dependencies: - tippy.js: 6.3.7 - vue: 3.5.32(typescript@6.0.2) - '@simonwep/pickr@1.9.0': dependencies: core-js: 3.32.2 diff --git a/tests/e2e/heatmap.test.ts b/tests/e2e/heatmap.test.ts new file mode 100644 index 00000000000..5aabfab196c --- /dev/null +++ b/tests/e2e/heatmap.test.ts @@ -0,0 +1,9 @@ +import {test, expect} from '@playwright/test'; +import {login} from './utils.ts'; + +test('heatmap tooltip shows on hover', async ({page}) => { + await login(page); + await page.goto('/'); + await page.locator('.heatmap-day').first().hover(); + await expect(page.locator('.tippy-box[data-state="visible"]')).toBeVisible(); +}); diff --git a/web_src/css/features/heatmap.css b/web_src/css/features/heatmap.css index e40adf1fe48..a2d8c4ea590 100644 --- a/web_src/css/features/heatmap.css +++ b/web_src/css/features/heatmap.css @@ -32,26 +32,29 @@ fill: currentcolor !important; } -/* root legend */ -#user-heatmap .vch__container > .vch__legend { +#user-heatmap .heatmap-footer { display: flex; font-size: 11px; justify-content: space-between; } -/* for the "Less" and "More" legend */ -#user-heatmap .vch__legend .vch__legend { +/* "Less [colors] More" scale */ +#user-heatmap .heatmap-legend { display: flex; align-items: center; justify-content: right; } -#user-heatmap .vch__legend .vch__legend div:first-child, -#user-heatmap .vch__legend .vch__legend div:last-child { +#user-heatmap .heatmap-legend-svg { + margin-right: -12px; +} + +#user-heatmap .heatmap-legend > div:first-child, +#user-heatmap .heatmap-legend > div:last-child { display: inline-block; padding: 0 5px; } -#user-heatmap .vch__day__square:hover { +#user-heatmap .heatmap-day:hover { outline: 1.5px solid var(--color-text); } diff --git a/web_src/js/components/ActivityHeatmap.vue b/web_src/js/components/ActivityHeatmap.vue index 7c7e0cd94ca..08c590aa16b 100644 --- a/web_src/js/components/ActivityHeatmap.vue +++ b/web_src/js/components/ActivityHeatmap.vue @@ -1,21 +1,23 @@ From ca44b5fca8e041ff4ef7ebe8c061105d0d5e2f99 Mon Sep 17 00:00:00 2001 From: PineBale <272794187+PineBale@users.noreply.github.com> Date: Tue, 21 Apr 2026 02:58:44 +0800 Subject: [PATCH 06/66] Add `form-fetch-action` to some forms, fix "fetch action" resp bug (#37305) Co-authored-by: wxiaoguang --- modules/test/utils.go | 2 +- routers/web/repo/setting/setting.go | 48 +++++++++++----------- templates/repo/settings/options.tmpl | 10 ++--- tests/integration/editor_test.go | 3 +- tests/integration/pull_create_test.go | 3 +- tests/integration/repo_visibility_test.go | 4 +- web_src/js/features/common-fetch-action.ts | 2 +- 7 files changed, 37 insertions(+), 35 deletions(-) diff --git a/modules/test/utils.go b/modules/test/utils.go index a55deeb2e35..331dc4a959b 100644 --- a/modules/test/utils.go +++ b/modules/test/utils.go @@ -47,7 +47,7 @@ func ParseJSONError(buf []byte) (ret struct { } func ParseJSONRedirect(buf []byte) (ret struct { - Redirect string `json:"redirect"` + Redirect *string `json:"redirect"` }, ) { _ = json.Unmarshal(buf, &ret) diff --git a/routers/web/repo/setting/setting.go b/routers/web/repo/setting/setting.go index 29f3e62b8fc..118f16d8f1f 100644 --- a/routers/web/repo/setting/setting.go +++ b/routers/web/repo/setting/setting.go @@ -725,16 +725,16 @@ func handleSettingsPostConvert(ctx *context.Context) { form := web.GetForm(ctx).(*forms.RepoSettingForm) repo := ctx.Repo.Repository if !ctx.Repo.IsOwner() { - ctx.HTTPError(http.StatusNotFound) + ctx.JSONErrorNotFound() return } if repo.Name != form.RepoName { - ctx.RenderWithErrDeprecated(ctx.Tr("form.enterred_invalid_repo_name"), tplSettingsOptions, nil) + ctx.JSONError(ctx.Tr("form.enterred_invalid_repo_name")) return } if !repo.IsMirror { - ctx.HTTPError(http.StatusNotFound) + ctx.JSONErrorNotFound() return } repo.IsMirror = false @@ -748,14 +748,14 @@ func handleSettingsPostConvert(ctx *context.Context) { } log.Trace("Repository converted from mirror to regular: %s", repo.FullName()) ctx.Flash.Success(ctx.Tr("repo.settings.convert_succeed")) - ctx.Redirect(repo.Link()) + ctx.JSONRedirect(repo.Link()) } func handleSettingsPostConvertFork(ctx *context.Context) { form := web.GetForm(ctx).(*forms.RepoSettingForm) repo := ctx.Repo.Repository if !ctx.Repo.IsOwner() { - ctx.HTTPError(http.StatusNotFound) + ctx.JSONErrorNotFound() return } if err := repo.LoadOwner(ctx); err != nil { @@ -763,12 +763,12 @@ func handleSettingsPostConvertFork(ctx *context.Context) { return } if repo.Name != form.RepoName { - ctx.RenderWithErrDeprecated(ctx.Tr("form.enterred_invalid_repo_name"), tplSettingsOptions, nil) + ctx.JSONError(ctx.Tr("form.enterred_invalid_repo_name")) return } if !repo.IsFork { - ctx.HTTPError(http.StatusNotFound) + ctx.JSONErrorNotFound() return } @@ -776,7 +776,7 @@ func handleSettingsPostConvertFork(ctx *context.Context) { maxCreationLimit := ctx.Repo.Owner.MaxCreationLimit() msg := ctx.TrN(maxCreationLimit, "repo.form.reach_limit_of_creation_1", "repo.form.reach_limit_of_creation_n", maxCreationLimit) ctx.Flash.Error(msg) - ctx.Redirect(repo.Link() + "/settings") + ctx.JSONRedirect(repo.Link() + "/settings") return } @@ -788,25 +788,25 @@ func handleSettingsPostConvertFork(ctx *context.Context) { log.Trace("Repository converted from fork to regular: %s", repo.FullName()) ctx.Flash.Success(ctx.Tr("repo.settings.convert_fork_succeed")) - ctx.Redirect(repo.Link()) + ctx.JSONRedirect(repo.Link()) } func handleSettingsPostTransfer(ctx *context.Context) { form := web.GetForm(ctx).(*forms.RepoSettingForm) repo := ctx.Repo.Repository if !ctx.Repo.IsOwner() { - ctx.HTTPError(http.StatusNotFound) + ctx.JSONErrorNotFound() return } if repo.Name != form.RepoName { - ctx.RenderWithErrDeprecated(ctx.Tr("form.enterred_invalid_repo_name"), tplSettingsOptions, nil) + ctx.JSONError(ctx.Tr("form.enterred_invalid_repo_name")) return } newOwner, err := user_model.GetUserByName(ctx, ctx.FormString("new_owner_name")) if err != nil { if user_model.IsErrUserNotExist(err) { - ctx.RenderWithErrDeprecated(ctx.Tr("form.enterred_invalid_owner_name"), tplSettingsOptions, nil) + ctx.JSONError(ctx.Tr("form.enterred_invalid_owner_name")) return } ctx.ServerError("IsUserExist", err) @@ -816,7 +816,7 @@ func handleSettingsPostTransfer(ctx *context.Context) { if newOwner.Type == user_model.UserTypeOrganization { if !ctx.Doer.IsAdmin && newOwner.Visibility == structs.VisibleTypePrivate && !organization.OrgFromUser(newOwner).HasMemberWithUserID(ctx, ctx.Doer.ID) { // The user shouldn't know about this organization - ctx.RenderWithErrDeprecated(ctx.Tr("form.enterred_invalid_owner_name"), tplSettingsOptions, nil) + ctx.JSONError(ctx.Tr("form.enterred_invalid_owner_name")) return } } @@ -830,14 +830,14 @@ func handleSettingsPostTransfer(ctx *context.Context) { oldFullname := repo.FullName() if err := repo_service.StartRepositoryTransfer(ctx, ctx.Doer, newOwner, repo, nil); err != nil { if repo_model.IsErrRepoAlreadyExist(err) { - ctx.RenderWithErrDeprecated(ctx.Tr("repo.settings.new_owner_has_same_repo"), tplSettingsOptions, nil) + ctx.JSONError(ctx.Tr("repo.settings.new_owner_has_same_repo")) } else if repo_model.IsErrRepoTransferInProgress(err) { - ctx.RenderWithErrDeprecated(ctx.Tr("repo.settings.transfer_in_progress"), tplSettingsOptions, nil) + ctx.JSONError(ctx.Tr("repo.settings.transfer_in_progress")) } else if repo_service.IsRepositoryLimitReached(err) { limit := err.(repo_service.LimitReachedError).Limit - ctx.RenderWithErrDeprecated(ctx.TrN(limit, "repo.form.reach_limit_of_creation_1", "repo.form.reach_limit_of_creation_n", limit), tplSettingsOptions, nil) + ctx.JSONError(ctx.TrN(limit, "repo.form.reach_limit_of_creation_1", "repo.form.reach_limit_of_creation_n", limit)) } else if errors.Is(err, user_model.ErrBlockedUser) { - ctx.RenderWithErrDeprecated(ctx.Tr("repo.settings.transfer.blocked_user"), tplSettingsOptions, nil) + ctx.JSONError(ctx.Tr("repo.settings.transfer.blocked_user")) } else { ctx.ServerError("TransferOwnership", err) } @@ -852,7 +852,7 @@ func handleSettingsPostTransfer(ctx *context.Context) { log.Trace("Repository transferred: %s -> %s", oldFullname, ctx.Repo.Repository.FullName()) ctx.Flash.Success(ctx.Tr("repo.settings.transfer_succeed")) } - ctx.Redirect(repo.Link() + "/settings") + ctx.JSONRedirect(repo.Link() + "/settings") } func handleSettingsPostCancelTransfer(ctx *context.Context) { @@ -887,11 +887,11 @@ func handleSettingsPostDelete(ctx *context.Context) { form := web.GetForm(ctx).(*forms.RepoSettingForm) repo := ctx.Repo.Repository if !ctx.Repo.IsOwner() { - ctx.HTTPError(http.StatusNotFound) + ctx.JSONErrorNotFound() return } if repo.Name != form.RepoName { - ctx.RenderWithErrDeprecated(ctx.Tr("form.enterred_invalid_repo_name"), tplSettingsOptions, nil) + ctx.JSONError(ctx.Tr("form.enterred_invalid_repo_name")) return } @@ -907,18 +907,18 @@ func handleSettingsPostDelete(ctx *context.Context) { log.Trace("Repository deleted: %s/%s", ctx.Repo.Owner.Name, repo.Name) ctx.Flash.Success(ctx.Tr("repo.settings.deletion_success")) - ctx.Redirect(ctx.Repo.Owner.DashboardLink()) + ctx.JSONRedirect(ctx.Repo.Owner.DashboardLink()) } func handleSettingsPostDeleteWiki(ctx *context.Context) { form := web.GetForm(ctx).(*forms.RepoSettingForm) repo := ctx.Repo.Repository if !ctx.Repo.IsOwner() { - ctx.HTTPError(http.StatusNotFound) + ctx.JSONErrorNotFound() return } if repo.Name != form.RepoName { - ctx.RenderWithErrDeprecated(ctx.Tr("form.enterred_invalid_repo_name"), tplSettingsOptions, nil) + ctx.JSONError(ctx.Tr("form.enterred_invalid_repo_name")) return } @@ -929,7 +929,7 @@ func handleSettingsPostDeleteWiki(ctx *context.Context) { log.Trace("Repository wiki deleted: %s/%s", ctx.Repo.Owner.Name, repo.Name) ctx.Flash.Success(ctx.Tr("repo.settings.wiki_deletion_success")) - ctx.Redirect(ctx.Repo.RepoLink + "/settings") + ctx.JSONRedirect(ctx.Repo.RepoLink + "/settings") } func handleSettingsPostArchive(ctx *context.Context) { diff --git a/templates/repo/settings/options.tmpl b/templates/repo/settings/options.tmpl index 09c2ab660bf..6a18c63fd28 100644 --- a/templates/repo/settings/options.tmpl +++ b/templates/repo/settings/options.tmpl @@ -885,7 +885,7 @@
{{ctx.Locale.Tr "repo.settings.convert_notices_1"}}
-
+ {{template "repo/settings/repo_name_confirm_fields" (dict "RepoName" .Repository.Name)}} {{template "base/modal_actions_confirm" (dict "ModalButtonDangerText" (ctx.Locale.Tr "repo.settings.convert_confirm"))}} @@ -902,7 +902,7 @@
{{ctx.Locale.Tr "repo.settings.convert_fork_notices_1"}}
- + {{template "repo/settings/repo_name_confirm_fields" (dict "RepoName" .Repository.Name)}} {{template "base/modal_actions_confirm" (dict "ModalButtonDangerText" (ctx.Locale.Tr "repo.settings.convert_fork_confirm"))}} @@ -921,7 +921,7 @@ {{ctx.Locale.Tr "repo.settings.transfer_notices_3"}}
{{ctx.Locale.Tr "repo.settings.transfer_notices_4"}} - + {{template "repo/settings/repo_name_confirm_fields" (dict "RepoName" .Repository.Name)}}
@@ -946,7 +946,7 @@ {{ctx.Locale.Tr "repo.settings.delete_notices_fork_1"}} {{end}}
- + {{template "repo/settings/repo_name_confirm_fields" (dict "RepoName" .Repository.Name)}} {{template "base/modal_actions_confirm" (dict "ModalButtonDangerText" (ctx.Locale.Tr "repo.settings.confirm_delete"))}} @@ -1012,7 +1012,7 @@ {{ctx.Locale.Tr "repo.settings.delete_notices_1"}}
{{ctx.Locale.Tr "repo.settings.wiki_delete_notices_1" .Repository.Name}} - + {{template "repo/settings/repo_name_confirm_fields" (dict "RepoName" .Repository.Name)}} {{template "base/modal_actions_confirm" (dict "ModalButtonDangerText" (ctx.Locale.Tr "repo.settings.confirm_wiki_delete"))}} diff --git a/tests/integration/editor_test.go b/tests/integration/editor_test.go index ac106bc776e..2ddee704402 100644 --- a/tests/integration/editor_test.go +++ b/tests/integration/editor_test.go @@ -372,7 +372,8 @@ func testForkToEditFile(t *testing.T, session *TestSession, user, owner, repo, b "action": "convert_fork", }, ) - session.MakeRequest(t, req, http.StatusSeeOther) + resp = session.MakeRequest(t, req, http.StatusOK) + assert.NotNil(t, test.ParseJSONRedirect(resp.Body.Bytes()).Redirect) }) // Fork repository again, and check the existence of the forked repo with unique name diff --git a/tests/integration/pull_create_test.go b/tests/integration/pull_create_test.go index 2c17557eb07..a8bf6689a34 100644 --- a/tests/integration/pull_create_test.go +++ b/tests/integration/pull_create_test.go @@ -189,7 +189,8 @@ func testDeleteRepository(t *testing.T, session *TestSession, ownerName, repoNam req := NewRequestWithValues(t, "POST", relURL+"?action=delete", map[string]string{ "repo_name": repoName, }) - session.MakeRequest(t, req, http.StatusSeeOther) + resp := session.MakeRequest(t, req, http.StatusOK) + assert.NotNil(t, test.ParseJSONRedirect(resp.Body.Bytes()).Redirect) } func TestPullBranchDelete(t *testing.T) { diff --git a/tests/integration/repo_visibility_test.go b/tests/integration/repo_visibility_test.go index e7ad8ddd876..f9a2ab83695 100644 --- a/tests/integration/repo_visibility_test.go +++ b/tests/integration/repo_visibility_test.go @@ -39,7 +39,7 @@ func TestRepositoryVisibilityChange(t *testing.T) { "confirm_repo_name": "user2/repo1", }) resp = session.MakeRequest(t, req, http.StatusOK) - assert.NotEmpty(t, test.ParseJSONRedirect(resp.Body.Bytes()).Redirect) + assert.NotNil(t, test.ParseJSONRedirect(resp.Body.Bytes()).Redirect) repo1 = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) assert.True(t, repo1.IsPrivate) @@ -51,7 +51,7 @@ func TestRepositoryVisibilityChange(t *testing.T) { "private": "false", }) resp := session.MakeRequest(t, req, http.StatusOK) - assert.NotEmpty(t, test.ParseJSONRedirect(resp.Body.Bytes()).Redirect) + assert.NotNil(t, test.ParseJSONRedirect(resp.Body.Bytes()).Redirect) repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}) assert.False(t, repo2.IsPrivate) diff --git a/web_src/js/features/common-fetch-action.ts b/web_src/js/features/common-fetch-action.ts index 595bb96c854..a96e69915f3 100644 --- a/web_src/js/features/common-fetch-action.ts +++ b/web_src/js/features/common-fetch-action.ts @@ -91,7 +91,7 @@ async function handleFetchActionSuccess(el: HTMLElement, opt: FetchActionOpts, r async function handleFetchActionError(resp: Response) { const isRespJson = resp.headers.get('content-type')?.includes('application/json'); const respText = await resp.text(); - const respJson = isRespJson ? JSON.parse(await resp.text()) : null; + const respJson = isRespJson ? JSON.parse(respText) : null; if (respJson?.errorMessage) { // the code was quite messy, sometimes the backend uses "err", sometimes it uses "error", and even "user_error" // but at the moment, as a new approach, we only use "errorMessage" here, backend can use JSONError() to respond. From b6ea666fd47cdbf627c95ff107338b200ea9b7c6 Mon Sep 17 00:00:00 2001 From: silverwind Date: Mon, 20 Apr 2026 21:49:38 +0200 Subject: [PATCH 07/66] Revert "Add WebKit to e2e test matrix (#37298)" (#37315) Reverts: #37298 Ref: https://github.com/go-gitea/gitea/actions/runs/24661464168/job/72108324223?pr=37312 WebKit on Linux has a long history of flakiness in Playwright CI runs, and the exact "WebKit encountered an internal error" class of failures has been reported repeatedly and closed without a real fix (typically stale/no-repro, or worked around by retries): - https://github.com/microsoft/playwright/issues/34450 - https://github.com/microsoft/playwright/issues/35773 - https://github.com/microsoft/playwright/issues/35870 - https://github.com/microsoft/playwright/issues/35293 - https://github.com/microsoft/playwright/issues/38838 Keeping chromium and firefox in the e2e matrix. --- This PR was written with the help of Claude Opus 4.7 Co-authored-by: Claude (Opus 4.7) --- Makefile | 3 ++- playwright.config.ts | 6 ------ 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index 0e4d68bffe0..e621cc362fc 100644 --- a/Makefile +++ b/Makefile @@ -518,7 +518,8 @@ test-mssql-migration: migrations.mssql.test migrations.individual.mssql.test .PHONY: playwright playwright: deps-frontend - @pnpm exec playwright install --with-deps chromium firefox webkit $(PLAYWRIGHT_FLAGS) + @# on GitHub Actions VMs, playwright's system deps are pre-installed + @pnpm exec playwright install $(if $(GITHUB_ACTIONS),,--with-deps) chromium firefox $(PLAYWRIGHT_FLAGS) .PHONY: test-e2e test-e2e: playwright $(EXECUTABLE_E2E) diff --git a/playwright.config.ts b/playwright.config.ts index 8fdd777ee47..9dc8a7c1b5c 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -36,11 +36,5 @@ export default defineConfig({ ...devices['Desktop Firefox'], }, }, - { - name: 'webkit', - use: { - ...devices['Desktop Safari'], - }, - }, ], }); From 8068d608d19e4f098430838143216dd42e02112c Mon Sep 17 00:00:00 2001 From: Sebastian Ertz Date: Mon, 20 Apr 2026 22:27:12 +0200 Subject: [PATCH 08/66] Update GitHub Actions to latest major versions (#37313) | | from | to | | --- | --- | --- | | actions/setup-node | `v5` | `v6` | | astral-sh/setup-uv | `v8.0.0` | `v8.1.0` | --- .github/workflows/pull-compliance.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/pull-compliance.yml b/.github/workflows/pull-compliance.yml index b4f5002082c..dd453d00beb 100644 --- a/.github/workflows/pull-compliance.yml +++ b/.github/workflows/pull-compliance.yml @@ -38,7 +38,7 @@ jobs: contents: read steps: - uses: actions/checkout@v6 - - uses: astral-sh/setup-uv@v8.0.0 + - uses: astral-sh/setup-uv@v8.1.0 - run: uv python install 3.14 - uses: pnpm/action-setup@v5 - uses: actions/setup-node@v6 @@ -58,7 +58,7 @@ jobs: contents: read steps: - uses: actions/checkout@v6 - - uses: astral-sh/setup-uv@v8.0.0 + - uses: astral-sh/setup-uv@v8.1.0 - run: uv python install 3.14 - run: make deps-py - run: make lint-yaml @@ -72,9 +72,11 @@ jobs: steps: - uses: actions/checkout@v6 - uses: pnpm/action-setup@v5 - - uses: actions/setup-node@v5 + - uses: actions/setup-node@v6 with: node-version: 24 + cache: pnpm + cache-dependency-path: pnpm-lock.yaml - run: make deps-frontend - run: make lint-json From 3f3bebda0d7ee2677566ba44944f3dead00cb066 Mon Sep 17 00:00:00 2001 From: Sebastian Ertz Date: Tue, 21 Apr 2026 00:32:45 +0200 Subject: [PATCH 09/66] Update go js dependencies (#37312) | go | from | to | | --- | --- | --- | | github.com/aws/aws-sdk-go-v2/credentials | `1.19.14` | `1.19.15` | | github.com/aws/aws-sdk-go-v2/service/codecommit | `1.33.12` | `1.33.13` | | github.com/dlclark/regexp2 | `1.11.5` | `1.12.0` | | github.com/go-co-op/gocron/v2 | `2.20.0` | `2.21.0` | | github.com/go-webauthn/webauthn | `0.16.4` | `0.16.5` | | js | from | to | | --- | --- | --- | | @codemirror/view | `6.41.0` | `6.41.1` | | @primer/octicons | `19.24.0` | `19.24.1` | | clippie | `4.1.10` | `4.1.14` | | postcss | `8.5.9` | `8.5.10` | | rolldown-license-plugin | `2.2.5` | `3.0.1` | | swagger-ui-dist | `5.32.2` | `5.32.4` | | vite | `8.0.8` | `8.0.9` | | @typescript-eslint/parser | `8.58.2` | `8.59.0` | | @vitest/eslint-plugin | `1.6.15` | `1.6.16` | | eslint | `10.2.0` | `10.2.1` | | eslint-plugin-playwright | `2.10.1` | `2.10.2` | | eslint-plugin-sonarjs | `4.0.2` | `4.0.3` | | happy-dom | `20.8.9` | `20.9.0` | | stylelint | `17.7.0` | `17.8.0` | | typescript | `6.0.2` | `6.0.3` | | typescript-eslint | `8.58.2` | `8.59.0` | | updates | `17.15.3` | `17.15.5` | | vue-tsc | `3.2.6` | `3.2.7` | Co-authored-by: Nicolas Co-authored-by: silverwind Co-authored-by: silverwind Co-authored-by: Claude (Opus 4.7) --- go.mod | 20 +- go.sum | 40 +- package.json | 36 +- pnpm-lock.yaml | 1145 +++++++++++---------- services/cron/cron.go | 2 +- web_src/js/features/admin/config.test.ts | 2 +- web_src/js/features/tribute.ts | 6 +- web_src/js/modules/fomantic/dropdown.ts | 2 +- web_src/js/webcomponents/relative-time.ts | 2 +- 9 files changed, 642 insertions(+), 613 deletions(-) diff --git a/go.mod b/go.mod index d1aac0db900..d7577bfbf07 100644 --- a/go.mod +++ b/go.mod @@ -27,8 +27,8 @@ require ( github.com/PuerkitoBio/goquery v1.12.0 github.com/SaveTheRbtz/zstd-seekable-format-go/pkg v0.8.0 github.com/alecthomas/chroma/v2 v2.23.1 - github.com/aws/aws-sdk-go-v2/credentials v1.19.14 - github.com/aws/aws-sdk-go-v2/service/codecommit v1.33.12 + github.com/aws/aws-sdk-go-v2/credentials v1.19.15 + github.com/aws/aws-sdk-go-v2/service/codecommit v1.33.13 github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb github.com/blevesearch/bleve/v2 v2.5.7 github.com/bohde/codel v0.2.0 @@ -37,7 +37,7 @@ require ( github.com/charmbracelet/git-lfs-transfer v0.1.1-0.20251013092601-6327009efd21 github.com/chi-middleware/proxy v1.1.1 github.com/dimiro1/reply v0.0.0-20200315094148-d0136a4c9e21 - github.com/dlclark/regexp2 v1.11.5 + github.com/dlclark/regexp2 v1.12.0 github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707 github.com/dustin/go-humanize v1.0.1 github.com/editorconfig/editorconfig-core-go/v2 v2.6.4 @@ -49,14 +49,14 @@ require ( github.com/gliderlabs/ssh v0.3.8 github.com/go-chi/chi/v5 v5.2.5 github.com/go-chi/cors v1.2.2 - github.com/go-co-op/gocron/v2 v2.20.0 + github.com/go-co-op/gocron/v2 v2.21.0 github.com/go-enry/go-enry/v2 v2.9.6 github.com/go-git/go-billy/v5 v5.8.0 github.com/go-git/go-git/v5 v5.18.0 github.com/go-ldap/ldap/v3 v3.4.13 github.com/go-redsync/redsync/v4 v4.16.0 github.com/go-sql-driver/mysql v1.9.3 - github.com/go-webauthn/webauthn v0.16.4 + github.com/go-webauthn/webauthn v0.16.5 github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85 github.com/golang-jwt/jwt/v5 v5.3.1 @@ -139,10 +139,10 @@ require ( github.com/andybalholm/brotli v1.2.1 // indirect github.com/andybalholm/cascadia v1.3.3 // indirect github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect - github.com/aws/aws-sdk-go-v2 v1.41.5 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.21 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.21 // indirect - github.com/aws/smithy-go v1.24.2 // indirect + github.com/aws/aws-sdk-go-v2 v1.41.6 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.22 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.22 // indirect + github.com/aws/smithy-go v1.25.0 // indirect github.com/aymerick/douceur v0.2.0 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bits-and-blooms/bitset v1.24.4 // indirect @@ -258,7 +258,7 @@ require ( github.com/sorairolake/lzip-go v0.3.8 // indirect github.com/spf13/afero v1.15.0 // indirect github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect - github.com/tinylib/msgp v1.6.3 // indirect + github.com/tinylib/msgp v1.6.4 // indirect github.com/unknwon/com v1.0.1 // indirect github.com/x448/float16 v0.8.4 // indirect github.com/xanzy/ssh-agent v0.3.3 // indirect diff --git a/go.sum b/go.sum index 547c61d826c..0b65e6305ff 100644 --- a/go.sum +++ b/go.sum @@ -92,18 +92,18 @@ github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuW github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= -github.com/aws/aws-sdk-go-v2 v1.41.5 h1:dj5kopbwUsVUVFgO4Fi5BIT3t4WyqIDjGKCangnV/yY= -github.com/aws/aws-sdk-go-v2 v1.41.5/go.mod h1:mwsPRE8ceUUpiTgF7QmQIJ7lgsKUPQOUl3o72QBrE1o= -github.com/aws/aws-sdk-go-v2/credentials v1.19.14 h1:n+UcGWAIZHkXzYt87uMFBv/l8THYELoX6gVcUvgl6fI= -github.com/aws/aws-sdk-go-v2/credentials v1.19.14/go.mod h1:cJKuyWB59Mqi0jM3nFYQRmnHVQIcgoxjEMAbLkpr62w= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.21 h1:Rgg6wvjjtX8bNHcvi9OnXWwcE0a2vGpbwmtICOsvcf4= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.21/go.mod h1:A/kJFst/nm//cyqonihbdpQZwiUhhzpqTsdbhDdRF9c= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.21 h1:PEgGVtPoB6NTpPrBgqSE5hE/o47Ij9qk/SEZFbUOe9A= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.21/go.mod h1:p+hz+PRAYlY3zcpJhPwXlLC4C+kqn70WIHwnzAfs6ps= -github.com/aws/aws-sdk-go-v2/service/codecommit v1.33.12 h1:yv3mfWt/eiDTTry6fkN5hh8wHJfU5ygnw+DJp10C0/c= -github.com/aws/aws-sdk-go-v2/service/codecommit v1.33.12/go.mod h1:voO3LP/dZ4CTERiNWCz3DFLbK/8hbfeC1OJkLW+sang= -github.com/aws/smithy-go v1.24.2 h1:FzA3bu/nt/vDvmnkg+R8Xl46gmzEDam6mZ1hzmwXFng= -github.com/aws/smithy-go v1.24.2/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc= +github.com/aws/aws-sdk-go-v2 v1.41.6 h1:1AX0AthnBQzMx1vbmir3Y4WsnJgiydmnJjiLu+LvXOg= +github.com/aws/aws-sdk-go-v2 v1.41.6/go.mod h1:dy0UzBIfwSeot4grGvY1AqFWN5zgziMmWGzysDnHFcQ= +github.com/aws/aws-sdk-go-v2/credentials v1.19.15 h1:fyvgWTszojq8hEnMi8PPBTvZdTtEVmAVyo+NFLHBhH4= +github.com/aws/aws-sdk-go-v2/credentials v1.19.15/go.mod h1:gJiYyMOjNg8OEdRWOf3CrFQxM2a98qmrtjx1zuiQfB8= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.22 h1:GmLa5Kw1ESqtFpXsx5MmC84QWa/ZrLZvlJGa2y+4kcQ= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.22/go.mod h1:6sW9iWm9DK9YRpRGga/qzrzNLgKpT2cIxb7Vo2eNOp0= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.22 h1:dY4kWZiSaXIzxnKlj17nHnBcXXBfac6UlsAx2qL6XrU= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.22/go.mod h1:KIpEUx0JuRZLO7U6cbV204cWAEco2iC3l061IxlwLtI= +github.com/aws/aws-sdk-go-v2/service/codecommit v1.33.13 h1:IIW5QmNI9PrnDTBCPa75HcD0g+hoD/a+d388dbIAkEM= +github.com/aws/aws-sdk-go-v2/service/codecommit v1.33.13/go.mod h1:B1FUSufCQp3d8VUzob1EY+AdSo2OuEWNEY6GQff7EHA= +github.com/aws/smithy-go v1.25.0 h1:Sz/XJ64rwuiKtB6j98nDIPyYrV1nVNJ4YU74gttcl5U= +github.com/aws/smithy-go v1.25.0/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc= github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -239,8 +239,8 @@ github.com/dimiro1/reply v0.0.0-20200315094148-d0136a4c9e21/go.mod h1:xJvkyD6Y2r github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= -github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ= -github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= +github.com/dlclark/regexp2 v1.12.0 h1:0j4c5qQmnC6XOWNjP3PIXURXN2gWx76rd3KvgdPkCz8= +github.com/dlclark/regexp2 v1.12.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707 h1:2tV76y6Q9BB+NEBasnqvs7e49aEBFI8ejC89PSnWH+4= github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707/go.mod h1:qssHWj60/X5sZFNxpG4HBPDHVqxNm4DfnCKgrbZOT+s= github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY= @@ -288,8 +288,8 @@ github.com/go-chi/chi/v5 v5.2.5 h1:Eg4myHZBjyvJmAFjFvWgrqDTXFyOzjj7YIm3L3mu6Ug= github.com/go-chi/chi/v5 v5.2.5/go.mod h1:X7Gx4mteadT3eDOMTsXzmI4/rwUpOwBHLpAfupzFJP0= github.com/go-chi/cors v1.2.2 h1:Jmey33TE+b+rB7fT8MUy1u0I4L+NARQlK6LhzKPSyQE= github.com/go-chi/cors v1.2.2/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58= -github.com/go-co-op/gocron/v2 v2.20.0 h1:9IMrnnVSWjfSh3E54gWmWCHbloQJLh6f9+nwyKfLNpc= -github.com/go-co-op/gocron/v2 v2.20.0/go.mod h1:5lEiCKk1oVJV39Zg7/YG10OnaVrDAV5GGR6O0663k6U= +github.com/go-co-op/gocron/v2 v2.21.0 h1:e1nt9AEFglarRH9/9y9q0V5sblwxlknpHPjttEajrwQ= +github.com/go-co-op/gocron/v2 v2.21.0/go.mod h1:5lEiCKk1oVJV39Zg7/YG10OnaVrDAV5GGR6O0663k6U= github.com/go-enry/go-enry/v2 v2.9.6 h1:np63eOtMV56zfYDHnFVgpEVOk8fr2kmylcMnAZUDbSs= github.com/go-enry/go-enry/v2 v2.9.6/go.mod h1:9yrj4ES1YrbNb1Wb7/PWYr2bpaCXUGRt0uafN0ISyG8= github.com/go-enry/go-oniguruma v1.2.1 h1:k8aAMuJfMrqm/56SG2lV9Cfti6tC4x8673aHCcBk+eo= @@ -325,8 +325,8 @@ github.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U= github.com/go-test/deep v1.1.1/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro= github.com/go-viper/mapstructure/v2 v2.5.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= -github.com/go-webauthn/webauthn v0.16.4 h1:R9jqR/cYZa7hRquFF7Za/8qoH/K/TIs1/Q/4CyGN+1Q= -github.com/go-webauthn/webauthn v0.16.4/go.mod h1:SU2ljAgToTV/YLPI0C05QS4qn+e04WpB5g1RMfcZfS4= +github.com/go-webauthn/webauthn v0.16.5 h1:x+vADHlaiIjta23kGhtwyCIlB5mayKx6SBlpwQ5NF9A= +github.com/go-webauthn/webauthn v0.16.5/go.mod h1:mQC6L0lZ5Kiu35G70zeB2WnrW4+vbHjR8Koq4HdVaMg= github.com/go-webauthn/x v0.2.3 h1:8oArS+Rc1SWFLXhE17KZNx258Z4kUSyaDgsSncCO5RA= github.com/go-webauthn/x v0.2.3/go.mod h1:tM04GF3V6VYq79AZMl7vbj4q6pz9r7L2criWRzbWhPk= github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM= @@ -695,8 +695,8 @@ github.com/stvp/tempredis v0.0.0-20181119212430-b82af8480203/go.mod h1:oqN97ltKN github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE= github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= github.com/tinylib/msgp v1.1.0/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= -github.com/tinylib/msgp v1.6.3 h1:bCSxiTz386UTgyT1i0MSCvdbWjVW+8sG3PjkGsZQt4s= -github.com/tinylib/msgp v1.6.3/go.mod h1:RSp0LW9oSxFut3KzESt5Voq4GVWyS+PSulT77roAqEA= +github.com/tinylib/msgp v1.6.4 h1:mOwYbyYDLPj35mkA2BjjYejgJk9BuHxDdvRnb6v2ZcQ= +github.com/tinylib/msgp v1.6.4/go.mod h1:RSp0LW9oSxFut3KzESt5Voq4GVWyS+PSulT77roAqEA= github.com/tstranex/u2f v1.0.0 h1:HhJkSzDDlVSVIVt7pDJwCHQj67k7A5EeBgPmeD+pVsQ= github.com/tstranex/u2f v1.0.0/go.mod h1:eahSLaqAS0zsIEv80+vXT7WanXs7MQQDg3j3wGBSayo= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= diff --git a/package.json b/package.json index 9dcbf411d38..9a458e4b49d 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "@codemirror/lint": "6.9.5", "@codemirror/search": "6.6.0", "@codemirror/state": "6.6.0", - "@codemirror/view": "6.41.0", + "@codemirror/view": "6.41.1", "@deltablot/dropzone": "7.4.3", "@github/markdown-toolbar-element": "2.2.3", "@github/paste-markdown": "1.5.3", @@ -28,7 +28,7 @@ "@lezer/highlight": "1.2.3", "@mcaptcha/vanilla-glue": "0.1.0-alpha-3", "@mermaid-js/layout-elk": "0.2.1", - "@primer/octicons": "19.24.0", + "@primer/octicons": "19.24.1", "@replit/codemirror-indentation-markers": "6.5.3", "@replit/codemirror-lang-nix": "6.0.1", "@replit/codemirror-lang-svelte": "6.0.0", @@ -40,7 +40,7 @@ "chart.js": "4.5.1", "chartjs-adapter-dayjs-4": "1.0.4", "chartjs-plugin-zoom": "2.2.0", - "clippie": "4.1.10", + "clippie": "4.1.14", "codemirror-lang-elixir": "4.0.1", "colord": "2.9.3", "compare-versions": "6.1.1", @@ -56,10 +56,10 @@ "online-3d-viewer": "0.18.0", "pdfobject": "2.3.1", "perfect-debounce": "2.1.0", - "postcss": "8.5.9", - "rolldown-license-plugin": "2.2.5", + "postcss": "8.5.10", + "rolldown-license-plugin": "3.0.1", "sortablejs": "1.15.7", - "swagger-ui-dist": "5.32.2", + "swagger-ui-dist": "5.32.4", "tailwindcss": "3.4.19", "throttle-debounce": "5.0.2", "tippy.js": "6.3.7", @@ -67,7 +67,7 @@ "tributejs": "5.1.3", "uint8-to-base64": "0.2.1", "vanilla-colorful": "0.7.2", - "vite": "8.0.8", + "vite": "8.0.9", "vite-string-plugin": "2.0.2", "vue": "3.5.32", "vue-bar-graph": "2.2.0", @@ -89,41 +89,41 @@ "@types/swagger-ui-dist": "3.30.6", "@types/throttle-debounce": "5.0.2", "@types/toastify-js": "1.12.4", - "@typescript-eslint/parser": "8.58.2", + "@typescript-eslint/parser": "8.59.0", "@vitejs/plugin-vue": "6.0.6", - "@vitest/eslint-plugin": "1.6.15", - "eslint": "10.2.0", + "@vitest/eslint-plugin": "1.6.16", + "eslint": "10.2.1", "eslint-import-resolver-typescript": "4.4.4", "eslint-plugin-array-func": "5.1.1", "eslint-plugin-de-morgan": "2.1.1", "eslint-plugin-github": "6.0.0", "eslint-plugin-import-x": "4.16.2", - "eslint-plugin-playwright": "2.10.1", + "eslint-plugin-playwright": "2.10.2", "eslint-plugin-regexp": "3.1.0", - "eslint-plugin-sonarjs": "4.0.2", + "eslint-plugin-sonarjs": "4.0.3", "eslint-plugin-unicorn": "64.0.0", "eslint-plugin-vue": "10.8.0", "eslint-plugin-vue-scoped-css": "3.0.0", "eslint-plugin-wc": "3.1.0", "globals": "17.5.0", - "happy-dom": "20.8.9", + "happy-dom": "20.9.0", "jiti": "2.6.1", "markdownlint-cli": "0.48.0", "material-icon-theme": "5.33.1", "nolyfill": "1.0.44", "postcss-html": "1.8.1", "spectral-cli-bundle": "1.0.7", - "stylelint": "17.7.0", + "stylelint": "17.8.0", "stylelint-config-recommended": "18.0.0", "stylelint-declaration-block-no-ignored-properties": "3.0.0", "stylelint-declaration-strict-value": "1.11.1", "stylelint-value-no-unknown-custom-properties": "6.1.1", "svgo": "4.0.1", - "typescript": "6.0.2", - "typescript-eslint": "8.58.2", - "updates": "17.15.3", + "typescript": "6.0.3", + "typescript-eslint": "8.59.0", + "updates": "17.15.5", "vitest": "4.1.4", - "vue-tsc": "3.2.6" + "vue-tsc": "3.2.7" }, "pnpm": { "peerDependencyRules": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index fdc569187a5..bd51102345f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -71,8 +71,8 @@ importers: specifier: 6.6.0 version: 6.6.0 '@codemirror/view': - specifier: 6.41.0 - version: 6.41.0 + specifier: 6.41.1 + version: 6.41.1 '@deltablot/dropzone': specifier: 7.4.3 version: 7.4.3 @@ -95,26 +95,26 @@ importers: specifier: 0.2.1 version: 0.2.1(mermaid@11.14.0) '@primer/octicons': - specifier: 19.24.0 - version: 19.24.0 + specifier: 19.24.1 + version: 19.24.1 '@replit/codemirror-indentation-markers': specifier: 6.5.3 - version: 6.5.3(@codemirror/language@6.12.3)(@codemirror/state@6.6.0)(@codemirror/view@6.41.0) + version: 6.5.3(@codemirror/language@6.12.3)(@codemirror/state@6.6.0)(@codemirror/view@6.41.1) '@replit/codemirror-lang-nix': specifier: 6.0.1 - version: 6.0.1(@codemirror/autocomplete@6.20.1)(@codemirror/language@6.12.3)(@codemirror/state@6.6.0)(@codemirror/view@6.41.0)(@lezer/common@1.5.2)(@lezer/highlight@1.2.3)(@lezer/lr@1.4.8) + version: 6.0.1(@codemirror/autocomplete@6.20.1)(@codemirror/language@6.12.3)(@codemirror/state@6.6.0)(@codemirror/view@6.41.1)(@lezer/common@1.5.2)(@lezer/highlight@1.2.3)(@lezer/lr@1.4.10) '@replit/codemirror-lang-svelte': specifier: 6.0.0 - version: 6.0.0(@codemirror/autocomplete@6.20.1)(@codemirror/lang-css@6.3.1)(@codemirror/lang-html@6.4.11)(@codemirror/lang-javascript@6.2.5)(@codemirror/language@6.12.3)(@codemirror/state@6.6.0)(@codemirror/view@6.41.0)(@lezer/common@1.5.2)(@lezer/highlight@1.2.3)(@lezer/javascript@1.5.4)(@lezer/lr@1.4.8) + version: 6.0.0(@codemirror/autocomplete@6.20.1)(@codemirror/lang-css@6.3.1)(@codemirror/lang-html@6.4.11)(@codemirror/lang-javascript@6.2.5)(@codemirror/language@6.12.3)(@codemirror/state@6.6.0)(@codemirror/view@6.41.1)(@lezer/common@1.5.2)(@lezer/highlight@1.2.3)(@lezer/javascript@1.5.4)(@lezer/lr@1.4.10) '@replit/codemirror-vscode-keymap': specifier: 6.0.2 - version: 6.0.2(@codemirror/autocomplete@6.20.1)(@codemirror/commands@6.10.3)(@codemirror/language@6.12.3)(@codemirror/lint@6.9.5)(@codemirror/search@6.6.0)(@codemirror/state@6.6.0)(@codemirror/view@6.41.0) + version: 6.0.2(@codemirror/autocomplete@6.20.1)(@codemirror/commands@6.10.3)(@codemirror/language@6.12.3)(@codemirror/lint@6.9.5)(@codemirror/search@6.6.0)(@codemirror/state@6.6.0)(@codemirror/view@6.41.1) '@resvg/resvg-wasm': specifier: 2.6.2 version: 2.6.2 '@vitejs/plugin-vue': specifier: 6.0.6 - version: 6.0.6(vite@8.0.8(@types/node@25.6.0)(esbuild@0.28.0)(jiti@2.6.1))(vue@3.5.32(typescript@6.0.2)) + version: 6.0.6(vite@8.0.9(@types/node@25.6.0)(esbuild@0.28.0)(jiti@2.6.1))(vue@3.5.32(typescript@6.0.3)) ansi_up: specifier: 6.0.6 version: 6.0.6 @@ -131,8 +131,8 @@ importers: specifier: 2.2.0 version: 2.2.0(chart.js@4.5.1) clippie: - specifier: 4.1.10 - version: 4.1.10 + specifier: 4.1.14 + version: 4.1.14 codemirror-lang-elixir: specifier: 4.0.1 version: 4.0.1 @@ -179,17 +179,17 @@ importers: specifier: 2.1.0 version: 2.1.0 postcss: - specifier: 8.5.9 - version: 8.5.9 + specifier: 8.5.10 + version: 8.5.10 rolldown-license-plugin: - specifier: 2.2.5 - version: 2.2.5(rolldown@1.0.0-rc.15) + specifier: 3.0.1 + version: 3.0.1(rolldown@1.0.0-rc.16) sortablejs: specifier: 1.15.7 version: 1.15.7 swagger-ui-dist: - specifier: 5.32.2 - version: 5.32.2 + specifier: 5.32.4 + version: 5.32.4 tailwindcss: specifier: 3.4.19 version: 3.4.19 @@ -212,24 +212,24 @@ importers: specifier: 0.7.2 version: 0.7.2 vite: - specifier: 8.0.8 - version: 8.0.8(@types/node@25.6.0)(esbuild@0.28.0)(jiti@2.6.1) + specifier: 8.0.9 + version: 8.0.9(@types/node@25.6.0)(esbuild@0.28.0)(jiti@2.6.1) vite-string-plugin: specifier: 2.0.2 - version: 2.0.2(vite@8.0.8(@types/node@25.6.0)(esbuild@0.28.0)(jiti@2.6.1)) + version: 2.0.2(vite@8.0.9(@types/node@25.6.0)(esbuild@0.28.0)(jiti@2.6.1)) vue: specifier: 3.5.32 - version: 3.5.32(typescript@6.0.2) + version: 3.5.32(typescript@6.0.3) vue-bar-graph: specifier: 2.2.0 - version: 2.2.0(typescript@6.0.2) + version: 2.2.0(typescript@6.0.3) vue-chartjs: specifier: 5.3.3 - version: 5.3.3(chart.js@4.5.1)(vue@3.5.32(typescript@6.0.2)) + version: 5.3.3(chart.js@4.5.1)(vue@3.5.32(typescript@6.0.3)) devDependencies: '@eslint-community/eslint-plugin-eslint-comments': specifier: 4.7.1 - version: 4.7.1(eslint@10.2.0(jiti@2.6.1)) + version: 4.7.1(eslint@10.2.1(jiti@2.6.1)) '@eslint/json': specifier: 1.2.0 version: 1.2.0 @@ -238,10 +238,10 @@ importers: version: 1.59.1 '@stylistic/eslint-plugin': specifier: 5.10.0 - version: 5.10.0(eslint@10.2.0(jiti@2.6.1)) + version: 5.10.0(eslint@10.2.1(jiti@2.6.1)) '@stylistic/stylelint-plugin': specifier: 5.1.0 - version: 5.1.0(stylelint@17.7.0(typescript@6.0.2)) + version: 5.1.0(stylelint@17.8.0(typescript@6.0.3)) '@types/codemirror': specifier: 5.60.17 version: 5.60.17 @@ -273,56 +273,56 @@ importers: specifier: 1.12.4 version: 1.12.4 '@typescript-eslint/parser': - specifier: 8.58.2 - version: 8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2) + specifier: 8.59.0 + version: 8.59.0(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3) '@vitest/eslint-plugin': - specifier: 1.6.15 - version: 1.6.15(@typescript-eslint/eslint-plugin@8.58.2(@typescript-eslint/parser@8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2))(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2))(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2)(vitest@4.1.4(@types/node@25.6.0)(happy-dom@20.8.9)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.28.0)(jiti@2.6.1))) + specifier: 1.6.16 + version: 1.6.16(@typescript-eslint/eslint-plugin@8.59.0(@typescript-eslint/parser@8.59.0(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3))(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3))(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3)(vitest@4.1.4(@types/node@25.6.0)(happy-dom@20.9.0)(vite@8.0.9(@types/node@25.6.0)(esbuild@0.28.0)(jiti@2.6.1))) eslint: - specifier: 10.2.0 - version: 10.2.0(jiti@2.6.1) + specifier: 10.2.1 + version: 10.2.1(jiti@2.6.1) eslint-import-resolver-typescript: specifier: 4.4.4 - version: 4.4.4(eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2))(eslint-import-resolver-node@0.3.10)(eslint@10.2.0(jiti@2.6.1)))(eslint-plugin-import@2.32.0)(eslint@10.2.0(jiti@2.6.1)) + version: 4.4.4(eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.59.0(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint@10.2.1(jiti@2.6.1)))(eslint-plugin-import@2.32.0)(eslint@10.2.1(jiti@2.6.1)) eslint-plugin-array-func: specifier: 5.1.1 - version: 5.1.1(eslint@10.2.0(jiti@2.6.1)) + version: 5.1.1(eslint@10.2.1(jiti@2.6.1)) eslint-plugin-de-morgan: specifier: 2.1.1 - version: 2.1.1(eslint@10.2.0(jiti@2.6.1)) + version: 2.1.1(eslint@10.2.1(jiti@2.6.1)) eslint-plugin-github: specifier: 6.0.0 - version: 6.0.0(eslint-import-resolver-typescript@4.4.4)(eslint@10.2.0(jiti@2.6.1)) + version: 6.0.0(eslint-import-resolver-typescript@4.4.4)(eslint@10.2.1(jiti@2.6.1)) eslint-plugin-import-x: specifier: 4.16.2 - version: 4.16.2(@typescript-eslint/utils@8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2))(eslint-import-resolver-node@0.3.10)(eslint@10.2.0(jiti@2.6.1)) + version: 4.16.2(@typescript-eslint/utils@8.59.0(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint@10.2.1(jiti@2.6.1)) eslint-plugin-playwright: - specifier: 2.10.1 - version: 2.10.1(eslint@10.2.0(jiti@2.6.1)) + specifier: 2.10.2 + version: 2.10.2(eslint@10.2.1(jiti@2.6.1)) eslint-plugin-regexp: specifier: 3.1.0 - version: 3.1.0(eslint@10.2.0(jiti@2.6.1)) + version: 3.1.0(eslint@10.2.1(jiti@2.6.1)) eslint-plugin-sonarjs: - specifier: 4.0.2 - version: 4.0.2(eslint@10.2.0(jiti@2.6.1)) + specifier: 4.0.3 + version: 4.0.3(eslint@10.2.1(jiti@2.6.1)) eslint-plugin-unicorn: specifier: 64.0.0 - version: 64.0.0(eslint@10.2.0(jiti@2.6.1)) + version: 64.0.0(eslint@10.2.1(jiti@2.6.1)) eslint-plugin-vue: specifier: 10.8.0 - version: 10.8.0(@stylistic/eslint-plugin@5.10.0(eslint@10.2.0(jiti@2.6.1)))(@typescript-eslint/parser@8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2))(eslint@10.2.0(jiti@2.6.1))(vue-eslint-parser@10.4.0(eslint@10.2.0(jiti@2.6.1))) + version: 10.8.0(@stylistic/eslint-plugin@5.10.0(eslint@10.2.1(jiti@2.6.1)))(@typescript-eslint/parser@8.59.0(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3))(eslint@10.2.1(jiti@2.6.1))(vue-eslint-parser@10.4.0(eslint@10.2.1(jiti@2.6.1))) eslint-plugin-vue-scoped-css: specifier: 3.0.0 - version: 3.0.0(eslint@10.2.0(jiti@2.6.1))(vue-eslint-parser@10.4.0(eslint@10.2.0(jiti@2.6.1))) + version: 3.0.0(eslint@10.2.1(jiti@2.6.1))(vue-eslint-parser@10.4.0(eslint@10.2.1(jiti@2.6.1))) eslint-plugin-wc: specifier: 3.1.0 - version: 3.1.0(eslint@10.2.0(jiti@2.6.1)) + version: 3.1.0(eslint@10.2.1(jiti@2.6.1)) globals: specifier: 17.5.0 version: 17.5.0 happy-dom: - specifier: 20.8.9 - version: 20.8.9 + specifier: 20.9.0 + version: 20.9.0 jiti: specifier: 2.6.1 version: 2.6.1 @@ -342,38 +342,38 @@ importers: specifier: 1.0.7 version: 1.0.7 stylelint: - specifier: 17.7.0 - version: 17.7.0(typescript@6.0.2) + specifier: 17.8.0 + version: 17.8.0(typescript@6.0.3) stylelint-config-recommended: specifier: 18.0.0 - version: 18.0.0(stylelint@17.7.0(typescript@6.0.2)) + version: 18.0.0(stylelint@17.8.0(typescript@6.0.3)) stylelint-declaration-block-no-ignored-properties: specifier: 3.0.0 - version: 3.0.0(stylelint@17.7.0(typescript@6.0.2)) + version: 3.0.0(stylelint@17.8.0(typescript@6.0.3)) stylelint-declaration-strict-value: specifier: 1.11.1 - version: 1.11.1(stylelint@17.7.0(typescript@6.0.2)) + version: 1.11.1(stylelint@17.8.0(typescript@6.0.3)) stylelint-value-no-unknown-custom-properties: specifier: 6.1.1 - version: 6.1.1(stylelint@17.7.0(typescript@6.0.2)) + version: 6.1.1(stylelint@17.8.0(typescript@6.0.3)) svgo: specifier: 4.0.1 version: 4.0.1 typescript: - specifier: 6.0.2 - version: 6.0.2 + specifier: 6.0.3 + version: 6.0.3 typescript-eslint: - specifier: 8.58.2 - version: 8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2) + specifier: 8.59.0 + version: 8.59.0(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3) updates: - specifier: 17.15.3 - version: 17.15.3 + specifier: 17.15.5 + version: 17.15.5 vitest: specifier: 4.1.4 - version: 4.1.4(@types/node@25.6.0)(happy-dom@20.8.9)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.28.0)(jiti@2.6.1)) + version: 4.1.4(@types/node@25.6.0)(happy-dom@20.9.0)(vite@8.0.9(@types/node@25.6.0)(esbuild@0.28.0)(jiti@2.6.1)) vue-tsc: - specifier: 3.2.6 - version: 3.2.6(typescript@6.0.2) + specifier: 3.2.7 + version: 3.2.7(typescript@6.0.3) packages: @@ -508,8 +508,8 @@ packages: '@codemirror/lang-javascript@6.2.5': resolution: {integrity: sha512-zD4e5mS+50htS7F+TYjBPsiIFGanfVqg4HyUz6WNFikgOPf2BgKlx+TQedI1w6n/IqRBVBbBWmGFdLB/7uxO4A==} - '@codemirror/lang-jinja@6.0.0': - resolution: {integrity: sha512-47MFmRcR8UAxd8DReVgj7WJN1WSAMT7OJnewwugZM4XiHWkOjgJQqvEM1NpMj9ALMPyxmlziEI1opH9IaEvmaw==} + '@codemirror/lang-jinja@6.0.1': + resolution: {integrity: sha512-P5kyHLObzjtbGj16h+hyvZTxJhSjBEeSx4wMjbnAf3b0uwTy2+F0zGjMZL4PQOm/mh2eGZ5xUDVZXgwP783Nsw==} '@codemirror/lang-json@6.0.2': resolution: {integrity: sha512-x2OtO+AvwEHrEwR0FyyPtfDUiloG3rnVTSZV1W8UteaLL8/MajQd8DpvUb2YVzC+/T18aSDv0H9mu+xw0EStoQ==} @@ -568,8 +568,8 @@ packages: '@codemirror/state@6.6.0': resolution: {integrity: sha512-4nbvra5R5EtiCzr9BTHiTLc+MLXK2QGiAVYMyi8PkQd3SR+6ixar/Q/01Fa21TBIDOZXgeWV4WppsQolSreAPQ==} - '@codemirror/view@6.41.0': - resolution: {integrity: sha512-6H/qadXsVuDY219Yljhohglve8xf4B8xJkVOEWfA5uiYKiTFppjqsvsfR5iPA0RbvRBoOyTZpbLIxe9+0UR8xA==} + '@codemirror/view@6.41.1': + resolution: {integrity: sha512-ToDnWKbBnke+ZLrP6vgTTDScGi5H37YYuZGniQaBzxMVdtCxMrslsmtnOvbPZk4RX9bvkQqnWR/WS/35tJA0qg==} '@csstools/css-calc@3.2.0': resolution: {integrity: sha512-bR9e6o2BDB12jzN/gIbjHa5wLJ4UjD1CB9pM7ehlc0ddk6EBz+yYS1EV2MF55/HUxrHcB/hehAyt5vhsA3hx7w==} @@ -618,9 +618,15 @@ packages: '@deltablot/dropzone@7.4.3': resolution: {integrity: sha512-qTj4KEalPcYrocazuKYfhAS3hfgAu17KXw0DkpUj71Aw9E1/x5vTSNK5hvIJLkbpt/pBECU18JkjA3yguONcPA==} + '@emnapi/core@1.10.0': + resolution: {integrity: sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==} + '@emnapi/core@1.9.2': resolution: {integrity: sha512-UC+ZhH3XtczQYfOlu3lNEkdW/p4dsJ1r/bP7H8+rhao3TTTMO1ATq/4DdIi23XuGoFY+Cz0JmCbdVl0hz9jZcA==} + '@emnapi/runtime@1.10.0': + resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==} + '@emnapi/runtime@1.9.2': resolution: {integrity: sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw==} @@ -863,12 +869,16 @@ packages: '@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==} + '@humanfs/core@0.19.2': + resolution: {integrity: sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==} engines: {node: '>=18.18.0'} - '@humanfs/node@0.16.7': - resolution: {integrity: sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==} + '@humanfs/node@0.16.8': + resolution: {integrity: sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==} + engines: {node: '>=18.18.0'} + + '@humanfs/types@0.15.0': + resolution: {integrity: sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==} engines: {node: '>=18.18.0'} '@humanwhocodes/module-importer@1.0.1': @@ -941,8 +951,8 @@ packages: '@lezer/json@1.0.3': resolution: {integrity: sha512-BP9KzdF9Y35PDpv04r0VeSTKDeox5vVr3efE7eBbx3r4s3oNLfunchejZhjArmeieBH+nVOpgIiBJpEAv8ilqQ==} - '@lezer/lr@1.4.8': - resolution: {integrity: sha512-bPWa0Pgx69ylNlMlPvBPryqeLYQjyJjqPx+Aupm5zydLIF3NE+6MMLT8Yi23Bd9cif9VS00aUebn+6fDIGBcDA==} + '@lezer/lr@1.4.10': + resolution: {integrity: sha512-rnCpTIBafOx4mRp43xOxDJbFipJm/c0cia/V5TiGlhmMa+wsSdoGmUN3w5Bqrks/09Q/D4tNAmWaT8p6NRi77A==} '@lezer/markdown@1.6.3': resolution: {integrity: sha512-jpGm5Ps+XErS+xA4urw7ogEGkeZOahVQF21Z6oECF0sj+2liwZopd2+I8uH5I/vZsRuuze3OxBREIANLf6KKUw==} @@ -985,8 +995,8 @@ packages: '@napi-rs/wasm-runtime@0.2.12': resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} - '@napi-rs/wasm-runtime@1.1.3': - resolution: {integrity: sha512-xK9sGVbJWYb08+mTJt3/YV24WxvxpXcXtP6B172paPZ+Ts69Re9dAr7lKwJoeIx8OoeuimEiRZ7umkiUVClmmQ==} + '@napi-rs/wasm-runtime@1.1.4': + resolution: {integrity: sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==} peerDependencies: '@emnapi/core': ^1.7.1 '@emnapi/runtime': ^1.7.1 @@ -1070,8 +1080,8 @@ packages: resolution: {integrity: sha512-3dsKlf4Ma7o+uxLIg5OI1Tgwfet2pE8WTbPjEGWvOe6CSjMtK0skJnnSVHaEVX4N4mYU81To0qDeZOPqjaUotg==} engines: {node: '>=12.4.0'} - '@oxc-project/types@0.124.0': - resolution: {integrity: sha512-VBFWMTBvHxS11Z5Lvlr3IWgrwhMTXV+Md+EQF0Xf60+wAdsGFTBx7X7K/hP4pi8N7dcm1RvcHwDxZ16Qx8keUg==} + '@oxc-project/types@0.126.0': + resolution: {integrity: sha512-oGfVtjAgwQVVpfBrbtk4e1XDyWHRFta6BS3GWVzrF8xYBT2VGQAk39yJS/wFSMrZqoiCU4oghT3Ch0HaHGIHcQ==} '@package-json/types@0.0.12': resolution: {integrity: sha512-uu43FGU34B5VM9mCNjXCwLaGHYjXdNincqKLaraaCW+7S2+SmiBg1Nv8bPnmschrIfZmfKNY9f3fC376MRrObw==} @@ -1088,8 +1098,8 @@ packages: '@popperjs/core@2.11.8': resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==} - '@primer/octicons@19.24.0': - resolution: {integrity: sha512-OS+8ip2nqrdd6nv6bXROgTFm/nsmZJQ/ExqaYnq80h5Zlz3+gxEtKQl2Zi/AshnhHztF7ErPe//Osbj6ZfwQLQ==} + '@primer/octicons@19.24.1': + resolution: {integrity: sha512-vgtSHq8IIf3oo/HjPGj0B7NkeatSyyw5mupMjXByPI1gY6uRZ/UQdv7uSJnSOCJYQJF3lVDUwiwp9wM71MYIgA==} '@replit/codemirror-indentation-markers@6.5.3': resolution: {integrity: sha512-hL5Sfvw3C1vgg7GolLe/uxX5T3tmgOA3ZzqlMv47zjU1ON51pzNWiVbS22oh6crYhtVhv8b3gdXwoYp++2ilHw==} @@ -1139,97 +1149,97 @@ packages: resolution: {integrity: sha512-FqALmHI8D4o6lk/LRWDnhw95z5eO+eAa6ORjVg09YRR7BkcM6oPHU9uyC0gtQG5vpFLvgpeU4+zEAz2H8APHNw==} engines: {node: '>= 10'} - '@rolldown/binding-android-arm64@1.0.0-rc.15': - resolution: {integrity: sha512-YYe6aWruPZDtHNpwu7+qAHEMbQ/yRl6atqb/AhznLTnD3UY99Q1jE7ihLSahNWkF4EqRPVC4SiR4O0UkLK02tA==} + '@rolldown/binding-android-arm64@1.0.0-rc.16': + resolution: {integrity: sha512-rhY3k7Bsae9qQfOtph2Pm2jZEA+s8Gmjoz4hhmx70K9iMQ/ddeae+xhRQcM5IuVx5ry1+bGfkvMn7D6MJggVSA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@rolldown/binding-darwin-arm64@1.0.0-rc.15': - resolution: {integrity: sha512-oArR/ig8wNTPYsXL+Mzhs0oxhxfuHRfG7Ikw7jXsw8mYOtk71W0OkF2VEVh699pdmzjPQsTjlD1JIOoHkLP1Fg==} + '@rolldown/binding-darwin-arm64@1.0.0-rc.16': + resolution: {integrity: sha512-rNz0yK078yrNn3DrdgN+PKiMOW8HfQ92jQiXxwX8yW899ayV00MLVdaCNeVBhG/TbH3ouYVObo8/yrkiectkcQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@rolldown/binding-darwin-x64@1.0.0-rc.15': - resolution: {integrity: sha512-YzeVqOqjPYvUbJSWJ4EDL8ahbmsIXQpgL3JVipmN+MX0XnXMeWomLN3Fb+nwCmP/jfyqte5I3XRSm7OfQrbyxw==} + '@rolldown/binding-darwin-x64@1.0.0-rc.16': + resolution: {integrity: sha512-r/OmdR00HmD4i79Z//xO06uEPOq5hRXdhw7nzkxQxwSavs3PSHa1ijntdpOiZ2mzOQ3fVVu8C1M19FoNM+dMUQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@rolldown/binding-freebsd-x64@1.0.0-rc.15': - resolution: {integrity: sha512-9Erhx956jeQ0nNTyif1+QWAXDRD38ZNjr//bSHrt6wDwB+QkAfl2q6Mn1k6OBPerznjRmbM10lgRb1Pli4xZPw==} + '@rolldown/binding-freebsd-x64@1.0.0-rc.16': + resolution: {integrity: sha512-KcRE5w8h0OnjUatG8pldyD14/CQ5Phs1oxfR+3pKDjboHRo9+MkqQaiIZlZRpsxC15paeXme/I127tUa9TXJ6g==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.15': - resolution: {integrity: sha512-cVwk0w8QbZJGTnP/AHQBs5yNwmpgGYStL88t4UIaqcvYJWBfS0s3oqVLZPwsPU6M0zlW4GqjP0Zq5MnAGwFeGA==} + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.16': + resolution: {integrity: sha512-bT0guA1bpxEJ/ZhTRniQf7rNF8ybvXOuWbNIeLABaV5NGjx4EtOWBTSRGWFU9ZWVkPOZ+HNFP8RMcBokBiZ0Kg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.15': - resolution: {integrity: sha512-eBZ/u8iAK9SoHGanqe/jrPnY0JvBN6iXbVOsbO38mbz+ZJsaobExAm1Iu+rxa4S1l2FjG0qEZn4Rc6X8n+9M+w==} + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.16': + resolution: {integrity: sha512-+tHktCHWV8BDQSjemUqm/Jl/TPk3QObCTIjmdDy/nlupcujZghmKK2962LYrqFpWu+ai01AN/REOH3NEpqvYQg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-arm64-musl@1.0.0-rc.15': - resolution: {integrity: sha512-ZvRYMGrAklV9PEkgt4LQM6MjQX2P58HPAuecwYObY2DhS2t35R0I810bKi0wmaYORt6m/2Sm+Z+nFgb0WhXNcQ==} + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.16': + resolution: {integrity: sha512-3fPzdREH806oRLxpTWW1Gt4tQHs0TitZFOECB2xzCFLPKnSOy90gwA7P29cksYilFO6XVRY1kzga0cL2nRjKPg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [musl] - '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.15': - resolution: {integrity: sha512-VDpgGBzgfg5hLg+uBpCLoFG5kVvEyafmfxGUV0UHLcL5irxAK7PKNeC2MwClgk6ZAiNhmo9FLhRYgvMmedLtnQ==} + '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.16': + resolution: {integrity: sha512-EKwI1tSrLs7YVw+JPJT/G2dJQ1jl9qlTTTEG0V2Ok/RdOenRfBw2PQdLPyjhIu58ocdBfP7vIRN/pvMsPxs/AQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.15': - resolution: {integrity: sha512-y1uXY3qQWCzcPgRJATPSOUP4tCemh4uBdY7e3EZbVwCJTY3gLJWnQABgeUetvED+bt1FQ01OeZwvhLS2bpNrAQ==} + '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.16': + resolution: {integrity: sha512-Uknladnb3Sxqu6SEcqBldQyJUpk8NleooZEc0MbRBJ4inEhRYWZX0NJu12vNf2mqAq7gsofAxHrGghiUYjhaLQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] libc: [glibc] - '@rolldown/binding-linux-x64-gnu@1.0.0-rc.15': - resolution: {integrity: sha512-023bTPBod7J3Y/4fzAN6QtpkSABR0rigtrwaP+qSEabUh5zf6ELr9Nc7GujaROuPY3uwdSIXWrvhn1KxOvurWA==} + '@rolldown/binding-linux-x64-gnu@1.0.0-rc.16': + resolution: {integrity: sha512-FIb8+uG49sZBtLTn+zt1AJ20TqVcqWeSIyoVt0or7uAWesgKaHbiBh6OpA/k9v0LTt+PTrb1Lao133kP4uVxkg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-x64-musl@1.0.0-rc.15': - resolution: {integrity: sha512-witB2O0/hU4CgfOOKUoeFgQ4GktPi1eEbAhaLAIpgD6+ZnhcPkUtPsoKKHRzmOoWPZue46IThdSgdo4XneOLYw==} + '@rolldown/binding-linux-x64-musl@1.0.0-rc.16': + resolution: {integrity: sha512-RuERhF9/EgWxZEXYWCOaViUWHIboceK4/ivdtQ3R0T44NjLkIIlGIAVAuCddFxsZ7vnRHtNQUrt2vR2n2slB2w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [musl] - '@rolldown/binding-openharmony-arm64@1.0.0-rc.15': - resolution: {integrity: sha512-UCL68NJ0Ud5zRipXZE9dF5PmirzJE4E4BCIOOssEnM7wLDsxjc6Qb0sGDxTNRTP53I6MZpygyCpY8Aa8sPfKPg==} + '@rolldown/binding-openharmony-arm64@1.0.0-rc.16': + resolution: {integrity: sha512-mXcXnvd9GpazCxeUCCnZ2+YF7nut+ZOEbE4GtaiPtyY6AkhZWbK70y1KK3j+RDhjVq5+U8FySkKRb/+w0EeUwA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - '@rolldown/binding-wasm32-wasi@1.0.0-rc.15': - resolution: {integrity: sha512-ApLruZq/ig+nhaE7OJm4lDjayUnOHVUa77zGeqnqZ9pn0ovdVbbNPerVibLXDmWeUZXjIYIT8V3xkT58Rm9u5Q==} - engines: {node: '>=14.0.0'} + '@rolldown/binding-wasm32-wasi@1.0.0-rc.16': + resolution: {integrity: sha512-3Q2KQxnC8IJOLqXmUMoYwyIPZU9hzRbnHaoV3Euz+VVnjZKcY8ktnNP8T9R4/GGQtb27C/UYKABxesKWb8lsvQ==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [wasm32] - '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.15': - resolution: {integrity: sha512-KmoUoU7HnN+Si5YWJigfTws1jz1bKBYDQKdbLspz0UaqjjFkddHsqorgiW1mxcAj88lYUE6NC/zJNwT+SloqtA==} + '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.16': + resolution: {integrity: sha512-tj7XRemQcOcFwv7qhpUxMTBbI5mWMlE4c1Omhg5+h8GuLXzyj8HviYgR+bB2DMDgRqUE+jiDleqSCRjx4aYk/Q==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@rolldown/binding-win32-x64-msvc@1.0.0-rc.15': - resolution: {integrity: sha512-3P2A8L+x75qavWLe/Dll3EYBJLQmtkJN8rfh+U/eR3MqMgL/h98PhYI+JFfXuDPgPeCB7iZAKiqii5vqOvnA0g==} + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.16': + resolution: {integrity: sha512-PH5DRZT+F4f2PTXRXR8uJxnBq2po/xFtddyabTJVJs/ZYVHqXPEgNIr35IHTEa6bpa0Q8Awg+ymkTaGnKITw4g==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] @@ -1237,8 +1247,8 @@ packages: '@rolldown/pluginutils@1.0.0-rc.13': resolution: {integrity: sha512-3ngTAv6F/Py35BsYbeeLeecvhMKdsKm4AoOETVhAA+Qc8nrA2I0kF7oa93mE9qnIurngOSpMnQ0x2nQY2FPviA==} - '@rolldown/pluginutils@1.0.0-rc.15': - resolution: {integrity: sha512-UromN0peaE53IaBRe9W7CjrZgXl90fqGpK+mIZbA3qSTeYqg3pqpROBdIPvOG3F5ereDHNwoHBI2e50n1BDr1g==} + '@rolldown/pluginutils@1.0.0-rc.16': + resolution: {integrity: sha512-45+YtqxLYKDWQouLKCrpIZhke+nXxhsw+qAHVzHDVwttyBlHNBVs2K25rDXrZzhpTp9w1FlAlvweV1H++fdZoA==} '@rtsao/scc@1.1.0': resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} @@ -1460,63 +1470,63 @@ packages: '@types/ws@8.18.1': resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==} - '@typescript-eslint/eslint-plugin@8.58.2': - resolution: {integrity: sha512-aC2qc5thQahutKjP+cl8cgN9DWe3ZUqVko30CMSZHnFEHyhOYoZSzkGtAI2mcwZ38xeImDucI4dnqsHiOYuuCw==} + '@typescript-eslint/eslint-plugin@8.59.0': + resolution: {integrity: sha512-HyAZtpdkgZwpq8Sz3FSUvCR4c+ScbuWa9AksK2Jweub7w4M3yTz4O11AqVJzLYjy/B9ZWPyc81I+mOdJU/bDQw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.58.2 + '@typescript-eslint/parser': ^8.59.0 eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/parser@8.58.2': - resolution: {integrity: sha512-/Zb/xaIDfxeJnvishjGdcR4jmr7S+bda8PKNhRGdljDM+elXhlvN0FyPSsMnLmJUrVG9aPO6dof80wjMawsASg==} + '@typescript-eslint/parser@8.59.0': + resolution: {integrity: sha512-TI1XGwKbDpo9tRW8UDIXCOeLk55qe9ZFGs8MTKU6/M08HWTw52DD/IYhfQtOEhEdPhLMT26Ka/x7p70nd3dzDg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/project-service@8.58.2': - resolution: {integrity: sha512-Cq6UfpZZk15+r87BkIh5rDpi38W4b+Sjnb8wQCPPDDweS/LRCFjCyViEbzHk5Ck3f2QDfgmlxqSa7S7clDtlfg==} + '@typescript-eslint/project-service@8.59.0': + resolution: {integrity: sha512-Lw5ITrR5s5TbC19YSvlr63ZfLaJoU6vtKTHyB0GQOpX0W7d5/Ir6vUahWi/8Sps/nOukZQ0IB3SmlxZnjaKVnw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/scope-manager@8.58.2': - resolution: {integrity: sha512-SgmyvDPexWETQek+qzZnrG6844IaO02UVyOLhI4wpo82dpZJY9+6YZCKAMFzXb7qhx37mFK1QcPQ18tud+vo6Q==} + '@typescript-eslint/scope-manager@8.59.0': + resolution: {integrity: sha512-UzR16Ut8IpA3Mc4DbgAShlPPkVm8xXMWafXxB0BocaVRHs8ZGakAxGRskF7FId3sdk9lgGD73GSFaWmWFDE4dg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/tsconfig-utils@8.58.2': - resolution: {integrity: sha512-3SR+RukipDvkkKp/d0jP0dyzuls3DbGmwDpVEc5wqk5f38KFThakqAAO0XMirWAE+kT00oTauTbzMFGPoAzB0A==} + '@typescript-eslint/tsconfig-utils@8.59.0': + resolution: {integrity: sha512-91Sbl3s4Kb3SybliIY6muFBmHVv+pYXfybC4Oolp3dvk8BvIE3wOPc+403CWIT7mJNkfQRGtdqghzs2+Z91Tqg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/type-utils@8.58.2': - resolution: {integrity: sha512-Z7EloNR/B389FvabdGeTo2XMs4W9TjtPiO9DAsmT0yom0bwlPyRjkJ1uCdW1DvrrrYP50AJZ9Xc3sByZA9+dcg==} + '@typescript-eslint/type-utils@8.59.0': + resolution: {integrity: sha512-3TRiZaQSltGqGeNrJzzr1+8YcEobKH9rHnqIp/1psfKFmhRQDNMGP5hBufanYTGznwShzVLs3Mz+gDN7HkWfXg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/types@8.58.2': - resolution: {integrity: sha512-9TukXyATBQf/Jq9AMQXfvurk+G5R2MwfqQGDR2GzGz28HvY/lXNKGhkY+6IOubwcquikWk5cjlgPvD2uAA7htQ==} + '@typescript-eslint/types@8.59.0': + resolution: {integrity: sha512-nLzdsT1gdOgFxxxwrlNVUBzSNBEEHJ86bblmk4QAS6stfig7rcJzWKqCyxFy3YRRHXDWEkb2NralA1nOYkkm/A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@8.58.2': - resolution: {integrity: sha512-ELGuoofuhhoCvNbQjFFiobFcGgcDCEm0ThWdmO4Z0UzLqPXS3KFvnEZ+SHewwOYHjM09tkzOWXNTv9u6Gqtyuw==} + '@typescript-eslint/typescript-estree@8.59.0': + resolution: {integrity: sha512-O9Re9P1BmBLFJyikRbQpLku/QA3/AueZNO9WePLBwQrvkixTmDe8u76B6CYUAITRl/rHawggEqUGn5QIkVRLMw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/utils@8.58.2': - resolution: {integrity: sha512-QZfjHNEzPY8+l0+fIXMvuQ2sJlplB4zgDZvA+NmvZsZv3EQwOcc1DuIU1VJUTWZ/RKouBMhDyNaBMx4sWvrzRA==} + '@typescript-eslint/utils@8.59.0': + resolution: {integrity: sha512-I1R/K7V07XsMJ12Oaxg/O9GfrysGTmCRhvZJBv0RE0NcULMzjqVpR5kRRQjHsz3J/bElU7HwCO7zkqL+MSUz+g==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/visitor-keys@8.58.2': - resolution: {integrity: sha512-f1WO2Lx8a9t8DARmcWAUPJbu0G20bJlj8L4z72K00TMeJAoyLr/tHhI/pzYBLrR4dXWkcxO1cWYZEOX8DKHTqA==} + '@typescript-eslint/visitor-keys@8.59.0': + resolution: {integrity: sha512-/uejZt4dSere1bx12WLlPfv8GktzcaDtuJ7s42/HEZ5zGj9oxRaD4bj7qwSunXkf+pbAhFt2zjpHYUiT5lHf0Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@unrs/resolver-binding-android-arm-eabi@1.11.1': @@ -1632,8 +1642,8 @@ packages: vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 vue: ^3.2.25 - '@vitest/eslint-plugin@1.6.15': - resolution: {integrity: sha512-dTMjrdngmcB+DxomlKQ+SUubCTvd0m2hQQFpv5sx+GRodmeoxr2PVbphk57SVp250vpxphk9Ccwyv6fQ6+2gkA==} + '@vitest/eslint-plugin@1.6.16': + resolution: {integrity: sha512-2pBN1F1JXq6zTSaYC58CMJa7pGxXIRsLfOioeZM4cPE3pRdSh1ySTSoHPQlOTEF5WgoVzWZQxhGQ3ygT78hOVg==} engines: {node: '>=18'} peerDependencies: '@typescript-eslint/eslint-plugin': '*' @@ -1698,8 +1708,8 @@ packages: '@vue/compiler-ssr@3.5.32': resolution: {integrity: sha512-Gp4gTs22T3DgRotZ8aA/6m2jMR+GMztvBXUBEUOYOcST+giyGWJ4WvFd7QLHBkzTxkfOt8IELKNdpzITLbA2rw==} - '@vue/language-core@3.2.6': - resolution: {integrity: sha512-xYYYX3/aVup576tP/23sEUpgiEnujrENaoNRbaozC1/MA9I6EGFQRJb4xrt/MmUCAGlxTKL2RmT8JLTPqagCkg==} + '@vue/language-core@3.2.7': + resolution: {integrity: sha512-Gn4q/tRxbpVGLEuARQ43p3YELlNAFgRUVCgW9U5Cr+5q4vfD2bWDWpl3ABbJMXUt5xlE1dF8dkigg2aUq7JYYw==} '@vue/reactivity@3.5.32': resolution: {integrity: sha512-/ORasxSGvZ6MN5gc+uE364SxFdJ0+WqVG0CENXaGW58TOCdrAW76WWaplDtECeS1qphvtBZtR+3/o1g1zL4xPQ==} @@ -1801,8 +1811,8 @@ packages: base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - baseline-browser-mapping@2.10.18: - resolution: {integrity: sha512-VSnGQAOLtP5mib/DPyg2/t+Tlv65NTBz83BJBJvmLVHHuKJVaDOBvJJykiT5TR++em5nfAySPccDZDa4oSrn8A==} + baseline-browser-mapping@2.10.20: + resolution: {integrity: sha512-1AaXxEPfXT+GvTBJFuy4yXVHWJBXa4OdbIebGN/wX5DlsIkU0+wzGnd2lOzokSk51d5LUmqjgBLRLlypLUqInQ==} engines: {node: '>=6.0.0'} hasBin: true @@ -1855,8 +1865,8 @@ packages: resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} engines: {node: '>= 6'} - caniuse-lite@1.0.30001787: - resolution: {integrity: sha512-mNcrMN9KeI68u7muanUpEejSLghOKlVhRqS/Za2IeyGllJ9I9otGpR9g3nsw7n4W378TE/LyIteA0+/FOZm4Kg==} + caniuse-lite@1.0.30001788: + resolution: {integrity: sha512-6q8HFp+lOQtcf7wBK+uEenxymVWkGKkjFpCvw5W25cmMwEDU45p1xQFBQv8JDlMMry7eNxyBaR+qxgmTUZkIRQ==} chai@6.2.2: resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} @@ -1917,8 +1927,8 @@ packages: resolution: {integrity: sha512-GfisEZEJvzKrmGWkvfhgzcz/BllN1USeqD2V6tg14OAOgaCD2Z/PUEuxnAZ/nPvmaHRG7a8y77p1T/IRQ4D1Hw==} engines: {node: '>=4'} - clippie@4.1.10: - resolution: {integrity: sha512-zUjK2fLH8/wju2lks5mH0u8wSRYCOJoHfT1KQ61+aCT5O1ouONnSrnKQ3BTKvIYLUYJarbLZo4FLHyce/SLF2g==} + clippie@4.1.14: + resolution: {integrity: sha512-VMyejKiX9jtz57BP2YLZeH+662xKTlIAXBoaHVXdtuuDiSd2D1z/0GyclLGX4POXKK03/vYB6cHVWlSLDI2YBw==} codemirror-lang-elixir@4.0.1: resolution: {integrity: sha512-z6W/XB4b7TZrp9EZYBGVq93vQfvKbff+1iM8YZaVErL0dguBAeLmVRlEv1NuDZHOP1qjJ3NwyibkUkNWn7q9VQ==} @@ -2267,8 +2277,8 @@ packages: resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} engines: {node: '>= 4'} - dompurify@3.3.3: - resolution: {integrity: sha512-Oj6pzI2+RqBfFG+qOaOLbFXLQ90ARpcGG6UePL82bJLtdsa6CYJD7nmiU8MW9nQNOtCHV3lZ/Bzq1X0QYbBZCA==} + dompurify@3.4.0: + resolution: {integrity: sha512-nolgK9JcaUXMSmW+j1yaSvaEaoXYHwWyGJlkoCTghc97KgGDDSnpoU/PlEnw63Ah+TGKFOyY+X5LnxaWbCSfXg==} domutils@3.2.2: resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} @@ -2276,8 +2286,8 @@ packages: easymde@2.20.0: resolution: {integrity: sha512-V1Z5f92TfR42Na852OWnIZMbM7zotWQYTddNaLYZFVKj7APBbyZ3FYJ27gBw2grMW3R6Qdv9J8n5Ij7XRSIgXQ==} - electron-to-chromium@1.5.335: - resolution: {integrity: sha512-q9n5T4BR4Xwa2cwbrwcsDJtHD/enpQ5S1xF1IAtdqf5AAgqDFmR/aakqH3ChFdqd/QXJhS3rnnXFtexU7rax6Q==} + electron-to-chromium@1.5.340: + resolution: {integrity: sha512-908qahOGocRMinT2nM3ajCEM99H4iPdv84eagPP3FfZy/1ZGeOy2CZYzjhms81ckOPCXPlW7LkY4XpxD8r1DrA==} elkjs@0.9.3: resolution: {integrity: sha512-f/ZeWvW/BCXbhGEf1Ujp29EASo/lk1FDnETgNKwJrsVvGZhUWCZyg3xLJjAsxfOmt8KjswHmI5EwCQcPMpOYhQ==} @@ -2451,8 +2461,8 @@ packages: resolution: {integrity: sha512-brcKcxGnISN2CcVhXJ/kEQlNa0MEfGRtwKtWA16SkqXHKitaKIMrfemJKLKX1YqDU5C/5JY3PvZXd5jEW04e0Q==} engines: {node: '>=5.0.0'} - eslint-plugin-playwright@2.10.1: - resolution: {integrity: sha512-qea3UxBOb8fTwJ77FMApZKvRye5DOluDHcev0LDJwID3RELeun0JlqzrNIXAB/SXCyB/AesCW/6sZfcT9q3Edg==} + eslint-plugin-playwright@2.10.2: + resolution: {integrity: sha512-0N+2OWc3NZbOZ0gK8mp2TK6Qu3UWcJTQ9rqU0UM2yRJXgT758pvpY0lsOLIySfbyFrLqn3TcXjixbmcK90VnuQ==} engines: {node: '>=16.9.0'} peerDependencies: eslint: '>=8.40.0' @@ -2477,8 +2487,8 @@ packages: peerDependencies: eslint: '>=9.38.0' - eslint-plugin-sonarjs@4.0.2: - resolution: {integrity: sha512-BTcT1zr1iTbmJtVlcesISwnXzh+9uhf9LEOr+RRNf4kR8xA0HQTPft4oiyOCzCOGKkpSJxjR8ZYF6H7VPyplyw==} + eslint-plugin-sonarjs@4.0.3: + resolution: {integrity: sha512-5drkJKLC9qQddIiaATV0e8+ygbUc7b0Ti6VB7M2d3jmKNh3X0RaiIJYTs3dr9xnlhlrxo+/s1FoO3Jgv6O/c7g==} peerDependencies: eslint: ^8.0.0 || ^9.0.0 || ^10.0.0 @@ -2541,8 +2551,8 @@ packages: resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} - eslint@10.2.0: - resolution: {integrity: sha512-+L0vBFYGIpSNIt/KWTpFonPrqYvgKw1eUI5Vn7mEogrQcWtWYtNQ7dNqC+px/J0idT3BAkiWrhfS7k+Tum8TUA==} + eslint@10.2.1: + resolution: {integrity: sha512-wiyGaKsDgqXvF40P8mDwiUp/KQjE1FdrIEJsM8PZ3XCiniTMXS3OHWWUe5FI5agoCnr8x4xPrTDZuxsBlNHl+Q==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} hasBin: true peerDependencies: @@ -2679,8 +2689,8 @@ packages: resolution: {integrity: sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==} engines: {node: '>=18'} - get-tsconfig@4.13.7: - resolution: {integrity: sha512-7tN6rFgBlMgpBML5j8typ92BKFi2sFQvIdpAqLA2beia5avZDrMs0FLZiM5etShWq5irVyGcGMEA1jcDaK7A/Q==} + get-tsconfig@4.14.0: + resolution: {integrity: sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==} glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} @@ -2724,8 +2734,8 @@ packages: resolution: {integrity: sha512-tSQXBXS/MWQOn/RKckawJ61vvsDpCom87JgxiYdGwHdOa0ht0vzUWDlfioofFCRU0L+6NGDt6XzbgoJvZkMeRQ==} engines: {node: '>=0.8.0'} - happy-dom@20.8.9: - resolution: {integrity: sha512-Tz23LR9T9jOGVZm2x1EPdXqwA37G/owYMxRwU0E4miurAtFsPMQ1d2Jc2okUaSjZqAFz2oEn3FLXC5a0a+siyA==} + happy-dom@20.9.0: + resolution: {integrity: sha512-GZZ9mKe8r646NUAf/zemnGbjYh4Bt8/MqASJY+pSm5ZDtc3YQox+4gsLI7yi1hba6o+eCsGxpHn5+iEVn31/FQ==} engines: {node: '>=20.0.0'} has-flag@5.0.1: @@ -3463,8 +3473,8 @@ packages: postcss-value-parser@4.2.0: resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} - postcss@8.5.9: - resolution: {integrity: sha512-7a70Nsot+EMX9fFU3064K/kdHWZqGVY+BADLyXc8Dfv+mTLLVl6JzJpPaCZ2kQL9gIJvKXSLMHhqdRRjwQeFtw==} + postcss@8.5.10: + resolution: {integrity: sha512-pMMHxBOZKFU6HgAZ4eyGnwXF/EvPGGqUr0MnZ5+99485wwW41kW91A4LOGxSHhgugZmSChL5AlElNdwlNgcnLQ==} engines: {node: ^10 || ^12 || >=14} prelude-ls@1.2.1: @@ -3475,8 +3485,8 @@ packages: resolution: {integrity: sha512-SxToR7P8Y2lWmv/kTzVLC1t/GDI2WGjMwNhLLE9qtH8Q13C+aEmuRlzDst4Up4s0Wc8sF2M+J57iB3cMLqftfg==} engines: {node: '>=6.0.0'} - prettier@3.8.2: - resolution: {integrity: sha512-8c3mgTe0ASwWAJK+78dpviD+A8EqhndQPUBpNUIPt6+xWlIigCwfN01lWr9MAede4uqXGTEKeQWTvzb3vjia0Q==} + prettier@3.8.3: + resolution: {integrity: sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==} engines: {node: '>=14'} hasBin: true @@ -3550,13 +3560,13 @@ packages: robust-predicates@3.0.3: resolution: {integrity: sha512-NS3levdsRIUOmiJ8FZWCP7LG3QpJyrs/TE0Zpf1yvZu8cAJJ6QMW92H1c7kWpdIHo8RvmLxN/o2JXTKHp74lUA==} - rolldown-license-plugin@2.2.5: - resolution: {integrity: sha512-z1Vjlyx5Q1Hsq1IjBJlt2Vj8/Uy9fqPN0NEwjJ6QHHuDKgHasv+5Pnuo0M0zSoIkCyxeRd+/9frYutccJa+jLQ==} + rolldown-license-plugin@3.0.1: + resolution: {integrity: sha512-0aBIHnHN2xiEXSmTMHFLWYCm3WBExqSbq0y9nr9LKg0JBI8wBy7Y+Nm4oL5JJHgcI4JeRniERVatHqUg2QtMzQ==} peerDependencies: rolldown: '*' - rolldown@1.0.0-rc.15: - resolution: {integrity: sha512-Ff31guA5zT6WjnGp0SXw76X6hzGRk/OQq2hE+1lcDe+lJdHSgnSX6nK3erbONHyCbpSj9a9E+uX/OvytZoWp2g==} + rolldown@1.0.0-rc.16: + resolution: {integrity: sha512-rzi5WqKzEZw3SooTt7cgm4eqIoujPIyGcJNGFL7iPEuajQw7vxMHUkXylu4/vhCkJGXsgRmxqMKXUpT6FEgl0g==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true @@ -3655,8 +3665,8 @@ packages: stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} - std-env@4.0.0: - resolution: {integrity: sha512-zUMPtQ/HBY3/50VbpkupYHbRroTRZJPRLvreamgErJVys0ceuzMkD44J/QjqhHjOzK42GQ3QZIeFG1OYfOtKqQ==} + std-env@4.1.0: + resolution: {integrity: sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==} string-width@4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} @@ -3720,13 +3730,13 @@ packages: peerDependencies: stylelint: '>=16' - stylelint@17.7.0: - resolution: {integrity: sha512-n/+4RheCRl+cecGnF+S/Adz59iCRaK9BVznJYB+a7GOksfwNzjiOPnYv17pTO0HgRse9IiqbMtekGNhOb2tVYQ==} + stylelint@17.8.0: + resolution: {integrity: sha512-oHkld9T60LDSaUQ4CSVc+tlt9eUoDlxhaGWShsUCKyIL14boZfmK5bSphZqx64aiC5tCqX+BsQMTMoSz8D1zIg==} engines: {node: '>=20.19.0'} hasBin: true - stylis@4.3.6: - resolution: {integrity: sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ==} + stylis@4.4.0: + resolution: {integrity: sha512-5Z9ZpRzfuH6l/UAvCPAPUo3665Nk2wLaZU3x+TLHKVzIz33+sbJqbtrYoC3KD4/uVOr2Zp+L0LySezP9OHV9yA==} sucrase@3.35.1: resolution: {integrity: sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==} @@ -3759,8 +3769,8 @@ packages: svgson@5.3.1: resolution: {integrity: sha512-qdPgvUNWb40gWktBJnbJRelWcPzkLed/ShhnRsjbayXz8OtdPOzbil9jtiZdrYvSDumAz/VNQr6JaNfPx/gvPA==} - swagger-ui-dist@5.32.2: - resolution: {integrity: sha512-t6Ns52nS8LU2hqi0+rezMjFO1ZrCsCrnommXrU7Nfrg2va2dWahdvM6TuSwzdHpG29v6BHJyU1c/UWFhgVZzVQ==} + swagger-ui-dist@5.32.4: + resolution: {integrity: sha512-0AADFFQNJzExEN49SrD/34Nn9cxNxVLiydYl2MBwSZFPVXNkVwC/EFAjoezGGqE8oDegiDC+p47t8lKObCinMQ==} sync-fetch@0.4.5: resolution: {integrity: sha512-esiWJ7ixSKGpd9DJPBTC4ckChqdOjIwJfYhVHkcQ2Gnm41323p1TRmEI+esTQ9ppD+b5opps2OTEGTCGX5kF+g==} @@ -3847,8 +3857,8 @@ packages: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} - typescript-eslint@8.58.2: - resolution: {integrity: sha512-V8iSng9mRbdZjl54VJ9NKr6ZB+dW0J3TzRXRGcSbLIej9jV86ZRtlYeTKDR/QLxXykocJ5icNzbsl2+5TzIvcQ==} + typescript-eslint@8.59.0: + resolution: {integrity: sha512-BU3ONW9X+v90EcCH9ZS6LMackcVtxRLlI3XrYyqZIwVSHIk7Qf7bFw1z0M9Q0IUxhTMZCf8piY9hTYaNEIASrw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 @@ -3859,8 +3869,8 @@ packages: engines: {node: '>=14.17'} hasBin: true - typescript@6.0.2: - resolution: {integrity: sha512-bGdAIrZ0wiGDo5l8c++HWtbaNCWTS4UTv7RaTH/ThVIgjkveJt83m74bBHMJkuCbslY8ixgLBVZJIOiQlQTjfQ==} + typescript@6.0.3: + resolution: {integrity: sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==} engines: {node: '>=14.17'} hasBin: true @@ -3892,8 +3902,8 @@ packages: peerDependencies: browserslist: '>= 4.21.0' - updates@17.15.3: - resolution: {integrity: sha512-owzNJZYmQf1YbX9hd8bKFwEMNyR8HSQMexlfoH+GLJew71PjTQ39VAOjtNQ9VhmiV2q8RTjoj//atkOVCHrz5w==} + updates@17.15.5: + resolution: {integrity: sha512-Ce004Zzj63jL/Vml1YFGOoFSpzpxRVQlAVAo65HShwg0v1UpOzmYYAiYAi1Z7ILH65QtfqHQCphSHeqR5SgPAg==} engines: {node: '>=22'} hasBin: true @@ -3915,8 +3925,8 @@ packages: peerDependencies: vite: '*' - vite@8.0.8: - resolution: {integrity: sha512-dbU7/iLVa8KZALJyLOBOQ88nOXtNG8vxKuOT4I2mD+Ya70KPceF4IAmDsmU0h1Qsn5bPrvsY9HJstCRh3hG6Uw==} + vite@8.0.9: + resolution: {integrity: sha512-t7g7GVRpMXjNpa67HaVWI/8BWtdVIQPCL2WoozXXA7LBGEFK4AkkKkHx2hAQf5x1GZSlcmEDPkVLSGahxnEEZw==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: @@ -4034,8 +4044,8 @@ packages: peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - vue-tsc@3.2.6: - resolution: {integrity: sha512-gYW/kWI0XrwGzd0PKc7tVB/qpdeAkIZLNZb10/InizkQjHjnT8weZ/vBarZoj4kHKbUTZT/bAVgoOr8x4NsQ/Q==} + vue-tsc@3.2.7: + resolution: {integrity: sha512-zc1tL3HoQni1zGTGrwBVRQb7rGP5SWdu/m4rGB6JcnAC5MT5LFZIxF7Y+EJEnt4hGF23d60rXH7gRjHGb5KQQQ==} hasBin: true peerDependencies: typescript: '>=5.0.0' @@ -4230,14 +4240,14 @@ snapshots: dependencies: '@codemirror/language': 6.12.3 '@codemirror/state': 6.6.0 - '@codemirror/view': 6.41.0 + '@codemirror/view': 6.41.1 '@lezer/common': 1.5.2 '@codemirror/commands@6.10.3': dependencies: '@codemirror/language': 6.12.3 '@codemirror/state': 6.6.0 - '@codemirror/view': 6.41.0 + '@codemirror/view': 6.41.1 '@lezer/common': 1.5.2 '@codemirror/lang-angular@0.1.4': @@ -4247,7 +4257,7 @@ snapshots: '@codemirror/language': 6.12.3 '@lezer/common': 1.5.2 '@lezer/highlight': 1.2.3 - '@lezer/lr': 1.4.8 + '@lezer/lr': 1.4.10 '@codemirror/lang-cpp@6.0.3': dependencies: @@ -4277,7 +4287,7 @@ snapshots: '@codemirror/lang-javascript': 6.2.5 '@codemirror/language': 6.12.3 '@codemirror/state': 6.6.0 - '@codemirror/view': 6.41.0 + '@codemirror/view': 6.41.1 '@lezer/common': 1.5.2 '@lezer/css': 1.3.3 '@lezer/html': 1.3.13 @@ -4293,17 +4303,20 @@ snapshots: '@codemirror/language': 6.12.3 '@codemirror/lint': 6.9.5 '@codemirror/state': 6.6.0 - '@codemirror/view': 6.41.0 + '@codemirror/view': 6.41.1 '@lezer/common': 1.5.2 '@lezer/javascript': 1.5.4 - '@codemirror/lang-jinja@6.0.0': + '@codemirror/lang-jinja@6.0.1': dependencies: + '@codemirror/autocomplete': 6.20.1 '@codemirror/lang-html': 6.4.11 '@codemirror/language': 6.12.3 + '@codemirror/state': 6.6.0 + '@codemirror/view': 6.41.1 '@lezer/common': 1.5.2 '@lezer/highlight': 1.2.3 - '@lezer/lr': 1.4.8 + '@lezer/lr': 1.4.10 '@codemirror/lang-json@6.0.2': dependencies: @@ -4316,7 +4329,7 @@ snapshots: '@codemirror/language': 6.12.3 '@lezer/common': 1.5.2 '@lezer/highlight': 1.2.3 - '@lezer/lr': 1.4.8 + '@lezer/lr': 1.4.10 '@codemirror/lang-liquid@6.3.2': dependencies: @@ -4324,10 +4337,10 @@ snapshots: '@codemirror/lang-html': 6.4.11 '@codemirror/language': 6.12.3 '@codemirror/state': 6.6.0 - '@codemirror/view': 6.41.0 + '@codemirror/view': 6.41.1 '@lezer/common': 1.5.2 '@lezer/highlight': 1.2.3 - '@lezer/lr': 1.4.8 + '@lezer/lr': 1.4.10 '@codemirror/lang-markdown@6.5.0': dependencies: @@ -4335,7 +4348,7 @@ snapshots: '@codemirror/lang-html': 6.4.11 '@codemirror/language': 6.12.3 '@codemirror/state': 6.6.0 - '@codemirror/view': 6.41.0 + '@codemirror/view': 6.41.1 '@lezer/common': 1.5.2 '@lezer/markdown': 1.6.3 @@ -4375,7 +4388,7 @@ snapshots: '@codemirror/state': 6.6.0 '@lezer/common': 1.5.2 '@lezer/highlight': 1.2.3 - '@lezer/lr': 1.4.8 + '@lezer/lr': 1.4.10 '@codemirror/lang-vue@0.1.3': dependencies: @@ -4384,21 +4397,21 @@ snapshots: '@codemirror/language': 6.12.3 '@lezer/common': 1.5.2 '@lezer/highlight': 1.2.3 - '@lezer/lr': 1.4.8 + '@lezer/lr': 1.4.10 '@codemirror/lang-wast@6.0.2': dependencies: '@codemirror/language': 6.12.3 '@lezer/common': 1.5.2 '@lezer/highlight': 1.2.3 - '@lezer/lr': 1.4.8 + '@lezer/lr': 1.4.10 '@codemirror/lang-xml@6.1.0': dependencies: '@codemirror/autocomplete': 6.20.1 '@codemirror/language': 6.12.3 '@codemirror/state': 6.6.0 - '@codemirror/view': 6.41.0 + '@codemirror/view': 6.41.1 '@lezer/common': 1.5.2 '@lezer/xml': 1.0.6 @@ -4409,7 +4422,7 @@ snapshots: '@codemirror/state': 6.6.0 '@lezer/common': 1.5.2 '@lezer/highlight': 1.2.3 - '@lezer/lr': 1.4.8 + '@lezer/lr': 1.4.10 '@lezer/yaml': 1.0.4 '@codemirror/language-data@6.5.2': @@ -4421,7 +4434,7 @@ snapshots: '@codemirror/lang-html': 6.4.11 '@codemirror/lang-java': 6.0.2 '@codemirror/lang-javascript': 6.2.5 - '@codemirror/lang-jinja': 6.0.0 + '@codemirror/lang-jinja': 6.0.1 '@codemirror/lang-json': 6.0.2 '@codemirror/lang-less': 6.0.2 '@codemirror/lang-liquid': 6.3.2 @@ -4441,10 +4454,10 @@ snapshots: '@codemirror/language@6.12.3': dependencies: '@codemirror/state': 6.6.0 - '@codemirror/view': 6.41.0 + '@codemirror/view': 6.41.1 '@lezer/common': 1.5.2 '@lezer/highlight': 1.2.3 - '@lezer/lr': 1.4.8 + '@lezer/lr': 1.4.10 style-mod: 4.1.3 '@codemirror/legacy-modes@6.5.2': @@ -4454,20 +4467,20 @@ snapshots: '@codemirror/lint@6.9.5': dependencies: '@codemirror/state': 6.6.0 - '@codemirror/view': 6.41.0 + '@codemirror/view': 6.41.1 crelt: 1.0.6 '@codemirror/search@6.6.0': dependencies: '@codemirror/state': 6.6.0 - '@codemirror/view': 6.41.0 + '@codemirror/view': 6.41.1 crelt: 1.0.6 '@codemirror/state@6.6.0': dependencies: '@marijn/find-cluster-break': 1.0.2 - '@codemirror/view@6.41.0': + '@codemirror/view@6.41.1': dependencies: '@codemirror/state': 6.6.0 crelt: 1.0.6 @@ -4506,12 +4519,23 @@ snapshots: dependencies: '@swc/helpers': 0.5.21 + '@emnapi/core@1.10.0': + dependencies: + '@emnapi/wasi-threads': 1.2.1 + tslib: 2.8.1 + optional: true + '@emnapi/core@1.9.2': dependencies: '@emnapi/wasi-threads': 1.2.1 tslib: 2.8.1 optional: true + '@emnapi/runtime@1.10.0': + dependencies: + tslib: 2.8.1 + optional: true + '@emnapi/runtime@1.9.2': dependencies: tslib: 2.8.1 @@ -4600,24 +4624,24 @@ snapshots: '@esbuild/win32-x64@0.28.0': optional: true - '@eslint-community/eslint-plugin-eslint-comments@4.7.1(eslint@10.2.0(jiti@2.6.1))': + '@eslint-community/eslint-plugin-eslint-comments@4.7.1(eslint@10.2.1(jiti@2.6.1))': dependencies: escape-string-regexp: 4.0.0 - eslint: 10.2.0(jiti@2.6.1) + eslint: 10.2.1(jiti@2.6.1) ignore: 7.0.5 - '@eslint-community/eslint-utils@4.9.1(eslint@10.2.0(jiti@2.6.1))': + '@eslint-community/eslint-utils@4.9.1(eslint@10.2.1(jiti@2.6.1))': dependencies: - eslint: 10.2.0(jiti@2.6.1) + eslint: 10.2.1(jiti@2.6.1) eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.2': {} - '@eslint/compat@1.4.1(eslint@10.2.0(jiti@2.6.1))': + '@eslint/compat@1.4.1(eslint@10.2.1(jiti@2.6.1))': dependencies: '@eslint/core': 0.17.0 optionalDependencies: - eslint: 10.2.0(jiti@2.6.1) + eslint: 10.2.1(jiti@2.6.1) '@eslint/config-array@0.23.5': dependencies: @@ -4687,13 +4711,18 @@ snapshots: '@github/combobox-nav': 2.3.1 dom-input-range: 2.0.1 - '@humanfs/core@0.19.1': {} - - '@humanfs/node@0.16.7': + '@humanfs/core@0.19.2': dependencies: - '@humanfs/core': 0.19.1 + '@humanfs/types': 0.15.0 + + '@humanfs/node@0.16.8': + dependencies: + '@humanfs/core': 0.19.2 + '@humanfs/types': 0.15.0 '@humanwhocodes/retry': 0.4.3 + '@humanfs/types@0.15.0': {} + '@humanwhocodes/module-importer@1.0.1': {} '@humanwhocodes/momoa@3.3.10': {} @@ -4738,19 +4767,19 @@ snapshots: dependencies: '@lezer/common': 1.5.2 '@lezer/highlight': 1.2.3 - '@lezer/lr': 1.4.8 + '@lezer/lr': 1.4.10 '@lezer/css@1.3.3': dependencies: '@lezer/common': 1.5.2 '@lezer/highlight': 1.2.3 - '@lezer/lr': 1.4.8 + '@lezer/lr': 1.4.10 '@lezer/go@1.0.1': dependencies: '@lezer/common': 1.5.2 '@lezer/highlight': 1.2.3 - '@lezer/lr': 1.4.8 + '@lezer/lr': 1.4.10 '@lezer/highlight@1.2.3': dependencies: @@ -4760,27 +4789,27 @@ snapshots: dependencies: '@lezer/common': 1.5.2 '@lezer/highlight': 1.2.3 - '@lezer/lr': 1.4.8 + '@lezer/lr': 1.4.10 '@lezer/java@1.1.3': dependencies: '@lezer/common': 1.5.2 '@lezer/highlight': 1.2.3 - '@lezer/lr': 1.4.8 + '@lezer/lr': 1.4.10 '@lezer/javascript@1.5.4': dependencies: '@lezer/common': 1.5.2 '@lezer/highlight': 1.2.3 - '@lezer/lr': 1.4.8 + '@lezer/lr': 1.4.10 '@lezer/json@1.0.3': dependencies: '@lezer/common': 1.5.2 '@lezer/highlight': 1.2.3 - '@lezer/lr': 1.4.8 + '@lezer/lr': 1.4.10 - '@lezer/lr@1.4.8': + '@lezer/lr@1.4.10': dependencies: '@lezer/common': 1.5.2 @@ -4793,37 +4822,37 @@ snapshots: dependencies: '@lezer/common': 1.5.2 '@lezer/highlight': 1.2.3 - '@lezer/lr': 1.4.8 + '@lezer/lr': 1.4.10 '@lezer/python@1.1.18': dependencies: '@lezer/common': 1.5.2 '@lezer/highlight': 1.2.3 - '@lezer/lr': 1.4.8 + '@lezer/lr': 1.4.10 '@lezer/rust@1.0.2': dependencies: '@lezer/common': 1.5.2 '@lezer/highlight': 1.2.3 - '@lezer/lr': 1.4.8 + '@lezer/lr': 1.4.10 '@lezer/sass@1.1.0': dependencies: '@lezer/common': 1.5.2 '@lezer/highlight': 1.2.3 - '@lezer/lr': 1.4.8 + '@lezer/lr': 1.4.10 '@lezer/xml@1.0.6': dependencies: '@lezer/common': 1.5.2 '@lezer/highlight': 1.2.3 - '@lezer/lr': 1.4.8 + '@lezer/lr': 1.4.10 '@lezer/yaml@1.0.4': dependencies: '@lezer/common': 1.5.2 '@lezer/highlight': 1.2.3 - '@lezer/lr': 1.4.8 + '@lezer/lr': 1.4.10 '@marijn/find-cluster-break@1.0.2': {} @@ -4845,12 +4874,12 @@ snapshots: '@napi-rs/wasm-runtime@0.2.12': dependencies: - '@emnapi/core': 1.9.2 - '@emnapi/runtime': 1.9.2 + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 '@tybys/wasm-util': 0.10.1 optional: true - '@napi-rs/wasm-runtime@1.1.3(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)': + '@napi-rs/wasm-runtime@1.1.4(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)': dependencies: '@emnapi/core': 1.9.2 '@emnapi/runtime': 1.9.2 @@ -4927,7 +4956,7 @@ snapshots: dependencies: '@nolyfill/shared': 1.0.44 - '@oxc-project/types@0.124.0': {} + '@oxc-project/types@0.126.0': {} '@package-json/types@0.0.12': {} @@ -4939,27 +4968,27 @@ snapshots: '@popperjs/core@2.11.8': {} - '@primer/octicons@19.24.0': + '@primer/octicons@19.24.1': dependencies: object-assign: 4.1.1 - '@replit/codemirror-indentation-markers@6.5.3(@codemirror/language@6.12.3)(@codemirror/state@6.6.0)(@codemirror/view@6.41.0)': + '@replit/codemirror-indentation-markers@6.5.3(@codemirror/language@6.12.3)(@codemirror/state@6.6.0)(@codemirror/view@6.41.1)': dependencies: '@codemirror/language': 6.12.3 '@codemirror/state': 6.6.0 - '@codemirror/view': 6.41.0 + '@codemirror/view': 6.41.1 - '@replit/codemirror-lang-nix@6.0.1(@codemirror/autocomplete@6.20.1)(@codemirror/language@6.12.3)(@codemirror/state@6.6.0)(@codemirror/view@6.41.0)(@lezer/common@1.5.2)(@lezer/highlight@1.2.3)(@lezer/lr@1.4.8)': + '@replit/codemirror-lang-nix@6.0.1(@codemirror/autocomplete@6.20.1)(@codemirror/language@6.12.3)(@codemirror/state@6.6.0)(@codemirror/view@6.41.1)(@lezer/common@1.5.2)(@lezer/highlight@1.2.3)(@lezer/lr@1.4.10)': dependencies: '@codemirror/autocomplete': 6.20.1 '@codemirror/language': 6.12.3 '@codemirror/state': 6.6.0 - '@codemirror/view': 6.41.0 + '@codemirror/view': 6.41.1 '@lezer/common': 1.5.2 '@lezer/highlight': 1.2.3 - '@lezer/lr': 1.4.8 + '@lezer/lr': 1.4.10 - '@replit/codemirror-lang-svelte@6.0.0(@codemirror/autocomplete@6.20.1)(@codemirror/lang-css@6.3.1)(@codemirror/lang-html@6.4.11)(@codemirror/lang-javascript@6.2.5)(@codemirror/language@6.12.3)(@codemirror/state@6.6.0)(@codemirror/view@6.41.0)(@lezer/common@1.5.2)(@lezer/highlight@1.2.3)(@lezer/javascript@1.5.4)(@lezer/lr@1.4.8)': + '@replit/codemirror-lang-svelte@6.0.0(@codemirror/autocomplete@6.20.1)(@codemirror/lang-css@6.3.1)(@codemirror/lang-html@6.4.11)(@codemirror/lang-javascript@6.2.5)(@codemirror/language@6.12.3)(@codemirror/state@6.6.0)(@codemirror/view@6.41.1)(@lezer/common@1.5.2)(@lezer/highlight@1.2.3)(@lezer/javascript@1.5.4)(@lezer/lr@1.4.10)': dependencies: '@codemirror/autocomplete': 6.20.1 '@codemirror/lang-css': 6.3.1 @@ -4967,13 +4996,13 @@ snapshots: '@codemirror/lang-javascript': 6.2.5 '@codemirror/language': 6.12.3 '@codemirror/state': 6.6.0 - '@codemirror/view': 6.41.0 + '@codemirror/view': 6.41.1 '@lezer/common': 1.5.2 '@lezer/highlight': 1.2.3 '@lezer/javascript': 1.5.4 - '@lezer/lr': 1.4.8 + '@lezer/lr': 1.4.10 - '@replit/codemirror-vscode-keymap@6.0.2(@codemirror/autocomplete@6.20.1)(@codemirror/commands@6.10.3)(@codemirror/language@6.12.3)(@codemirror/lint@6.9.5)(@codemirror/search@6.6.0)(@codemirror/state@6.6.0)(@codemirror/view@6.41.0)': + '@replit/codemirror-vscode-keymap@6.0.2(@codemirror/autocomplete@6.20.1)(@codemirror/commands@6.10.3)(@codemirror/language@6.12.3)(@codemirror/lint@6.9.5)(@codemirror/search@6.6.0)(@codemirror/state@6.6.0)(@codemirror/view@6.41.1)': dependencies: '@codemirror/autocomplete': 6.20.1 '@codemirror/commands': 6.10.3 @@ -4981,62 +5010,62 @@ snapshots: '@codemirror/lint': 6.9.5 '@codemirror/search': 6.6.0 '@codemirror/state': 6.6.0 - '@codemirror/view': 6.41.0 + '@codemirror/view': 6.41.1 '@resvg/resvg-wasm@2.6.2': {} - '@rolldown/binding-android-arm64@1.0.0-rc.15': + '@rolldown/binding-android-arm64@1.0.0-rc.16': optional: true - '@rolldown/binding-darwin-arm64@1.0.0-rc.15': + '@rolldown/binding-darwin-arm64@1.0.0-rc.16': optional: true - '@rolldown/binding-darwin-x64@1.0.0-rc.15': + '@rolldown/binding-darwin-x64@1.0.0-rc.16': optional: true - '@rolldown/binding-freebsd-x64@1.0.0-rc.15': + '@rolldown/binding-freebsd-x64@1.0.0-rc.16': optional: true - '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.15': + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.16': optional: true - '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.15': + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.16': optional: true - '@rolldown/binding-linux-arm64-musl@1.0.0-rc.15': + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.16': optional: true - '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.15': + '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.16': optional: true - '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.15': + '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.16': optional: true - '@rolldown/binding-linux-x64-gnu@1.0.0-rc.15': + '@rolldown/binding-linux-x64-gnu@1.0.0-rc.16': optional: true - '@rolldown/binding-linux-x64-musl@1.0.0-rc.15': + '@rolldown/binding-linux-x64-musl@1.0.0-rc.16': optional: true - '@rolldown/binding-openharmony-arm64@1.0.0-rc.15': + '@rolldown/binding-openharmony-arm64@1.0.0-rc.16': optional: true - '@rolldown/binding-wasm32-wasi@1.0.0-rc.15': + '@rolldown/binding-wasm32-wasi@1.0.0-rc.16': dependencies: '@emnapi/core': 1.9.2 '@emnapi/runtime': 1.9.2 - '@napi-rs/wasm-runtime': 1.1.3(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2) + '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2) optional: true - '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.15': + '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.16': optional: true - '@rolldown/binding-win32-x64-msvc@1.0.0-rc.15': + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.16': optional: true '@rolldown/pluginutils@1.0.0-rc.13': {} - '@rolldown/pluginutils@1.0.0-rc.15': {} + '@rolldown/pluginutils@1.0.0-rc.16': {} '@rtsao/scc@1.1.0': {} @@ -5064,26 +5093,26 @@ snapshots: '@standard-schema/spec@1.1.0': {} - '@stylistic/eslint-plugin@5.10.0(eslint@10.2.0(jiti@2.6.1))': + '@stylistic/eslint-plugin@5.10.0(eslint@10.2.1(jiti@2.6.1))': dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.2.0(jiti@2.6.1)) - '@typescript-eslint/types': 8.58.2 - eslint: 10.2.0(jiti@2.6.1) + '@eslint-community/eslint-utils': 4.9.1(eslint@10.2.1(jiti@2.6.1)) + '@typescript-eslint/types': 8.59.0 + eslint: 10.2.1(jiti@2.6.1) eslint-visitor-keys: 4.2.1 espree: 10.4.0 estraverse: 5.3.0 picomatch: 4.0.4 - '@stylistic/stylelint-plugin@5.1.0(stylelint@17.7.0(typescript@6.0.2))': + '@stylistic/stylelint-plugin@5.1.0(stylelint@17.8.0(typescript@6.0.3))': dependencies: '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.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) - postcss: 8.5.9 + postcss: 8.5.10 postcss-selector-parser: 7.1.1 postcss-value-parser: 4.2.0 style-search: 0.1.0 - stylelint: 17.7.0(typescript@6.0.2) + stylelint: 17.8.0(typescript@6.0.3) '@swc/helpers@0.5.21': dependencies: @@ -5277,15 +5306,15 @@ snapshots: dependencies: '@types/node': 25.6.0 - '@typescript-eslint/eslint-plugin@8.58.2(@typescript-eslint/parser@8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2))(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/eslint-plugin@8.59.0(@typescript-eslint/parser@8.59.0(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3))(eslint@10.2.1(jiti@2.6.1))(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2) - '@typescript-eslint/scope-manager': 8.58.2 - '@typescript-eslint/type-utils': 8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/utils': 8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.58.2 - eslint: 10.2.0(jiti@2.6.1) + '@typescript-eslint/parser': 8.59.0(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3) + '@typescript-eslint/scope-manager': 8.59.0 + '@typescript-eslint/type-utils': 8.59.0(eslint@10.2.1(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/utils': 8.59.0(eslint@10.2.1(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.59.0 + eslint: 10.2.1(jiti@2.6.1) ignore: 7.0.5 natural-compare: 1.4.0 ts-api-utils: 2.5.0(typescript@5.9.3) @@ -5293,109 +5322,109 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/eslint-plugin@8.58.2(@typescript-eslint/parser@8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2))(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2)': + '@typescript-eslint/eslint-plugin@8.59.0(@typescript-eslint/parser@8.59.0(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3))(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2) - '@typescript-eslint/scope-manager': 8.58.2 - '@typescript-eslint/type-utils': 8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2) - '@typescript-eslint/utils': 8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2) - '@typescript-eslint/visitor-keys': 8.58.2 - eslint: 10.2.0(jiti@2.6.1) + '@typescript-eslint/parser': 8.59.0(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3) + '@typescript-eslint/scope-manager': 8.59.0 + '@typescript-eslint/type-utils': 8.59.0(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3) + '@typescript-eslint/utils': 8.59.0(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3) + '@typescript-eslint/visitor-keys': 8.59.0 + eslint: 10.2.1(jiti@2.6.1) ignore: 7.0.5 natural-compare: 1.4.0 - ts-api-utils: 2.5.0(typescript@6.0.2) - typescript: 6.0.2 + ts-api-utils: 2.5.0(typescript@6.0.3) + typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/parser@8.59.0(eslint@10.2.1(jiti@2.6.1))(typescript@5.9.3)': dependencies: - '@typescript-eslint/scope-manager': 8.58.2 - '@typescript-eslint/types': 8.58.2 - '@typescript-eslint/typescript-estree': 8.58.2(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.58.2 + '@typescript-eslint/scope-manager': 8.59.0 + '@typescript-eslint/types': 8.59.0 + '@typescript-eslint/typescript-estree': 8.59.0(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.59.0 debug: 4.4.3 - eslint: 10.2.0(jiti@2.6.1) + eslint: 10.2.1(jiti@2.6.1) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2)': + '@typescript-eslint/parser@8.59.0(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3)': dependencies: - '@typescript-eslint/scope-manager': 8.58.2 - '@typescript-eslint/types': 8.58.2 - '@typescript-eslint/typescript-estree': 8.58.2(typescript@6.0.2) - '@typescript-eslint/visitor-keys': 8.58.2 + '@typescript-eslint/scope-manager': 8.59.0 + '@typescript-eslint/types': 8.59.0 + '@typescript-eslint/typescript-estree': 8.59.0(typescript@6.0.3) + '@typescript-eslint/visitor-keys': 8.59.0 debug: 4.4.3 - eslint: 10.2.0(jiti@2.6.1) - typescript: 6.0.2 + eslint: 10.2.1(jiti@2.6.1) + typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.58.2(typescript@5.9.3)': + '@typescript-eslint/project-service@8.59.0(typescript@5.9.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.58.2(typescript@5.9.3) - '@typescript-eslint/types': 8.58.2 + '@typescript-eslint/tsconfig-utils': 8.59.0(typescript@5.9.3) + '@typescript-eslint/types': 8.59.0 debug: 4.4.3 typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.58.2(typescript@6.0.2)': + '@typescript-eslint/project-service@8.59.0(typescript@6.0.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.58.2(typescript@6.0.2) - '@typescript-eslint/types': 8.58.2 + '@typescript-eslint/tsconfig-utils': 8.59.0(typescript@6.0.3) + '@typescript-eslint/types': 8.59.0 debug: 4.4.3 - typescript: 6.0.2 + typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@8.58.2': + '@typescript-eslint/scope-manager@8.59.0': dependencies: - '@typescript-eslint/types': 8.58.2 - '@typescript-eslint/visitor-keys': 8.58.2 + '@typescript-eslint/types': 8.59.0 + '@typescript-eslint/visitor-keys': 8.59.0 - '@typescript-eslint/tsconfig-utils@8.58.2(typescript@5.9.3)': + '@typescript-eslint/tsconfig-utils@8.59.0(typescript@5.9.3)': dependencies: typescript: 5.9.3 - '@typescript-eslint/tsconfig-utils@8.58.2(typescript@6.0.2)': + '@typescript-eslint/tsconfig-utils@8.59.0(typescript@6.0.3)': dependencies: - typescript: 6.0.2 + typescript: 6.0.3 - '@typescript-eslint/type-utils@8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/type-utils@8.59.0(eslint@10.2.1(jiti@2.6.1))(typescript@5.9.3)': dependencies: - '@typescript-eslint/types': 8.58.2 - '@typescript-eslint/typescript-estree': 8.58.2(typescript@5.9.3) - '@typescript-eslint/utils': 8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/types': 8.59.0 + '@typescript-eslint/typescript-estree': 8.59.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.59.0(eslint@10.2.1(jiti@2.6.1))(typescript@5.9.3) debug: 4.4.3 - eslint: 10.2.0(jiti@2.6.1) + eslint: 10.2.1(jiti@2.6.1) ts-api-utils: 2.5.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/type-utils@8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2)': + '@typescript-eslint/type-utils@8.59.0(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3)': dependencies: - '@typescript-eslint/types': 8.58.2 - '@typescript-eslint/typescript-estree': 8.58.2(typescript@6.0.2) - '@typescript-eslint/utils': 8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2) + '@typescript-eslint/types': 8.59.0 + '@typescript-eslint/typescript-estree': 8.59.0(typescript@6.0.3) + '@typescript-eslint/utils': 8.59.0(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3) debug: 4.4.3 - eslint: 10.2.0(jiti@2.6.1) - ts-api-utils: 2.5.0(typescript@6.0.2) - typescript: 6.0.2 + eslint: 10.2.1(jiti@2.6.1) + ts-api-utils: 2.5.0(typescript@6.0.3) + typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/types@8.58.2': {} + '@typescript-eslint/types@8.59.0': {} - '@typescript-eslint/typescript-estree@8.58.2(typescript@5.9.3)': + '@typescript-eslint/typescript-estree@8.59.0(typescript@5.9.3)': dependencies: - '@typescript-eslint/project-service': 8.58.2(typescript@5.9.3) - '@typescript-eslint/tsconfig-utils': 8.58.2(typescript@5.9.3) - '@typescript-eslint/types': 8.58.2 - '@typescript-eslint/visitor-keys': 8.58.2 + '@typescript-eslint/project-service': 8.59.0(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.59.0(typescript@5.9.3) + '@typescript-eslint/types': 8.59.0 + '@typescript-eslint/visitor-keys': 8.59.0 debug: 4.4.3 minimatch: 10.2.5 semver: 7.7.4 @@ -5405,46 +5434,46 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/typescript-estree@8.58.2(typescript@6.0.2)': + '@typescript-eslint/typescript-estree@8.59.0(typescript@6.0.3)': dependencies: - '@typescript-eslint/project-service': 8.58.2(typescript@6.0.2) - '@typescript-eslint/tsconfig-utils': 8.58.2(typescript@6.0.2) - '@typescript-eslint/types': 8.58.2 - '@typescript-eslint/visitor-keys': 8.58.2 + '@typescript-eslint/project-service': 8.59.0(typescript@6.0.3) + '@typescript-eslint/tsconfig-utils': 8.59.0(typescript@6.0.3) + '@typescript-eslint/types': 8.59.0 + '@typescript-eslint/visitor-keys': 8.59.0 debug: 4.4.3 minimatch: 10.2.5 semver: 7.7.4 tinyglobby: 0.2.16 - ts-api-utils: 2.5.0(typescript@6.0.2) - typescript: 6.0.2 + ts-api-utils: 2.5.0(typescript@6.0.3) + typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/utils@8.59.0(eslint@10.2.1(jiti@2.6.1))(typescript@5.9.3)': dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.2.0(jiti@2.6.1)) - '@typescript-eslint/scope-manager': 8.58.2 - '@typescript-eslint/types': 8.58.2 - '@typescript-eslint/typescript-estree': 8.58.2(typescript@5.9.3) - eslint: 10.2.0(jiti@2.6.1) + '@eslint-community/eslint-utils': 4.9.1(eslint@10.2.1(jiti@2.6.1)) + '@typescript-eslint/scope-manager': 8.59.0 + '@typescript-eslint/types': 8.59.0 + '@typescript-eslint/typescript-estree': 8.59.0(typescript@5.9.3) + eslint: 10.2.1(jiti@2.6.1) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2)': + '@typescript-eslint/utils@8.59.0(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3)': dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.2.0(jiti@2.6.1)) - '@typescript-eslint/scope-manager': 8.58.2 - '@typescript-eslint/types': 8.58.2 - '@typescript-eslint/typescript-estree': 8.58.2(typescript@6.0.2) - eslint: 10.2.0(jiti@2.6.1) - typescript: 6.0.2 + '@eslint-community/eslint-utils': 4.9.1(eslint@10.2.1(jiti@2.6.1)) + '@typescript-eslint/scope-manager': 8.59.0 + '@typescript-eslint/types': 8.59.0 + '@typescript-eslint/typescript-estree': 8.59.0(typescript@6.0.3) + eslint: 10.2.1(jiti@2.6.1) + typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@8.58.2': + '@typescript-eslint/visitor-keys@8.59.0': dependencies: - '@typescript-eslint/types': 8.58.2 + '@typescript-eslint/types': 8.59.0 eslint-visitor-keys: 5.0.1 '@unrs/resolver-binding-android-arm-eabi@1.11.1': @@ -5511,21 +5540,21 @@ snapshots: d3-selection: 3.0.0 d3-transition: 3.0.1(d3-selection@3.0.0) - '@vitejs/plugin-vue@6.0.6(vite@8.0.8(@types/node@25.6.0)(esbuild@0.28.0)(jiti@2.6.1))(vue@3.5.32(typescript@6.0.2))': + '@vitejs/plugin-vue@6.0.6(vite@8.0.9(@types/node@25.6.0)(esbuild@0.28.0)(jiti@2.6.1))(vue@3.5.32(typescript@6.0.3))': dependencies: '@rolldown/pluginutils': 1.0.0-rc.13 - vite: 8.0.8(@types/node@25.6.0)(esbuild@0.28.0)(jiti@2.6.1) - vue: 3.5.32(typescript@6.0.2) + vite: 8.0.9(@types/node@25.6.0)(esbuild@0.28.0)(jiti@2.6.1) + vue: 3.5.32(typescript@6.0.3) - '@vitest/eslint-plugin@1.6.15(@typescript-eslint/eslint-plugin@8.58.2(@typescript-eslint/parser@8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2))(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2))(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2)(vitest@4.1.4(@types/node@25.6.0)(happy-dom@20.8.9)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.28.0)(jiti@2.6.1)))': + '@vitest/eslint-plugin@1.6.16(@typescript-eslint/eslint-plugin@8.59.0(@typescript-eslint/parser@8.59.0(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3))(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3))(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3)(vitest@4.1.4(@types/node@25.6.0)(happy-dom@20.9.0)(vite@8.0.9(@types/node@25.6.0)(esbuild@0.28.0)(jiti@2.6.1)))': dependencies: - '@typescript-eslint/scope-manager': 8.58.2 - '@typescript-eslint/utils': 8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2) - eslint: 10.2.0(jiti@2.6.1) + '@typescript-eslint/scope-manager': 8.59.0 + '@typescript-eslint/utils': 8.59.0(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3) + eslint: 10.2.1(jiti@2.6.1) optionalDependencies: - '@typescript-eslint/eslint-plugin': 8.58.2(@typescript-eslint/parser@8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2))(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2) - typescript: 6.0.2 - vitest: 4.1.4(@types/node@25.6.0)(happy-dom@20.8.9)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.28.0)(jiti@2.6.1)) + '@typescript-eslint/eslint-plugin': 8.59.0(@typescript-eslint/parser@8.59.0(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3))(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3) + typescript: 6.0.3 + vitest: 4.1.4(@types/node@25.6.0)(happy-dom@20.9.0)(vite@8.0.9(@types/node@25.6.0)(esbuild@0.28.0)(jiti@2.6.1)) transitivePeerDependencies: - supports-color @@ -5538,13 +5567,13 @@ snapshots: chai: 6.2.2 tinyrainbow: 3.1.0 - '@vitest/mocker@4.1.4(vite@8.0.8(@types/node@25.6.0)(esbuild@0.28.0)(jiti@2.6.1))': + '@vitest/mocker@4.1.4(vite@8.0.9(@types/node@25.6.0)(esbuild@0.28.0)(jiti@2.6.1))': dependencies: '@vitest/spy': 4.1.4 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 8.0.8(@types/node@25.6.0)(esbuild@0.28.0)(jiti@2.6.1) + vite: 8.0.9(@types/node@25.6.0)(esbuild@0.28.0)(jiti@2.6.1) '@vitest/pretty-format@4.1.4': dependencies: @@ -5604,7 +5633,7 @@ snapshots: '@vue/shared': 3.5.32 estree-walker: 2.0.2 magic-string: 0.30.21 - postcss: 8.5.9 + postcss: 8.5.10 source-map-js: 1.2.1 '@vue/compiler-ssr@3.5.32': @@ -5612,7 +5641,7 @@ snapshots: '@vue/compiler-dom': 3.5.32 '@vue/shared': 3.5.32 - '@vue/language-core@3.2.6': + '@vue/language-core@3.2.7': dependencies: '@volar/language-core': 2.4.28 '@vue/compiler-dom': 3.5.32 @@ -5638,11 +5667,11 @@ snapshots: '@vue/shared': 3.5.32 csstype: 3.2.3 - '@vue/server-renderer@3.5.32(vue@3.5.32(typescript@6.0.2))': + '@vue/server-renderer@3.5.32(vue@3.5.32(typescript@6.0.3))': dependencies: '@vue/compiler-ssr': 3.5.32 '@vue/shared': 3.5.32 - vue: 3.5.32(typescript@6.0.2) + vue: 3.5.32(typescript@6.0.3) '@vue/shared@3.5.32': {} @@ -5713,7 +5742,7 @@ snapshots: base64-js@1.5.1: {} - baseline-browser-mapping@2.10.18: {} + baseline-browser-mapping@2.10.20: {} binary-extensions@2.3.0: {} @@ -5734,9 +5763,9 @@ snapshots: browserslist@4.28.2: dependencies: - baseline-browser-mapping: 2.10.18 - caniuse-lite: 1.0.30001787 - electron-to-chromium: 1.5.335 + baseline-browser-mapping: 2.10.20 + caniuse-lite: 1.0.30001788 + electron-to-chromium: 1.5.340 node-releases: 2.0.37 update-browserslist-db: 1.2.3(browserslist@4.28.2) @@ -5763,7 +5792,7 @@ snapshots: camelcase-css@2.0.1: {} - caniuse-lite@1.0.30001787: {} + caniuse-lite@1.0.30001788: {} chai@6.2.2: {} @@ -5825,7 +5854,7 @@ snapshots: dependencies: escape-string-regexp: 1.0.5 - clippie@4.1.10: {} + clippie@4.1.14: {} codemirror-lang-elixir@4.0.1: dependencies: @@ -5880,14 +5909,14 @@ snapshots: dependencies: layout-base: 2.0.1 - cosmiconfig@9.0.1(typescript@6.0.2): + cosmiconfig@9.0.1(typescript@6.0.3): dependencies: env-paths: 2.2.1 import-fresh: 3.3.1 js-yaml: 4.1.1 parse-json: 5.2.0 optionalDependencies: - typescript: 6.0.2 + typescript: 6.0.3 crelt@1.0.6: {} @@ -6172,7 +6201,7 @@ snapshots: dependencies: domelementtype: 2.3.0 - dompurify@3.3.3: + dompurify@3.4.0: optionalDependencies: '@types/trusted-types': 2.0.7 @@ -6190,7 +6219,7 @@ snapshots: codemirror-spell-checker: 1.1.2 marked: 4.3.0 - electron-to-chromium@1.5.335: {} + electron-to-chromium@1.5.340: {} elkjs@0.9.3: {} @@ -6247,13 +6276,13 @@ snapshots: escape-string-regexp@4.0.0: {} - eslint-config-prettier@10.1.8(eslint@10.2.0(jiti@2.6.1)): + eslint-config-prettier@10.1.8(eslint@10.2.1(jiti@2.6.1)): dependencies: - eslint: 10.2.0(jiti@2.6.1) + eslint: 10.2.1(jiti@2.6.1) eslint-import-context@0.1.9(unrs-resolver@1.11.1): dependencies: - get-tsconfig: 4.13.7 + get-tsconfig: 4.14.0 stable-hash-x: 0.2.0 optionalDependencies: unrs-resolver: 1.11.1 @@ -6266,103 +6295,103 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@4.4.4(eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2))(eslint-import-resolver-node@0.3.10)(eslint@10.2.0(jiti@2.6.1)))(eslint-plugin-import@2.32.0)(eslint@10.2.0(jiti@2.6.1)): + eslint-import-resolver-typescript@4.4.4(eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.59.0(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint@10.2.1(jiti@2.6.1)))(eslint-plugin-import@2.32.0)(eslint@10.2.1(jiti@2.6.1)): dependencies: debug: 4.4.3 - eslint: 10.2.0(jiti@2.6.1) + eslint: 10.2.1(jiti@2.6.1) eslint-import-context: 0.1.9(unrs-resolver@1.11.1) - get-tsconfig: 4.13.7 + get-tsconfig: 4.14.0 is-bun-module: 2.0.0 stable-hash-x: 0.2.0 tinyglobby: 0.2.16 unrs-resolver: 1.11.1 optionalDependencies: - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2))(eslint-import-resolver-typescript@4.4.4)(eslint@10.2.0(jiti@2.6.1)) - eslint-plugin-import-x: 4.16.2(@typescript-eslint/utils@8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2))(eslint-import-resolver-node@0.3.10)(eslint@10.2.0(jiti@2.6.1)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.59.0(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3))(eslint-import-resolver-typescript@4.4.4)(eslint@10.2.1(jiti@2.6.1)) + eslint-plugin-import-x: 4.16.2(@typescript-eslint/utils@8.59.0(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint@10.2.1(jiti@2.6.1)) transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.1(@typescript-eslint/parser@8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@4.4.4)(eslint@10.2.0(jiti@2.6.1)): + eslint-module-utils@2.12.1(@typescript-eslint/parser@8.59.0(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@4.4.4)(eslint@10.2.1(jiti@2.6.1)): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2) - eslint: 10.2.0(jiti@2.6.1) + '@typescript-eslint/parser': 8.59.0(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3) + eslint: 10.2.1(jiti@2.6.1) eslint-import-resolver-node: 0.3.10 - eslint-import-resolver-typescript: 4.4.4(eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2))(eslint-import-resolver-node@0.3.10)(eslint@10.2.0(jiti@2.6.1)))(eslint-plugin-import@2.32.0)(eslint@10.2.0(jiti@2.6.1)) + eslint-import-resolver-typescript: 4.4.4(eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.59.0(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint@10.2.1(jiti@2.6.1)))(eslint-plugin-import@2.32.0)(eslint@10.2.1(jiti@2.6.1)) transitivePeerDependencies: - supports-color - eslint-plugin-array-func@5.1.1(eslint@10.2.0(jiti@2.6.1)): + eslint-plugin-array-func@5.1.1(eslint@10.2.1(jiti@2.6.1)): dependencies: - eslint: 10.2.0(jiti@2.6.1) + eslint: 10.2.1(jiti@2.6.1) - eslint-plugin-de-morgan@2.1.1(eslint@10.2.0(jiti@2.6.1)): + eslint-plugin-de-morgan@2.1.1(eslint@10.2.1(jiti@2.6.1)): dependencies: - eslint: 10.2.0(jiti@2.6.1) + eslint: 10.2.1(jiti@2.6.1) - eslint-plugin-escompat@3.11.4(eslint@10.2.0(jiti@2.6.1)): + eslint-plugin-escompat@3.11.4(eslint@10.2.1(jiti@2.6.1)): dependencies: browserslist: 4.28.2 - eslint: 10.2.0(jiti@2.6.1) + eslint: 10.2.1(jiti@2.6.1) - eslint-plugin-eslint-comments@3.2.0(eslint@10.2.0(jiti@2.6.1)): + eslint-plugin-eslint-comments@3.2.0(eslint@10.2.1(jiti@2.6.1)): dependencies: escape-string-regexp: 1.0.5 - eslint: 10.2.0(jiti@2.6.1) + eslint: 10.2.1(jiti@2.6.1) ignore: 5.3.2 - eslint-plugin-filenames@1.3.2(eslint@10.2.0(jiti@2.6.1)): + eslint-plugin-filenames@1.3.2(eslint@10.2.1(jiti@2.6.1)): dependencies: - eslint: 10.2.0(jiti@2.6.1) + eslint: 10.2.1(jiti@2.6.1) lodash.camelcase: 4.3.0 lodash.kebabcase: 4.1.1 lodash.snakecase: 4.1.1 lodash.upperfirst: 4.3.1 - eslint-plugin-github@6.0.0(eslint-import-resolver-typescript@4.4.4)(eslint@10.2.0(jiti@2.6.1)): + eslint-plugin-github@6.0.0(eslint-import-resolver-typescript@4.4.4)(eslint@10.2.1(jiti@2.6.1)): dependencies: - '@eslint/compat': 1.4.1(eslint@10.2.0(jiti@2.6.1)) + '@eslint/compat': 1.4.1(eslint@10.2.1(jiti@2.6.1)) '@eslint/eslintrc': 3.3.5 '@eslint/js': 9.39.4 '@github/browserslist-config': 1.0.0 - '@typescript-eslint/eslint-plugin': 8.58.2(@typescript-eslint/parser@8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2))(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/parser': 8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/eslint-plugin': 8.59.0(@typescript-eslint/parser@8.59.0(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3))(eslint@10.2.1(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/parser': 8.59.0(eslint@10.2.1(jiti@2.6.1))(typescript@5.9.3) aria-query: 5.3.2 - eslint: 10.2.0(jiti@2.6.1) - eslint-config-prettier: 10.1.8(eslint@10.2.0(jiti@2.6.1)) - eslint-plugin-escompat: 3.11.4(eslint@10.2.0(jiti@2.6.1)) - eslint-plugin-eslint-comments: 3.2.0(eslint@10.2.0(jiti@2.6.1)) - eslint-plugin-filenames: 1.3.2(eslint@10.2.0(jiti@2.6.1)) - eslint-plugin-i18n-text: 1.0.1(eslint@10.2.0(jiti@2.6.1)) - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2))(eslint-import-resolver-typescript@4.4.4)(eslint@10.2.0(jiti@2.6.1)) - eslint-plugin-jsx-a11y: 6.10.2(eslint@10.2.0(jiti@2.6.1)) + eslint: 10.2.1(jiti@2.6.1) + eslint-config-prettier: 10.1.8(eslint@10.2.1(jiti@2.6.1)) + eslint-plugin-escompat: 3.11.4(eslint@10.2.1(jiti@2.6.1)) + eslint-plugin-eslint-comments: 3.2.0(eslint@10.2.1(jiti@2.6.1)) + eslint-plugin-filenames: 1.3.2(eslint@10.2.1(jiti@2.6.1)) + eslint-plugin-i18n-text: 1.0.1(eslint@10.2.1(jiti@2.6.1)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.59.0(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3))(eslint-import-resolver-typescript@4.4.4)(eslint@10.2.1(jiti@2.6.1)) + eslint-plugin-jsx-a11y: 6.10.2(eslint@10.2.1(jiti@2.6.1)) eslint-plugin-no-only-tests: 3.3.0 - eslint-plugin-prettier: 5.5.5(eslint-config-prettier@10.1.8(eslint@10.2.0(jiti@2.6.1)))(eslint@10.2.0(jiti@2.6.1))(prettier@3.8.2) + eslint-plugin-prettier: 5.5.5(eslint-config-prettier@10.1.8(eslint@10.2.1(jiti@2.6.1)))(eslint@10.2.1(jiti@2.6.1))(prettier@3.8.3) eslint-rule-documentation: 1.0.23 globals: 16.5.0 jsx-ast-utils: 3.3.5 - prettier: 3.8.2 + prettier: 3.8.3 svg-element-attributes: 1.3.1 typescript: 5.9.3 - typescript-eslint: 8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3) + typescript-eslint: 8.59.0(eslint@10.2.1(jiti@2.6.1))(typescript@5.9.3) transitivePeerDependencies: - '@types/eslint' - eslint-import-resolver-typescript - eslint-import-resolver-webpack - supports-color - eslint-plugin-i18n-text@1.0.1(eslint@10.2.0(jiti@2.6.1)): + eslint-plugin-i18n-text@1.0.1(eslint@10.2.1(jiti@2.6.1)): dependencies: - eslint: 10.2.0(jiti@2.6.1) + eslint: 10.2.1(jiti@2.6.1) - eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2))(eslint-import-resolver-node@0.3.10)(eslint@10.2.0(jiti@2.6.1)): + eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.59.0(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint@10.2.1(jiti@2.6.1)): dependencies: '@package-json/types': 0.0.12 - '@typescript-eslint/types': 8.58.2 + '@typescript-eslint/types': 8.59.0 comment-parser: 1.4.6 debug: 4.4.3 - eslint: 10.2.0(jiti@2.6.1) + eslint: 10.2.1(jiti@2.6.1) eslint-import-context: 0.1.9(unrs-resolver@1.11.1) is-glob: 4.0.3 minimatch: 10.2.5 @@ -6370,12 +6399,12 @@ snapshots: stable-hash-x: 0.2.0 unrs-resolver: 1.11.1 optionalDependencies: - '@typescript-eslint/utils': 8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2) + '@typescript-eslint/utils': 8.59.0(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3) eslint-import-resolver-node: 0.3.10 transitivePeerDependencies: - supports-color - eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2))(eslint-import-resolver-typescript@4.4.4)(eslint@10.2.0(jiti@2.6.1)): + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.59.0(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3))(eslint-import-resolver-typescript@4.4.4)(eslint@10.2.1(jiti@2.6.1)): dependencies: '@rtsao/scc': 1.1.0 array-includes: '@nolyfill/array-includes@1.0.44' @@ -6384,9 +6413,9 @@ snapshots: array.prototype.flatmap: '@nolyfill/array.prototype.flatmap@1.0.44' debug: 3.2.7 doctrine: 2.1.0 - eslint: 10.2.0(jiti@2.6.1) + eslint: 10.2.1(jiti@2.6.1) eslint-import-resolver-node: 0.3.10 - eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@4.4.4)(eslint@10.2.0(jiti@2.6.1)) + eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.59.0(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@4.4.4)(eslint@10.2.1(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 @@ -6398,13 +6427,13 @@ snapshots: string.prototype.trimend: '@nolyfill/string.prototype.trimend@1.0.44' tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2) + '@typescript-eslint/parser': 8.59.0(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack - supports-color - eslint-plugin-jsx-a11y@6.10.2(eslint@10.2.0(jiti@2.6.1)): + eslint-plugin-jsx-a11y@6.10.2(eslint@10.2.1(jiti@2.6.1)): dependencies: aria-query: 5.3.2 array-includes: '@nolyfill/array-includes@1.0.44' @@ -6414,7 +6443,7 @@ snapshots: axobject-query: 4.1.0 damerau-levenshtein: 1.0.8 emoji-regex: 9.2.2 - eslint: 10.2.0(jiti@2.6.1) + eslint: 10.2.1(jiti@2.6.1) hasown: '@nolyfill/hasown@1.0.44' jsx-ast-utils: 3.3.5 language-tags: 1.0.9 @@ -6425,37 +6454,37 @@ snapshots: eslint-plugin-no-only-tests@3.3.0: {} - eslint-plugin-playwright@2.10.1(eslint@10.2.0(jiti@2.6.1)): + eslint-plugin-playwright@2.10.2(eslint@10.2.1(jiti@2.6.1)): dependencies: - eslint: 10.2.0(jiti@2.6.1) + eslint: 10.2.1(jiti@2.6.1) globals: 17.5.0 - eslint-plugin-prettier@5.5.5(eslint-config-prettier@10.1.8(eslint@10.2.0(jiti@2.6.1)))(eslint@10.2.0(jiti@2.6.1))(prettier@3.8.2): + eslint-plugin-prettier@5.5.5(eslint-config-prettier@10.1.8(eslint@10.2.1(jiti@2.6.1)))(eslint@10.2.1(jiti@2.6.1))(prettier@3.8.3): dependencies: - eslint: 10.2.0(jiti@2.6.1) - prettier: 3.8.2 + eslint: 10.2.1(jiti@2.6.1) + prettier: 3.8.3 prettier-linter-helpers: 1.0.1 synckit: 0.11.12 optionalDependencies: - eslint-config-prettier: 10.1.8(eslint@10.2.0(jiti@2.6.1)) + eslint-config-prettier: 10.1.8(eslint@10.2.1(jiti@2.6.1)) - eslint-plugin-regexp@3.1.0(eslint@10.2.0(jiti@2.6.1)): + eslint-plugin-regexp@3.1.0(eslint@10.2.1(jiti@2.6.1)): dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.2.0(jiti@2.6.1)) + '@eslint-community/eslint-utils': 4.9.1(eslint@10.2.1(jiti@2.6.1)) '@eslint-community/regexpp': 4.12.2 comment-parser: 1.4.6 - eslint: 10.2.0(jiti@2.6.1) + eslint: 10.2.1(jiti@2.6.1) jsdoc-type-pratt-parser: 7.2.0 refa: 0.12.1 regexp-ast-analysis: 0.7.1 scslre: 0.3.0 - eslint-plugin-sonarjs@4.0.2(eslint@10.2.0(jiti@2.6.1)): + eslint-plugin-sonarjs@4.0.3(eslint@10.2.1(jiti@2.6.1)): dependencies: '@eslint-community/regexpp': 4.12.2 builtin-modules: 3.3.0 bytes: 3.1.2 - eslint: 10.2.0(jiti@2.6.1) + eslint: 10.2.1(jiti@2.6.1) functional-red-black-tree: 1.0.1 globals: 17.5.0 jsx-ast-utils-x: 0.1.0 @@ -6463,18 +6492,18 @@ snapshots: minimatch: 10.2.5 scslre: 0.3.0 semver: 7.7.4 - ts-api-utils: 2.5.0(typescript@6.0.2) - typescript: 6.0.2 + ts-api-utils: 2.5.0(typescript@6.0.3) + typescript: 6.0.3 - eslint-plugin-unicorn@64.0.0(eslint@10.2.0(jiti@2.6.1)): + eslint-plugin-unicorn@64.0.0(eslint@10.2.1(jiti@2.6.1)): dependencies: '@babel/helper-validator-identifier': 7.28.5 - '@eslint-community/eslint-utils': 4.9.1(eslint@10.2.0(jiti@2.6.1)) + '@eslint-community/eslint-utils': 4.9.1(eslint@10.2.1(jiti@2.6.1)) change-case: 5.4.4 ci-info: 4.4.0 clean-regexp: 1.0.0 core-js-compat: 3.49.0 - eslint: 10.2.0(jiti@2.6.1) + eslint: 10.2.1(jiti@2.6.1) find-up-simple: 1.0.1 globals: 17.5.0 indent-string: 5.0.0 @@ -6486,33 +6515,33 @@ snapshots: semver: 7.7.4 strip-indent: 4.1.1 - eslint-plugin-vue-scoped-css@3.0.0(eslint@10.2.0(jiti@2.6.1))(vue-eslint-parser@10.4.0(eslint@10.2.0(jiti@2.6.1))): + eslint-plugin-vue-scoped-css@3.0.0(eslint@10.2.1(jiti@2.6.1))(vue-eslint-parser@10.4.0(eslint@10.2.1(jiti@2.6.1))): dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.2.0(jiti@2.6.1)) - eslint: 10.2.0(jiti@2.6.1) + '@eslint-community/eslint-utils': 4.9.1(eslint@10.2.1(jiti@2.6.1)) + eslint: 10.2.1(jiti@2.6.1) lodash: 4.18.1 - postcss: 8.5.9 - postcss-safe-parser: 7.0.1(postcss@8.5.9) + postcss: 8.5.10 + postcss-safe-parser: 7.0.1(postcss@8.5.10) postcss-selector-parser: 7.1.1 - vue-eslint-parser: 10.4.0(eslint@10.2.0(jiti@2.6.1)) + vue-eslint-parser: 10.4.0(eslint@10.2.1(jiti@2.6.1)) - eslint-plugin-vue@10.8.0(@stylistic/eslint-plugin@5.10.0(eslint@10.2.0(jiti@2.6.1)))(@typescript-eslint/parser@8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2))(eslint@10.2.0(jiti@2.6.1))(vue-eslint-parser@10.4.0(eslint@10.2.0(jiti@2.6.1))): + eslint-plugin-vue@10.8.0(@stylistic/eslint-plugin@5.10.0(eslint@10.2.1(jiti@2.6.1)))(@typescript-eslint/parser@8.59.0(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3))(eslint@10.2.1(jiti@2.6.1))(vue-eslint-parser@10.4.0(eslint@10.2.1(jiti@2.6.1))): dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.2.0(jiti@2.6.1)) - eslint: 10.2.0(jiti@2.6.1) + '@eslint-community/eslint-utils': 4.9.1(eslint@10.2.1(jiti@2.6.1)) + eslint: 10.2.1(jiti@2.6.1) natural-compare: 1.4.0 nth-check: 2.1.1 postcss-selector-parser: 7.1.1 semver: 7.7.4 - vue-eslint-parser: 10.4.0(eslint@10.2.0(jiti@2.6.1)) + vue-eslint-parser: 10.4.0(eslint@10.2.1(jiti@2.6.1)) xml-name-validator: 4.0.0 optionalDependencies: - '@stylistic/eslint-plugin': 5.10.0(eslint@10.2.0(jiti@2.6.1)) - '@typescript-eslint/parser': 8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2) + '@stylistic/eslint-plugin': 5.10.0(eslint@10.2.1(jiti@2.6.1)) + '@typescript-eslint/parser': 8.59.0(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3) - eslint-plugin-wc@3.1.0(eslint@10.2.0(jiti@2.6.1)): + eslint-plugin-wc@3.1.0(eslint@10.2.1(jiti@2.6.1)): dependencies: - eslint: 10.2.0(jiti@2.6.1) + eslint: 10.2.1(jiti@2.6.1) is-valid-element-name: 1.0.0 js-levenshtein-esm: 2.0.0 @@ -6531,15 +6560,15 @@ snapshots: eslint-visitor-keys@5.0.1: {} - eslint@10.2.0(jiti@2.6.1): + eslint@10.2.1(jiti@2.6.1): dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.2.0(jiti@2.6.1)) + '@eslint-community/eslint-utils': 4.9.1(eslint@10.2.1(jiti@2.6.1)) '@eslint-community/regexpp': 4.12.2 '@eslint/config-array': 0.23.5 '@eslint/config-helpers': 0.5.5 '@eslint/core': 1.2.1 '@eslint/plugin-kit': 0.7.1 - '@humanfs/node': 0.16.7 + '@humanfs/node': 0.16.8 '@humanwhocodes/module-importer': 1.0.1 '@humanwhocodes/retry': 0.4.3 '@types/estree': 1.0.8 @@ -6682,7 +6711,7 @@ snapshots: get-east-asian-width@1.5.0: {} - get-tsconfig@4.13.7: + get-tsconfig@4.14.0: dependencies: resolve-pkg-maps: 1.0.0 @@ -6725,7 +6754,7 @@ snapshots: hammerjs@2.0.8: {} - happy-dom@20.8.9: + happy-dom@20.9.0: dependencies: '@types/node': 25.6.0 '@types/whatwg-mimetype': 3.0.2 @@ -6930,7 +6959,7 @@ snapshots: lezer-elixir@1.1.3: dependencies: '@lezer/highlight': 1.2.3 - '@lezer/lr': 1.4.8 + '@lezer/lr': 1.4.10 lightningcss-android-arm64@1.32.0: optional: true @@ -7090,13 +7119,13 @@ snapshots: d3-sankey: 0.12.3 dagre-d3-es: 7.0.14 dayjs: 1.11.20 - dompurify: 3.3.3 + dompurify: 3.4.0 katex: 0.16.45 khroma: 2.1.0 lodash-es: 4.18.1 marked: 16.4.2 roughjs: 4.6.6 - stylis: 4.3.6 + stylis: 4.4.0 ts-dedent: 2.2.0 uuid: 11.1.0 @@ -7444,40 +7473,40 @@ snapshots: dependencies: htmlparser2: 8.0.2 js-tokens: 9.0.1 - postcss: 8.5.9 - postcss-safe-parser: 6.0.0(postcss@8.5.9) + postcss: 8.5.10 + postcss-safe-parser: 6.0.0(postcss@8.5.10) - postcss-import@15.1.0(postcss@8.5.9): + postcss-import@15.1.0(postcss@8.5.10): dependencies: - postcss: 8.5.9 + postcss: 8.5.10 postcss-value-parser: 4.2.0 read-cache: 1.0.0 resolve: 1.22.12 - postcss-js@4.1.0(postcss@8.5.9): + postcss-js@4.1.0(postcss@8.5.10): dependencies: camelcase-css: 2.0.1 - postcss: 8.5.9 + postcss: 8.5.10 - postcss-load-config@6.0.1(jiti@1.21.7)(postcss@8.5.9): + postcss-load-config@6.0.1(jiti@1.21.7)(postcss@8.5.10): dependencies: lilconfig: 3.1.3 optionalDependencies: jiti: 1.21.7 - postcss: 8.5.9 + postcss: 8.5.10 - postcss-nested@6.2.0(postcss@8.5.9): + postcss-nested@6.2.0(postcss@8.5.10): dependencies: - postcss: 8.5.9 + postcss: 8.5.10 postcss-selector-parser: 6.1.2 - postcss-safe-parser@6.0.0(postcss@8.5.9): + postcss-safe-parser@6.0.0(postcss@8.5.10): dependencies: - postcss: 8.5.9 + postcss: 8.5.10 - postcss-safe-parser@7.0.1(postcss@8.5.9): + postcss-safe-parser@7.0.1(postcss@8.5.10): dependencies: - postcss: 8.5.9 + postcss: 8.5.10 postcss-selector-parser@6.1.2: dependencies: @@ -7491,7 +7520,7 @@ snapshots: postcss-value-parser@4.2.0: {} - postcss@8.5.9: + postcss@8.5.10: dependencies: nanoid: 3.3.11 picocolors: 1.1.1 @@ -7503,7 +7532,7 @@ snapshots: dependencies: fast-diff: 1.3.0 - prettier@3.8.2: {} + prettier@3.8.3: {} punycode.js@2.3.1: {} @@ -7566,30 +7595,30 @@ snapshots: robust-predicates@3.0.3: {} - rolldown-license-plugin@2.2.5(rolldown@1.0.0-rc.15): + rolldown-license-plugin@3.0.1(rolldown@1.0.0-rc.16): dependencies: - rolldown: 1.0.0-rc.15 + rolldown: 1.0.0-rc.16 - rolldown@1.0.0-rc.15: + rolldown@1.0.0-rc.16: dependencies: - '@oxc-project/types': 0.124.0 - '@rolldown/pluginutils': 1.0.0-rc.15 + '@oxc-project/types': 0.126.0 + '@rolldown/pluginutils': 1.0.0-rc.16 optionalDependencies: - '@rolldown/binding-android-arm64': 1.0.0-rc.15 - '@rolldown/binding-darwin-arm64': 1.0.0-rc.15 - '@rolldown/binding-darwin-x64': 1.0.0-rc.15 - '@rolldown/binding-freebsd-x64': 1.0.0-rc.15 - '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-rc.15 - '@rolldown/binding-linux-arm64-gnu': 1.0.0-rc.15 - '@rolldown/binding-linux-arm64-musl': 1.0.0-rc.15 - '@rolldown/binding-linux-ppc64-gnu': 1.0.0-rc.15 - '@rolldown/binding-linux-s390x-gnu': 1.0.0-rc.15 - '@rolldown/binding-linux-x64-gnu': 1.0.0-rc.15 - '@rolldown/binding-linux-x64-musl': 1.0.0-rc.15 - '@rolldown/binding-openharmony-arm64': 1.0.0-rc.15 - '@rolldown/binding-wasm32-wasi': 1.0.0-rc.15 - '@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.15 - '@rolldown/binding-win32-x64-msvc': 1.0.0-rc.15 + '@rolldown/binding-android-arm64': 1.0.0-rc.16 + '@rolldown/binding-darwin-arm64': 1.0.0-rc.16 + '@rolldown/binding-darwin-x64': 1.0.0-rc.16 + '@rolldown/binding-freebsd-x64': 1.0.0-rc.16 + '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-rc.16 + '@rolldown/binding-linux-arm64-gnu': 1.0.0-rc.16 + '@rolldown/binding-linux-arm64-musl': 1.0.0-rc.16 + '@rolldown/binding-linux-ppc64-gnu': 1.0.0-rc.16 + '@rolldown/binding-linux-s390x-gnu': 1.0.0-rc.16 + '@rolldown/binding-linux-x64-gnu': 1.0.0-rc.16 + '@rolldown/binding-linux-x64-musl': 1.0.0-rc.16 + '@rolldown/binding-openharmony-arm64': 1.0.0-rc.16 + '@rolldown/binding-wasm32-wasi': 1.0.0-rc.16 + '@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.16 + '@rolldown/binding-win32-x64-msvc': 1.0.0-rc.16 roughjs@4.6.6: dependencies: @@ -7673,7 +7702,7 @@ snapshots: stackback@0.0.2: {} - std-env@4.0.0: {} + std-env@4.1.0: {} string-width@4.2.3: dependencies: @@ -7709,25 +7738,25 @@ snapshots: style-search@0.1.0: {} - stylelint-config-recommended@18.0.0(stylelint@17.7.0(typescript@6.0.2)): + stylelint-config-recommended@18.0.0(stylelint@17.8.0(typescript@6.0.3)): dependencies: - stylelint: 17.7.0(typescript@6.0.2) + stylelint: 17.8.0(typescript@6.0.3) - stylelint-declaration-block-no-ignored-properties@3.0.0(stylelint@17.7.0(typescript@6.0.2)): + stylelint-declaration-block-no-ignored-properties@3.0.0(stylelint@17.8.0(typescript@6.0.3)): dependencies: - stylelint: 17.7.0(typescript@6.0.2) + stylelint: 17.8.0(typescript@6.0.3) - stylelint-declaration-strict-value@1.11.1(stylelint@17.7.0(typescript@6.0.2)): + stylelint-declaration-strict-value@1.11.1(stylelint@17.8.0(typescript@6.0.3)): dependencies: - stylelint: 17.7.0(typescript@6.0.2) + stylelint: 17.8.0(typescript@6.0.3) - stylelint-value-no-unknown-custom-properties@6.1.1(stylelint@17.7.0(typescript@6.0.2)): + stylelint-value-no-unknown-custom-properties@6.1.1(stylelint@17.8.0(typescript@6.0.3)): dependencies: postcss-value-parser: 4.2.0 resolve: 1.22.12 - stylelint: 17.7.0(typescript@6.0.2) + stylelint: 17.8.0(typescript@6.0.3) - stylelint@17.7.0(typescript@6.0.2): + stylelint@17.8.0(typescript@6.0.3): dependencies: '@csstools/css-calc': 3.2.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) @@ -7737,7 +7766,7 @@ snapshots: '@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) colord: 2.9.3 - cosmiconfig: 9.0.1(typescript@6.0.2) + cosmiconfig: 9.0.1(typescript@6.0.3) css-functions-list: 3.3.3 css-tree: 3.2.1 debug: 4.4.3 @@ -7756,8 +7785,8 @@ snapshots: micromatch: 4.0.8 normalize-path: 3.0.0 picocolors: 1.1.1 - postcss: 8.5.9 - postcss-safe-parser: 7.0.1(postcss@8.5.9) + postcss: 8.5.10 + postcss-safe-parser: 7.0.1(postcss@8.5.10) postcss-selector-parser: 7.1.1 postcss-value-parser: 4.2.0 string-width: 8.2.0 @@ -7769,7 +7798,7 @@ snapshots: - supports-color - typescript - stylis@4.3.6: {} + stylis@4.4.0: {} sucrase@3.35.1: dependencies: @@ -7809,7 +7838,7 @@ snapshots: deep-rename-keys: 0.2.1 xml-reader: 2.4.3 - swagger-ui-dist@5.32.2: + swagger-ui-dist@5.32.4: dependencies: '@scarf/scarf': 1.4.0 @@ -7848,11 +7877,11 @@ snapshots: normalize-path: 3.0.0 object-hash: 3.0.0 picocolors: 1.1.1 - postcss: 8.5.9 - postcss-import: 15.1.0(postcss@8.5.9) - postcss-js: 4.1.0(postcss@8.5.9) - postcss-load-config: 6.0.1(jiti@1.21.7)(postcss@8.5.9) - postcss-nested: 6.2.0(postcss@8.5.9) + postcss: 8.5.10 + postcss-import: 15.1.0(postcss@8.5.10) + postcss-js: 4.1.0(postcss@8.5.10) + postcss-load-config: 6.0.1(jiti@1.21.7)(postcss@8.5.10) + postcss-nested: 6.2.0(postcss@8.5.10) postcss-selector-parser: 6.1.2 resolve: 1.22.12 sucrase: 3.35.1 @@ -7901,9 +7930,9 @@ snapshots: dependencies: typescript: 5.9.3 - ts-api-utils@2.5.0(typescript@6.0.2): + ts-api-utils@2.5.0(typescript@6.0.3): dependencies: - typescript: 6.0.2 + typescript: 6.0.3 ts-dedent@2.2.0: {} @@ -7922,31 +7951,31 @@ snapshots: dependencies: prelude-ls: 1.2.1 - typescript-eslint@8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3): + typescript-eslint@8.59.0(eslint@10.2.1(jiti@2.6.1))(typescript@5.9.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.58.2(@typescript-eslint/parser@8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2))(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/parser': 8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/typescript-estree': 8.58.2(typescript@5.9.3) - '@typescript-eslint/utils': 8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3) - eslint: 10.2.0(jiti@2.6.1) + '@typescript-eslint/eslint-plugin': 8.59.0(@typescript-eslint/parser@8.59.0(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3))(eslint@10.2.1(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/parser': 8.59.0(eslint@10.2.1(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/typescript-estree': 8.59.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.59.0(eslint@10.2.1(jiti@2.6.1))(typescript@5.9.3) + eslint: 10.2.1(jiti@2.6.1) typescript: 5.9.3 transitivePeerDependencies: - supports-color - typescript-eslint@8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2): + typescript-eslint@8.59.0(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.58.2(@typescript-eslint/parser@8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2))(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2) - '@typescript-eslint/parser': 8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2) - '@typescript-eslint/typescript-estree': 8.58.2(typescript@6.0.2) - '@typescript-eslint/utils': 8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2) - eslint: 10.2.0(jiti@2.6.1) - typescript: 6.0.2 + '@typescript-eslint/eslint-plugin': 8.59.0(@typescript-eslint/parser@8.59.0(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3))(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3) + '@typescript-eslint/parser': 8.59.0(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3) + '@typescript-eslint/typescript-estree': 8.59.0(typescript@6.0.3) + '@typescript-eslint/utils': 8.59.0(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3) + eslint: 10.2.1(jiti@2.6.1) + typescript: 6.0.3 transitivePeerDependencies: - supports-color typescript@5.9.3: {} - typescript@6.0.2: {} + typescript@6.0.3: {} typo-js@1.3.1: {} @@ -7990,7 +8019,7 @@ snapshots: escalade: 3.2.0 picocolors: 1.1.1 - updates@17.15.3: {} + updates@17.15.5: {} uri-js@4.4.1: dependencies: @@ -8002,16 +8031,16 @@ snapshots: vanilla-colorful@0.7.2: {} - vite-string-plugin@2.0.2(vite@8.0.8(@types/node@25.6.0)(esbuild@0.28.0)(jiti@2.6.1)): + vite-string-plugin@2.0.2(vite@8.0.9(@types/node@25.6.0)(esbuild@0.28.0)(jiti@2.6.1)): dependencies: - vite: 8.0.8(@types/node@25.6.0)(esbuild@0.28.0)(jiti@2.6.1) + vite: 8.0.9(@types/node@25.6.0)(esbuild@0.28.0)(jiti@2.6.1) - vite@8.0.8(@types/node@25.6.0)(esbuild@0.28.0)(jiti@2.6.1): + vite@8.0.9(@types/node@25.6.0)(esbuild@0.28.0)(jiti@2.6.1): dependencies: lightningcss: 1.32.0 picomatch: 4.0.4 - postcss: 8.5.9 - rolldown: 1.0.0-rc.15 + postcss: 8.5.10 + rolldown: 1.0.0-rc.16 tinyglobby: 0.2.16 optionalDependencies: '@types/node': 25.6.0 @@ -8019,10 +8048,10 @@ snapshots: fsevents: 2.3.3 jiti: 2.6.1 - vitest@4.1.4(@types/node@25.6.0)(happy-dom@20.8.9)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.28.0)(jiti@2.6.1)): + vitest@4.1.4(@types/node@25.6.0)(happy-dom@20.9.0)(vite@8.0.9(@types/node@25.6.0)(esbuild@0.28.0)(jiti@2.6.1)): dependencies: '@vitest/expect': 4.1.4 - '@vitest/mocker': 4.1.4(vite@8.0.8(@types/node@25.6.0)(esbuild@0.28.0)(jiti@2.6.1)) + '@vitest/mocker': 4.1.4(vite@8.0.9(@types/node@25.6.0)(esbuild@0.28.0)(jiti@2.6.1)) '@vitest/pretty-format': 4.1.4 '@vitest/runner': 4.1.4 '@vitest/snapshot': 4.1.4 @@ -8034,16 +8063,16 @@ snapshots: obug: 2.1.1 pathe: 2.0.3 picomatch: 4.0.4 - std-env: 4.0.0 + std-env: 4.1.0 tinybench: 2.9.0 tinyexec: 1.1.1 tinyglobby: 0.2.16 tinyrainbow: 3.1.0 - vite: 8.0.8(@types/node@25.6.0)(esbuild@0.28.0)(jiti@2.6.1) + vite: 8.0.9(@types/node@25.6.0)(esbuild@0.28.0)(jiti@2.6.1) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 25.6.0 - happy-dom: 20.8.9 + happy-dom: 20.9.0 transitivePeerDependencies: - msw @@ -8064,21 +8093,21 @@ snapshots: vscode-uri@3.1.0: {} - vue-bar-graph@2.2.0(typescript@6.0.2): + vue-bar-graph@2.2.0(typescript@6.0.3): dependencies: - vue: 3.5.32(typescript@6.0.2) + vue: 3.5.32(typescript@6.0.3) transitivePeerDependencies: - typescript - vue-chartjs@5.3.3(chart.js@4.5.1)(vue@3.5.32(typescript@6.0.2)): + vue-chartjs@5.3.3(chart.js@4.5.1)(vue@3.5.32(typescript@6.0.3)): dependencies: chart.js: 4.5.1 - vue: 3.5.32(typescript@6.0.2) + vue: 3.5.32(typescript@6.0.3) - vue-eslint-parser@10.4.0(eslint@10.2.0(jiti@2.6.1)): + vue-eslint-parser@10.4.0(eslint@10.2.1(jiti@2.6.1)): dependencies: debug: 4.4.3 - eslint: 10.2.0(jiti@2.6.1) + eslint: 10.2.1(jiti@2.6.1) eslint-scope: 9.1.2 eslint-visitor-keys: 5.0.1 espree: 11.2.0 @@ -8087,21 +8116,21 @@ snapshots: transitivePeerDependencies: - supports-color - vue-tsc@3.2.6(typescript@6.0.2): + vue-tsc@3.2.7(typescript@6.0.3): dependencies: '@volar/typescript': 2.4.28 - '@vue/language-core': 3.2.6 - typescript: 6.0.2 + '@vue/language-core': 3.2.7 + typescript: 6.0.3 - vue@3.5.32(typescript@6.0.2): + vue@3.5.32(typescript@6.0.3): dependencies: '@vue/compiler-dom': 3.5.32 '@vue/compiler-sfc': 3.5.32 '@vue/runtime-dom': 3.5.32 - '@vue/server-renderer': 3.5.32(vue@3.5.32(typescript@6.0.2)) + '@vue/server-renderer': 3.5.32(vue@3.5.32(typescript@6.0.3)) '@vue/shared': 3.5.32 optionalDependencies: - typescript: 6.0.2 + typescript: 6.0.3 w3c-keyname@2.2.8: {} diff --git a/services/cron/cron.go b/services/cron/cron.go index 7a4eb21bbbd..a0b3c7b5ac2 100644 --- a/services/cron/cron.go +++ b/services/cron/cron.go @@ -111,7 +111,7 @@ func ListTasks() TaskTable { spec = tags[1] // the second tag is the task spec } next, _ = e.NextRun() - prev, _ = e.LastRun() + prev, _ = e.LastRunStartedAt() } task.lock.Lock() diff --git a/web_src/js/features/admin/config.test.ts b/web_src/js/features/admin/config.test.ts index 3de524070cb..b8468610ca5 100644 --- a/web_src/js/features/admin/config.test.ts +++ b/web_src/js/features/admin/config.test.ts @@ -29,7 +29,7 @@ test('ConfigFormValueMapper', () => { mapper.fillFromSystemConfig(); const formData = mapper.collectToFormData(); const result: Record = {}; - const keys = [], values = []; + const keys: string[] = [], values: string[] = []; for (const [key, value] of formData.entries()) { if (key === 'key') keys.push(value as string); if (key === 'value') values.push(value as string); diff --git a/web_src/js/features/tribute.ts b/web_src/js/features/tribute.ts index 462a925ab67..713e297f810 100644 --- a/web_src/js/features/tribute.ts +++ b/web_src/js/features/tribute.ts @@ -50,9 +50,9 @@ export async function attachTribute(element: HTMLElement) { const tribute = new Tribute({ collection: [ - emojiCollection as TributeCollection, - mentionCollection as TributeCollection, - ], + emojiCollection, + mentionCollection, + ] as TributeCollection[], noMatchTemplate: () => '', }); tribute.attach(element); diff --git a/web_src/js/modules/fomantic/dropdown.ts b/web_src/js/modules/fomantic/dropdown.ts index b98a5cf3f41..e49c410682f 100644 --- a/web_src/js/modules/fomantic/dropdown.ts +++ b/web_src/js/modules/fomantic/dropdown.ts @@ -324,7 +324,7 @@ export function hideScopedEmptyDividers(container: Element) { handleScopeSwitch(itemScope); } if (!isHidden(item)) { - curScopeVisibleItems.push(item as HTMLElement); + curScopeVisibleItems.push(item); } } handleScopeSwitch(''); diff --git a/web_src/js/webcomponents/relative-time.ts b/web_src/js/webcomponents/relative-time.ts index 8a5d9887337..e9e668bfc45 100644 --- a/web_src/js/webcomponents/relative-time.ts +++ b/web_src/js/webcomponents/relative-time.ts @@ -432,7 +432,7 @@ class RelativeTime extends HTMLElement { const value = d[`${unit}s` as keyof Duration] as number; if (value || (duration.blank && unit === 'second')) { try { - parts.push(new Intl.NumberFormat(locale, {style: 'unit', unit, unitDisplay: style} as Intl.NumberFormatOptions).format(value)); + parts.push(new Intl.NumberFormat(locale, {style: 'unit', unit, unitDisplay: style}).format(value)); } catch { // PaleMoon lacks Intl.NumberFormat unit style support parts.push(`${value} ${value === 1 ? unit : `${unit}s`}`); } From 85c09b8f453f4b6085e9069c83d268dea261178f Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 20 Apr 2026 16:57:08 -0700 Subject: [PATCH 10/66] Fix AppFullLink (#37325) Fix a bug the checkout command line hint becomes `git fetch -u https://gitea.combircni/tea` --- services/context/context_template.go | 2 +- services/context/context_test.go | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/services/context/context_template.go b/services/context/context_template.go index 2b34681faa4..2c8fde6870d 100644 --- a/services/context/context_template.go +++ b/services/context/context_template.go @@ -88,7 +88,7 @@ func (c TemplateContext) AppFullLink(link ...string) template.URL { if len(link) == 0 { return template.URL(s) } - return template.URL(s + strings.TrimPrefix(link[0], "/")) + return template.URL(s + "/" + strings.TrimPrefix(link[0], "/")) } var globalVars = sync.OnceValue(func() (ret struct { diff --git a/services/context/context_test.go b/services/context/context_test.go index 54044644f07..aaf79de7163 100644 --- a/services/context/context_test.go +++ b/services/context/context_test.go @@ -49,3 +49,17 @@ func TestRedirectToCurrentSite(t *testing.T) { }) } } + +func TestAppFullLink(t *testing.T) { + setting.IsInTesting = true + defer test.MockVariableValue(&setting.AppURL, "https://gitea.example.com/sub/")() + defer test.MockVariableValue(&setting.AppSubURL, "/sub")() + defer test.MockVariableValue(&setting.PublicURLDetection, setting.PublicURLNever)() + + req := httptest.NewRequest(http.MethodGet, "https://gitea.example.com/sub/", nil) + tmplCtx := NewTemplateContext(req.Context(), req) + + assert.Equal(t, "https://gitea.example.com/sub", string(tmplCtx.AppFullLink())) + assert.Equal(t, "https://gitea.example.com/sub/user/repo", string(tmplCtx.AppFullLink("user/repo"))) + assert.Equal(t, "https://gitea.example.com/sub/user/repo", string(tmplCtx.AppFullLink("/user/repo"))) +} From 12733d362451ba2ca8af67d6d290a9cc77ab185a Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 20 Apr 2026 18:18:12 -0700 Subject: [PATCH 11/66] Fix bug when accessing user badges (#37321) Fix #37302 --------- Co-authored-by: silverwind --- models/user/badge.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models/user/badge.go b/models/user/badge.go index a41eda07b5e..a4a465a9d54 100644 --- a/models/user/badge.go +++ b/models/user/badge.go @@ -64,7 +64,7 @@ type GetBadgeUsersOptions struct { func GetBadgeUsers(ctx context.Context, opts *GetBadgeUsersOptions) ([]*User, int64, error) { sess := db.GetEngine(ctx). Select("`user`.*"). - Join("INNER", "user_badge", "`user_badge`.user_id=user.id"). + Join("INNER", "user_badge", "`user_badge`.user_id=`user`.id"). Join("INNER", "badge", "`user_badge`.badge_id=badge.id"). Where("badge.slug=?", opts.BadgeSlug) From f94b476c45579f94359139810b1d9167950f0747 Mon Sep 17 00:00:00 2001 From: silverwind Date: Tue, 21 Apr 2026 04:25:36 +0200 Subject: [PATCH 12/66] Fix actions concurrency groups cross-branch leak (#37311) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Problem Workflow-level concurrency groups were evaluated — and jobs were parsed — before the run was persisted, so `run.ID` was `0` and `github.run_id` in the expression context resolved to an empty string. Expressions like: ```yaml concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} cancel-in-progress: true ``` collapsed to `-` on every push event (`head_ref` is empty on push), so `cancel-in-progress` cancelled in-progress runs across **unrelated branches**, not just the current one. Reproduced on a 1.26 instance: - push to `master` → `ci` run starts - push to `feature-branch` → the `master` run gets cancelled GitHub Actions' documented semantic: on push events `github.run_id` is unique per run, so the group is unique → no cancellation; on PR events `github.head_ref` is the source branch → cancellation is per-PR. ## Fix Insert the run **before** parsing jobs or evaluating workflow-level concurrency, so `run.ID` is populated in time for every expression that reads `github.run_id` — not just the concurrency group, but also `run-name`, job names, and `runs-on`. `jobparser.Parse` now runs inside the `InsertRun` transaction, after `db.Insert(ctx, run)`. Workflow-level concurrency evaluation runs next and only mutates `run` in memory. All concurrency-derived fields (`raw_concurrency`, `concurrency_group`, `concurrency_cancel`) plus `status` and `title` are persisted in a single final `UpdateRun` at end-of-transaction — one `INSERT` + one `UPDATE` per run in both the concurrency and non-concurrency paths (matches pre-branch parity, one fewer `UpdateRepoRunsNumbers` `COUNT` than the interim state). `GenerateGiteaContext` now sets `run_id` from `run.ID` unconditionally; every caller passes a persisted run. **Verification**: tested end-to-end on a 1.26 deployment. Before the patch, two successive `ci` pushes (one to master, one to a feature branch) cross-cancelled each other. After the patch, the same pushes — in both orders (master→branch, branch→master) — run to completion simultaneously across 15+ runs with zero cancellations. **Regression tests** in `services/actions/context_test.go`: - `TestEvaluateRunConcurrency_RunIDFallback` — unit check that `EvaluateRunConcurrencyFillModel` resolves `github.run_id` from `run.ID`. - `TestPrepareRunAndInsert_ExpressionsSeeRunID` — full-flow check: calls `PrepareRunAndInsert` with `${{ github.run_id }}` in both `run-name` and the concurrency group, then asserts the persisted `Title`, `ConcurrencyGroup`, and `RawConcurrency` contain / survive the run's ID. Re-ordering `db.Insert` relative to either parse or concurrency eval fails this test. ## Relation to #37119 [#37119](https://github.com/go-gitea/gitea/pull/37119) also moves concurrency evaluation into `InsertRun` but keeps it **before** `db.Insert`, then tries to populate `run_id` only when `run.ID > 0` — which is still `0` at that call site, so the cross-branch leak would survive that PR as written. This PR fixes the ordering so that `run.ID` is actually populated at eval time, and broadens it to cover parse-time expression interpolation too. Co-authored-by: Claude (Opus 4.7) --- services/actions/context.go | 2 +- services/actions/context_test.go | 72 ++++++++++++++++++++++++++++++++ services/actions/run.go | 65 ++++++++++++++-------------- 3 files changed, 107 insertions(+), 32 deletions(-) diff --git a/services/actions/context.go b/services/actions/context.go index 626ae6ee6bf..69d59376232 100644 --- a/services/actions/context.go +++ b/services/actions/context.go @@ -73,7 +73,7 @@ func GenerateGiteaContext(run *actions_model.ActionRun, job *actions_model.Actio "repository_owner": run.Repo.OwnerName, // string, The repository owner's name. For example, Codertocat. "repositoryUrl": run.Repo.HTMLURL(), // string, The Git URL to the repository. For example, git://github.com/codertocat/hello-world.git. "retention_days": "", // string, The number of days that workflow run logs and artifacts are kept. - "run_id": "", // string, A unique number for each workflow run within a repository. This number does not change if you re-run the workflow run. + "run_id": strconv.FormatInt(run.ID, 10), // string, A unique number for each workflow run within a repository. This number does not change if you re-run the workflow run. "run_number": strconv.FormatInt(run.Index, 10), // string, A unique number for each run of a particular workflow in a repository. This number begins at 1 for the workflow's first run, and increments with each new run. This number does not change if you re-run the workflow run. "run_attempt": "", // string, A unique number for each attempt of a particular workflow run in a repository. This number begins at 1 for the workflow run's first attempt, and increments with each re-run. "secret_source": "Actions", // string, The source of a secret used in a workflow. Possible values are None, Actions, Dependabot, or Codespaces. diff --git a/services/actions/context_test.go b/services/actions/context_test.go index 74ef694021a..4ade67111cf 100644 --- a/services/actions/context_test.go +++ b/services/actions/context_test.go @@ -4,14 +4,86 @@ package actions import ( + "strconv" "testing" actions_model "code.gitea.io/gitea/models/actions" "code.gitea.io/gitea/models/unittest" + act_model "github.com/nektos/act/pkg/model" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) +func TestEvaluateRunConcurrency_RunIDFallback(t *testing.T) { + // Unit-level check that EvaluateRunConcurrencyFillModel resolves + // github.run_id from run.ID. The full-flow regression — that run.ID is + // non-zero by the time evaluation happens — is in + // TestPrepareRunAndInsert_ExpressionsSeeRunID. + assert.NoError(t, unittest.PrepareTestDatabase()) + ctx := t.Context() + + runA := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{ID: 791}) + runB := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{ID: 792}) + + expr := &act_model.RawConcurrency{ + Group: "${{ github.workflow }}-${{ github.head_ref || github.run_id }}", + CancelInProgress: "true", + } + + assert.NoError(t, EvaluateRunConcurrencyFillModel(ctx, runA, expr, nil, nil)) + assert.NoError(t, EvaluateRunConcurrencyFillModel(ctx, runB, expr, nil, nil)) + + assert.Contains(t, runA.ConcurrencyGroup, "791") + assert.Contains(t, runB.ConcurrencyGroup, "792") + assert.NotEqual(t, runA.ConcurrencyGroup, runB.ConcurrencyGroup) +} + +func TestPrepareRunAndInsert_ExpressionsSeeRunID(t *testing.T) { + // Regression for the cross-branch concurrency leak: github.run_id must + // be available during BOTH jobparser.Parse (run-name) and workflow-level + // concurrency evaluation. Re-ordering db.Insert relative to either step + // would leave run.ID at 0 and break this test. + assert.NoError(t, unittest.PrepareTestDatabase()) + ctx := t.Context() + + content := []byte(`name: cross-branch +run-name: "Run ${{ github.run_id }}" +on: push +concurrency: + group: group-${{ github.run_id }} + cancel-in-progress: true +jobs: + hello: + runs-on: ubuntu-latest + steps: + - run: echo hi +`) + + run := &actions_model.ActionRun{ + Title: "before parse", + RepoID: 4, + OwnerID: 1, + WorkflowID: "expr-runid.yaml", + TriggerUserID: 1, + Ref: "refs/heads/master", + CommitSHA: "c2d72f548424103f01ee1dc02889c1e2bff816b0", + Event: "push", + TriggerEvent: "push", + EventPayload: "{}", + } + require.NoError(t, PrepareRunAndInsert(ctx, content, run, nil)) + require.Positive(t, run.ID) + + persisted := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{ID: run.ID}) + runIDStr := strconv.FormatInt(run.ID, 10) + assert.Equal(t, "Run "+runIDStr, persisted.Title) + assert.Equal(t, "group-"+runIDStr, persisted.ConcurrencyGroup) + // Rerun reads raw_concurrency from the DB to re-evaluate the group; + // see services/actions/rerun.go. Must survive the insert. + assert.NotEmpty(t, persisted.RawConcurrency) +} + func TestFindTaskNeeds(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) diff --git a/services/actions/run.go b/services/actions/run.go index e9fcdcaf43d..432bb196284 100644 --- a/services/actions/run.go +++ b/services/actions/run.go @@ -13,6 +13,7 @@ import ( "code.gitea.io/gitea/modules/util" notify_service "code.gitea.io/gitea/services/notify" + act_model "github.com/nektos/act/pkg/model" "go.yaml.in/yaml/v4" ) @@ -34,25 +35,7 @@ func PrepareRunAndInsert(ctx context.Context, content []byte, run *actions_model return fmt.Errorf("ReadWorkflowRawConcurrency: %w", err) } - if wfRawConcurrency != nil { - err = EvaluateRunConcurrencyFillModel(ctx, run, wfRawConcurrency, vars, inputsWithDefaults) - if err != nil { - return fmt.Errorf("EvaluateRunConcurrencyFillModel: %w", err) - } - } - - giteaCtx := GenerateGiteaContext(run, nil) - - jobs, err := jobparser.Parse(content, jobparser.WithVars(vars), jobparser.WithGitContext(giteaCtx.ToGitHubContext()), jobparser.WithInputs(inputsWithDefaults)) - if err != nil { - return fmt.Errorf("parse workflow: %w", err) - } - - if len(jobs) > 0 && jobs[0].RunName != "" { - run.Title = jobs[0].RunName - } - - if err = InsertRun(ctx, run, jobs, vars, inputsWithDefaults); err != nil { + if err = InsertRun(ctx, run, content, vars, inputsWithDefaults, wfRawConcurrency); err != nil { return fmt.Errorf("InsertRun: %w", err) } @@ -74,7 +57,7 @@ func PrepareRunAndInsert(ctx context.Context, content []byte, run *actions_model // InsertRun inserts a run // The title will be cut off at 255 characters if it's longer than 255 characters. -func InsertRun(ctx context.Context, run *actions_model.ActionRun, jobs []*jobparser.SingleWorkflow, vars map[string]string, inputs map[string]any) error { +func InsertRun(ctx context.Context, run *actions_model.ActionRun, content []byte, vars map[string]string, inputs map[string]any, wfRawConcurrency *act_model.RawConcurrency) error { return db.WithTx(ctx, func(ctx context.Context) error { index, err := db.GetNextResourceIndex(ctx, "action_run_index", run.RepoID) if err != nil { @@ -82,23 +65,36 @@ func InsertRun(ctx context.Context, run *actions_model.ActionRun, jobs []*jobpar } run.Index = index run.Title = util.EllipsisDisplayString(run.Title, 255) + run.Status = actions_model.StatusWaiting - // check run (workflow-level) concurrency - run.Status, err = PrepareToStartRunWithConcurrency(ctx, run) - if err != nil { - return err - } - + // Insert before parsing jobs or evaluating workflow-level concurrency + // so that run.ID is populated. Expressions referencing github.run_id — + // in run-name, job names, runs-on, or a workflow-level concurrency + // group like `${{ github.head_ref || github.run_id }}` — would otherwise + // interpolate to an empty string. if err := db.Insert(ctx, run); err != nil { return err } - if err := run.LoadRepo(ctx); err != nil { - return err + giteaCtx := GenerateGiteaContext(run, nil) + jobs, err := jobparser.Parse(content, jobparser.WithVars(vars), jobparser.WithGitContext(giteaCtx.ToGitHubContext()), jobparser.WithInputs(inputs)) + if err != nil { + return fmt.Errorf("parse workflow: %w", err) } - if err := actions_model.UpdateRepoRunsNumbers(ctx, run.Repo); err != nil { - return err + titleChanged := len(jobs) > 0 && jobs[0].RunName != "" + if titleChanged { + run.Title = util.EllipsisDisplayString(jobs[0].RunName, 255) + } + + if wfRawConcurrency != nil { + if err := EvaluateRunConcurrencyFillModel(ctx, run, wfRawConcurrency, vars, inputs); err != nil { + return fmt.Errorf("EvaluateRunConcurrencyFillModel: %w", err) + } + run.Status, err = PrepareToStartRunWithConcurrency(ctx, run) + if err != nil { + return err + } } runJobs := make([]*actions_model.ActionRunJob, 0, len(jobs)) @@ -168,7 +164,14 @@ func InsertRun(ctx context.Context, run *actions_model.ActionRun, jobs []*jobpar } run.Status = actions_model.AggregateJobStatus(runJobs) - if err := actions_model.UpdateRun(ctx, run, "status"); err != nil { + cols := []string{"status"} + if titleChanged { + cols = append(cols, "title") + } + if wfRawConcurrency != nil { + cols = append(cols, "raw_concurrency", "concurrency_group", "concurrency_cancel") + } + if err := actions_model.UpdateRun(ctx, run, cols...); err != nil { return err } From 63db5972a14aed725cfe61e2a192c7a7278cd0a0 Mon Sep 17 00:00:00 2001 From: prettysunflower Date: Tue, 21 Apr 2026 01:58:04 -0400 Subject: [PATCH 13/66] fix(oauth): Error on auth sources with spaces (#37327) The link to authentication sources is now escaped with the QueryEscape. This commit fixes that by unescaping the provider name in the URL. --------- Signed-off-by: prettysunflower Signed-off-by: wxiaoguang Co-authored-by: wxiaoguang --- routers/web/auth/oauth.go | 4 +++- tests/integration/oauth_test.go | 33 ++++++++++++++++++++++++++++++--- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/routers/web/auth/oauth.go b/routers/web/auth/oauth.go index 8645aedbdee..e3f7e382424 100644 --- a/routers/web/auth/oauth.go +++ b/routers/web/auth/oauth.go @@ -36,7 +36,9 @@ import ( // SignInOAuth handles the OAuth2 login buttons func SignInOAuth(ctx *context.Context) { - authName := ctx.PathParam("provider") + // the provider is escaped by backend QueryEscape and frontend urlQueryEscape + // so always use QueryUnescape to decode it + authName, _ := url.QueryUnescape(ctx.PathParamRaw("provider")) authSource, err := auth.GetActiveOAuth2SourceByAuthName(ctx, authName) if err != nil { ctx.ServerError("SignIn", err) diff --git a/tests/integration/oauth_test.go b/tests/integration/oauth_test.go index de02a5a0c37..b28f81a0483 100644 --- a/tests/integration/oauth_test.go +++ b/tests/integration/oauth_test.go @@ -44,6 +44,8 @@ func TestOAuth2Provider(t *testing.T) { t.Run("AuthorizeLoginRedirect", testAuthorizeLoginRedirect) t.Run("OAuth2WellKnown", testOAuth2WellKnown) + t.Run("OAuthSourceWithSpace", testOAuthSourceWithSpace) + // TODO: move more tests as sub-tests here, avoid unnecessary PrepareTestEnv } func testAuthorizeNoClientID(t *testing.T) { @@ -995,9 +997,7 @@ func addOAuth2Source(t *testing.T, authName string, cfg oauth2.Source) { require.NoError(t, err) } -func TestSignInOauthCallbackSyncSSHKeys(t *testing.T) { - defer tests.PrepareTestEnv(t)() - +func createMockServer() *httptest.Server { var mockServer *httptest.Server mockServer = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { switch r.URL.Path { @@ -1012,6 +1012,14 @@ func TestSignInOauthCallbackSyncSSHKeys(t *testing.T) { http.NotFound(w, r) } })) + + return mockServer +} + +func TestSignInOauthCallbackSyncSSHKeys(t *testing.T) { + defer tests.PrepareTestEnv(t)() + + mockServer := createMockServer() defer mockServer.Close() ctx := t.Context() @@ -1087,3 +1095,22 @@ func TestSignInOauthCallbackSyncSSHKeys(t *testing.T) { }) } } + +// Checks if an OAuth provider with spaces within the name does work, +// with the encoding of its names in the URL (PR#37327) +func testOAuthSourceWithSpace(t *testing.T) { + mockServer := createMockServer() + defer mockServer.Close() + + authName := "oauth test with spaces" + oauth2Source := oauth2.Source{ + Provider: "openidConnect", + OpenIDConnectAutoDiscoveryURL: mockServer.URL + "/.well-known/openid-configuration", + } + addOAuth2Source(t, authName, oauth2Source) + + session := emptyTestSession(t) + req := NewRequest(t, "GET", "/user/oauth2/"+url.QueryEscape(authName)) + resp := session.MakeRequest(t, req, http.StatusTemporaryRedirect) + assert.Contains(t, resp.Header().Get("Location"), mockServer.URL+"/authorize") +} From 3db31276553eb1d196a4cf13caa40df0cc07b5de Mon Sep 17 00:00:00 2001 From: Nicolas Date: Tue, 21 Apr 2026 09:22:11 +0200 Subject: [PATCH 14/66] Enhance styling in actions page (#37323) - Adjust workflow graph for better visualization - change summary icon to home icon - use octicon-file-removed for expired artifacts --- routers/web/devtest/mock_actions.go | 4 +- web_src/js/components/RepoActionView.vue | 4 +- web_src/js/components/WorkflowGraph.vue | 63 ++++++++++++++---------- web_src/js/svg.ts | 4 ++ 4 files changed, 44 insertions(+), 31 deletions(-) diff --git a/routers/web/devtest/mock_actions.go b/routers/web/devtest/mock_actions.go index fe12dc3079c..51c13113e59 100644 --- a/routers/web/devtest/mock_actions.go +++ b/routers/web/devtest/mock_actions.go @@ -126,10 +126,10 @@ func MockActionsRunsJobs(ctx *context.Context) { resp.State.Run.Jobs = append(resp.State.Run.Jobs, &actions.ViewJob{ ID: runID * 10, JobID: "job-100", - Name: "job 100", + Name: "job 100 (testsubname)", Status: actions_model.StatusRunning.String(), CanRerun: true, - Duration: "1h", + Duration: "1h23m45s", }) resp.State.Run.Jobs = append(resp.State.Run.Jobs, &actions.ViewJob{ ID: runID*10 + 1, diff --git a/web_src/js/components/RepoActionView.vue b/web_src/js/components/RepoActionView.vue index dbb5426ca78..9877a8fcc2e 100644 --- a/web_src/js/components/RepoActionView.vue +++ b/web_src/js/components/RepoActionView.vue @@ -95,7 +95,7 @@ async function deleteArtifact(name: string) {
- + {{ locale.summary }} @@ -136,7 +136,7 @@ async function deleteArtifact(name: string) { - + {{ artifact.name }} {{ locale.artifactExpired }} diff --git a/web_src/js/components/WorkflowGraph.vue b/web_src/js/components/WorkflowGraph.vue index 06ac1686e68..260f20f1cfb 100644 --- a/web_src/js/components/WorkflowGraph.vue +++ b/web_src/js/components/WorkflowGraph.vue @@ -83,9 +83,11 @@ const saveState = () => { localUserSettings.setJsonObject(settingKeyStates, Object.fromEntries(sortedStates)); }; +const minNodeWidth = 168; +const maxNodeWidth = 232; const nodeWidth = computed(() => { - const maxNameLength = Math.max(...props.jobs.map(j => j.name.length)); - return Math.min(Math.max(140, maxNameLength * 8), 180); + const maxNameLength = Math.max(...props.jobs.map(j => j.name.length), 0); + return Math.min(Math.max(minNodeWidth, maxNameLength * 8), maxNodeWidth); }); const horizontalSpacing = computed(() => nodeWidth.value + 84); @@ -342,8 +344,8 @@ const graphMetrics = computed(() => { }; }) -const nodeHeight = 48; -const verticalSpacing = 88; +const nodeHeight = 52; +const verticalSpacing = 90; const margin = 40; const minScale = 0.3; @@ -589,7 +591,7 @@ function onNodeClick(job: JobNode, event: MouseEvent) { :d="edge.path" fill="none" stroke="var(--color-secondary-alpha-50)" - stroke-width="1.75" + stroke-width="1.5" :class="['node-edge', { 'highlighted-edge': isEdgeHighlighted(edge) }]" /> @@ -608,10 +610,10 @@ function onNodeClick(job: JobNode, event: MouseEvent) { :y="job.y" :width="nodeWidth" :height="nodeHeight" - rx="10" - fill="var(--color-button)" - stroke="var(--color-light-border)" - stroke-width="1.25" + rx="8" + fill="var(--color-box-body)" + stroke="var(--color-secondary)" + stroke-width="1" class="job-rect" /> @@ -619,7 +621,7 @@ function onNodeClick(job: JobNode, event: MouseEvent) { v-if="nodesWithIncomingEdge.has(job.id)" :cx="job.x" :cy="job.y + nodeHeight / 2" - r="6" + r="4.5" class="node-port" /> @@ -627,13 +629,13 @@ function onNodeClick(job: JobNode, event: MouseEvent) { v-if="nodesWithOutgoingEdge.has(job.id)" :cx="job.x + nodeWidth" :cy="job.y + nodeHeight / 2" - r="6" + r="4.5" class="node-port" />
{{ job.name }} @@ -707,7 +709,7 @@ function onNodeClick(job: JobNode, event: MouseEvent) { .graph-container { flex: 1; overflow: hidden; - padding: 12px 16px 20px; + padding: 10px 14px 18px; border-radius: 0 0 var(--border-radius) var(--border-radius); cursor: grab; position: relative; @@ -730,7 +732,7 @@ function onNodeClick(job: JobNode, event: MouseEvent) { } .highlighted-edge { - stroke-width: 2.25 !important; + stroke-width: 2 !important; stroke: var(--color-workflow-edge-hover) !important; } @@ -749,18 +751,20 @@ function onNodeClick(job: JobNode, event: MouseEvent) { width: 100%; height: 100%; display: flex; - align-items: center; - justify-content: space-between; - gap: 4px; - padding-right: 8px; + flex-direction: column; + align-items: flex-start; + justify-content: center; + gap: 1px; + padding: 4px 8px 4px 0; + overflow: hidden; } .job-name { - flex: 1; + width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; - font-size: 11px; + font-size: 12px; font-weight: var(--font-weight-semibold); color: var(--color-text); user-select: none; @@ -768,10 +772,13 @@ function onNodeClick(job: JobNode, event: MouseEvent) { } .job-duration { - font-size: 11px; + font-size: 10px; + line-height: 1.2; color: var(--color-text-light-2); white-space: nowrap; - flex-shrink: 0; + max-width: 100%; + overflow: hidden; + text-overflow: ellipsis; user-select: none; pointer-events: none; } @@ -792,11 +799,13 @@ function onNodeClick(job: JobNode, event: MouseEvent) { .node-port { fill: var(--color-box-body); stroke: var(--color-light-border); - stroke-width: 1.5; + stroke-width: 1.25; + opacity: 0.85; pointer-events: none; } .node-edge { transition: stroke-width 0.2s ease, opacity 0.2s ease; + opacity: 0.75; } diff --git a/web_src/js/svg.ts b/web_src/js/svg.ts index 60c1c763d65..7f8f4c5bdf4 100644 --- a/web_src/js/svg.ts +++ b/web_src/js/svg.ts @@ -32,6 +32,7 @@ import octiconFile from '../../public/assets/img/svg/octicon-file.svg'; import octiconFileCode from '../../public/assets/img/svg/octicon-file-code.svg'; import octiconFileDirectoryFill from '../../public/assets/img/svg/octicon-file-directory-fill.svg'; import octiconFileDirectoryOpenFill from '../../public/assets/img/svg/octicon-file-directory-open-fill.svg'; +import octiconFileRemoved from '../../public/assets/img/svg/octicon-file-removed.svg'; import octiconFileSubmodule from '../../public/assets/img/svg/octicon-file-submodule.svg'; import octiconFileSymlinkFile from '../../public/assets/img/svg/octicon-file-symlink-file.svg'; import octiconFilter from '../../public/assets/img/svg/octicon-filter.svg'; @@ -45,6 +46,7 @@ import octiconGitPullRequestDraft from '../../public/assets/img/svg/octicon-git- import octiconGrabber from '../../public/assets/img/svg/octicon-grabber.svg'; import octiconHeading from '../../public/assets/img/svg/octicon-heading.svg'; import octiconHorizontalRule from '../../public/assets/img/svg/octicon-horizontal-rule.svg'; +import octiconHome from '../../public/assets/img/svg/octicon-home.svg'; import octiconImage from '../../public/assets/img/svg/octicon-image.svg'; import octiconIssueClosed from '../../public/assets/img/svg/octicon-issue-closed.svg'; import octiconIssueOpened from '../../public/assets/img/svg/octicon-issue-opened.svg'; @@ -116,6 +118,7 @@ const svgs = { 'octicon-file-code': octiconFileCode, 'octicon-file-directory-fill': octiconFileDirectoryFill, 'octicon-file-directory-open-fill': octiconFileDirectoryOpenFill, + 'octicon-file-removed': octiconFileRemoved, 'octicon-file-submodule': octiconFileSubmodule, 'octicon-file-symlink-file': octiconFileSymlinkFile, 'octicon-filter': octiconFilter, @@ -129,6 +132,7 @@ const svgs = { 'octicon-grabber': octiconGrabber, 'octicon-heading': octiconHeading, 'octicon-horizontal-rule': octiconHorizontalRule, + 'octicon-home': octiconHome, 'octicon-image': octiconImage, 'octicon-issue-closed': octiconIssueClosed, 'octicon-issue-opened': octiconIssueOpened, From caff989f34413f5a9c24c7db0df9af2c860d3bad Mon Sep 17 00:00:00 2001 From: silverwind Date: Tue, 21 Apr 2026 09:53:19 +0200 Subject: [PATCH 15/66] Fix `relative-time` error and improve global error handler (#37241) 1. Fixes: #37239 2. Enhance global error message to show stack trace on click --------- Signed-off-by: silverwind Signed-off-by: wxiaoguang Co-authored-by: Claude (Opus 4.7) Co-authored-by: wxiaoguang --- templates/devtest/toast-and-message.tmpl | 17 ++++--- web_src/css/modules/message.css | 19 ++++++++ web_src/js/modules/devtest.ts | 7 +++ web_src/js/modules/errors.test.ts | 25 ++++++++++- web_src/js/modules/errors.ts | 45 ++++++++++++------- .../js/webcomponents/relative-time.test.ts | 12 +++++ web_src/js/webcomponents/relative-time.ts | 10 ++--- 7 files changed, 104 insertions(+), 31 deletions(-) diff --git a/templates/devtest/toast-and-message.tmpl b/templates/devtest/toast-and-message.tmpl index c4056b6fc6b..484110ef1bf 100644 --- a/templates/devtest/toast-and-message.tmpl +++ b/templates/devtest/toast-and-message.tmpl @@ -1,11 +1,14 @@ {{template "devtest/devtest-header"}} -
-

Toast

-
- - - - +
+
+
+

Toast

+
+ + + + +
{{template "devtest/devtest-footer"}} diff --git a/web_src/css/modules/message.css b/web_src/css/modules/message.css index d7a6cb8aee1..26f7af792f0 100644 --- a/web_src/css/modules/message.css +++ b/web_src/css/modules/message.css @@ -12,6 +12,25 @@ border-radius: var(--border-radius); } +details.ui.message { + padding: 0; +} + +details.ui.message summary { + padding: 1em 1.5em; +} + +details.ui.message pre { + margin: -1.25em 0 0; + padding: 0.5em 1.5em; + white-space: pre-wrap; +} + +details.ui.message:not(:has(pre)) summary { + list-style: none; + cursor: text; +} + .ui.message:first-child { margin-top: 0; } diff --git a/web_src/js/modules/devtest.ts b/web_src/js/modules/devtest.ts index 7886ff97480..d96df89bae0 100644 --- a/web_src/js/modules/devtest.ts +++ b/web_src/js/modules/devtest.ts @@ -4,6 +4,7 @@ import {registerGlobalInitFunc} from './observer.ts'; import {fomanticQuery} from './fomantic/base.ts'; import {createElementFromHTML} from '../utils/dom.ts'; import {html} from '../utils/html.ts'; +import {showGlobalErrorMessage} from './errors.ts'; type LevelMap = Record Toast | null>; @@ -54,4 +55,10 @@ function initDevtestPage() { export function initDevtest() { registerGlobalInitFunc('initDevtestPage', initDevtestPage); + registerGlobalInitFunc('initDevtestDetailsErrorMessage', () => { + for (let i = 0; i < 2; i++) { + showGlobalErrorMessage('showGlobalErrorMessage single message', 'warning'); + showGlobalErrorMessage('showGlobalErrorMessage message with details', 'error', `detail message 1\nvery lo${'o'.repeat(200)}ng line 2\nline 3`); + } + }); } diff --git a/web_src/js/modules/errors.test.ts b/web_src/js/modules/errors.test.ts index efa114a88d0..df2431f9680 100644 --- a/web_src/js/modules/errors.test.ts +++ b/web_src/js/modules/errors.test.ts @@ -1,4 +1,8 @@ -import {isGiteaError, showGlobalErrorMessage} from './errors.ts'; +import {isGiteaError, processWindowErrorEvent, showGlobalErrorMessage} from './errors.ts'; + +beforeEach(() => { + document.body.innerHTML = '
'; +}); test('isGiteaError', () => { expect(isGiteaError('', '')).toBe(true); @@ -16,7 +20,6 @@ test('isGiteaError', () => { }); test('showGlobalErrorMessage', () => { - document.body.innerHTML = '
'; showGlobalErrorMessage('test msg 1'); showGlobalErrorMessage('test msg 2'); showGlobalErrorMessage('test msg 1'); // duplicated @@ -25,3 +28,21 @@ test('showGlobalErrorMessage', () => { expect(document.body.innerHTML).toContain('>test msg 2<'); expect(document.querySelectorAll('.js-global-error').length).toEqual(2); }); + +test('processWindowErrorEvent renders stack trace in details', () => { + const error = new Error('boom'); + error.stack = `Error: boom\n at fn (${window.location.origin}/assets/js/index.js:1:1)`; + processWindowErrorEvent({error, type: 'error'} as ErrorEvent & PromiseRejectionEvent); + expect(document.querySelector('.js-global-error summary')!.textContent).toContain('JavaScript error: boom'); + expect(document.querySelector('.js-global-error pre')!.textContent).toContain('/assets/js/index.js:1:1'); +}); + +test('processWindowErrorEvent falls back to message without stack', () => { + processWindowErrorEvent({ + error: {message: 'script error'}, type: 'error', + filename: `${window.location.origin}/assets/js/x.js`, lineno: 5, colno: 10, + } as ErrorEvent & PromiseRejectionEvent); + const msgText = document.querySelector('.js-global-error .ui.message')!.textContent; + expect(msgText).toContain('JavaScript error: script error'); + expect(msgText).toContain('@ 5:10'); +}); diff --git a/web_src/js/modules/errors.ts b/web_src/js/modules/errors.ts index 276b498ead7..d4fb549cfed 100644 --- a/web_src/js/modules/errors.ts +++ b/web_src/js/modules/errors.ts @@ -6,25 +6,36 @@ export function errorMessage(err: unknown): string { return (err as Error)?.message || String(err); } -export function showGlobalErrorMessage(msg: string, msgType: Intent = 'error') { - const msgContainer = document.querySelector('.page-content') ?? document.body; - if (!msgContainer) { +export function showGlobalErrorMessage(msg: string, msgType: Intent = 'error', details?: string) { + const parentContainer = document.querySelector('.page-content') ?? document.body; + if (!parentContainer) { alert(`${msgType}: ${msg}`); return; } - const msgCompact = msg.replace(/\W/g, '').trim(); // compact the message to a data attribute to avoid too many duplicated messages - let msgDiv = msgContainer.querySelector(`.js-global-error[data-global-error-msg-compact="${msgCompact}"]`); - if (!msgDiv) { + // compact the message to a data attribute to avoid too many duplicated messages + const msgCompact = `${msgType}-${msg.trim()}`.replace(/[^-\w\u{80}-\u{10FFFF}]+/gu, ''); + let msgContainer = parentContainer.querySelector(`.js-global-error[data-global-error-msg-compact="${msgCompact}"]`); + if (!msgContainer) { const el = document.createElement('div'); - el.innerHTML = html`
`; - msgDiv = el.childNodes[0] as HTMLDivElement; + el.innerHTML = html`
`; + msgContainer = el.childNodes[0] as HTMLDivElement; } + // merge duplicated messages into "the message (count)" format - const msgCount = Number(msgDiv.getAttribute(`data-global-error-msg-count`)) + 1; - msgDiv.setAttribute(`data-global-error-msg-compact`, msgCompact); - msgDiv.setAttribute(`data-global-error-msg-count`, msgCount.toString()); - msgDiv.querySelector('.ui.message')!.textContent = msg + (msgCount > 1 ? ` (${msgCount})` : ''); - msgContainer.prepend(msgDiv); + const msgCount = Number(msgContainer.getAttribute(`data-global-error-msg-count`)) + 1; + msgContainer.setAttribute(`data-global-error-msg-compact`, msgCompact); + msgContainer.setAttribute(`data-global-error-msg-count`, msgCount.toString()); + + const msgElem = msgContainer.querySelector('details')!; + const msgSummary = msgElem.querySelector('summary')!; + msgSummary.textContent = msg + (msgCount > 1 ? ` (${msgCount})` : ''); + if (details) { + let msgDetailsPre = msgElem.querySelector('pre'); + if (!msgDetailsPre) msgDetailsPre = document.createElement('pre'); + msgDetailsPre.textContent = details; + msgElem.append(msgDetailsPre); + } + parentContainer.prepend(msgContainer); } // Detect whether an error originated from Gitea's own scripts, not from @@ -53,9 +64,9 @@ export function processWindowErrorEvent({error, reason, message, type, filename, // Filter out errors from browser extensions or other non-Gitea scripts. if (!isGiteaError(filename ?? '', err?.stack ?? '')) return; - let msg = err?.message ?? message; - if (lineno) msg += ` (${filename} @ ${lineno}:${colno})`; - const dot = msg.endsWith('.') ? '' : '.'; const renderedType = type === 'unhandledrejection' ? 'promise rejection' : type; - showGlobalErrorMessage(`JavaScript ${renderedType}: ${msg}${dot} Open browser console to see more details.`); + let msg = err?.message ?? message; + if (!err?.stack && lineno) msg += ` (${filename} @ ${lineno}:${colno})`; + const dot = msg.endsWith('.') ? '' : '.'; + showGlobalErrorMessage(`JavaScript ${renderedType}: ${msg}${dot} Open browser console to see more details.`, 'error', err?.stack); } diff --git a/web_src/js/webcomponents/relative-time.test.ts b/web_src/js/webcomponents/relative-time.test.ts index 009006c71ba..e20f262ca4b 100644 --- a/web_src/js/webcomponents/relative-time.test.ts +++ b/web_src/js/webcomponents/relative-time.test.ts @@ -109,6 +109,18 @@ test('respects lang from parent element', async () => { expect(getText(el)).toBe('vor 3 Tagen'); }); +test('falls back when navigator.language is invalid', async () => { + vi.spyOn(navigator, 'language', 'get').mockReturnValue('undefined'); + try { + const el = document.createElement('relative-time'); + el.setAttribute('datetime', new Date(Date.now() - 3 * 60 * 1000).toISOString()); + await Promise.resolve(); + expect(getText(el)).toBe('3 minutes ago'); + } finally { + vi.restoreAllMocks(); + } +}); + test('switches to datetime with P1D threshold', async () => { const el = createRelativeTime(new Date(Date.now() - 2 * 24 * 60 * 60 * 1000).toISOString(), { lang: 'en-US', diff --git a/web_src/js/webcomponents/relative-time.ts b/web_src/js/webcomponents/relative-time.ts index e9e668bfc45..e37638b7c4a 100644 --- a/web_src/js/webcomponents/relative-time.ts +++ b/web_src/js/webcomponents/relative-time.ts @@ -258,13 +258,13 @@ class RelativeTime extends HTMLElement { } get #lang(): string { - const lang = this.closest('[lang]')?.getAttribute('lang'); - if (lang) { + for (const candidate of [this.closest('[lang]')?.getAttribute('lang'), navigator.language]) { + if (!candidate) continue; try { - return new Intl.Locale(lang).toString(); - } catch { /* invalid locale, fall through */ } + return String(new Intl.Locale(candidate)); + } catch {} } - return navigator.language ?? 'en'; + return 'en'; } get second(): 'numeric' | '2-digit' | undefined { From 5495b5d1264fde6443566880b0c3c2c84b3450e0 Mon Sep 17 00:00:00 2001 From: chethenry Date: Tue, 21 Apr 2026 04:52:28 -0600 Subject: [PATCH 16/66] When the requested arch rpm is missing fall back to noarch (#37236) This fixes: https://github.com/go-gitea/gitea/issues/37235 It uses the same changeset alpine packages got in: https://github.com/go-gitea/gitea/issues/26691 --------- Co-authored-by: Lunny Xiao Co-authored-by: wxiaoguang --- routers/api/packages/rpm/rpm.go | 51 ++++---- tests/integration/api_packages_rpm_test.go | 129 ++++++++++++++++++--- 2 files changed, 141 insertions(+), 39 deletions(-) diff --git a/routers/api/packages/rpm/rpm.go b/routers/api/packages/rpm/rpm.go index 51cedd2a9f6..d4fdb0affa2 100644 --- a/routers/api/packages/rpm/rpm.go +++ b/routers/api/packages/rpm/rpm.go @@ -9,6 +9,7 @@ import ( "fmt" "io" "net/http" + "net/url" "strings" "time" @@ -220,30 +221,38 @@ func UploadPackageFile(ctx *context.Context) { func DownloadPackageFile(ctx *context.Context) { name := ctx.PathParam("name") version := ctx.PathParam("version") + architecture := ctx.PathParam("architecture") + group := ctx.PathParam("group") - s, u, pf, err := packages_service.OpenFileForDownloadByPackageNameAndVersion( - ctx, - &packages_service.PackageInfo{ - Owner: ctx.Package.Owner, - PackageType: packages_model.TypeRpm, - Name: name, - Version: version, - }, - &packages_service.PackageFileInfo{ - Filename: fmt.Sprintf("%s-%s.%s.rpm", name, version, ctx.PathParam("architecture")), - CompositeKey: ctx.PathParam("group"), - }, - ctx.Req.Method, - ) - if err != nil { - if errors.Is(err, util.ErrNotExist) { - apiError(ctx, http.StatusNotFound, err) - } else { - apiError(ctx, http.StatusInternalServerError, err) - } - return + openForDownload := func(filename string) (io.ReadSeekCloser, *url.URL, *packages_model.PackageFile, error) { + return packages_service.OpenFileForDownloadByPackageNameAndVersion( + ctx, + &packages_service.PackageInfo{ + Owner: ctx.Package.Owner, + PackageType: packages_model.TypeRpm, + Name: name, + Version: version, + }, + &packages_service.PackageFileInfo{ + Filename: filename, + CompositeKey: group, + }, + ctx.Req.Method, + ) } + s, u, pf, err := openForDownload(fmt.Sprintf("%s-%s.%s.rpm", name, version, architecture)) + if errors.Is(err, util.ErrNotExist) && architecture != "noarch" { + s, u, pf, err = openForDownload(fmt.Sprintf("%s-%s.%s.rpm", name, version, "noarch")) + } + + if errors.Is(err, util.ErrNotExist) { + apiError(ctx, http.StatusNotFound, err) + return + } else if err != nil { + apiError(ctx, http.StatusInternalServerError, err) + return + } helper.ServePackageFile(ctx, s, u, pf) } diff --git a/tests/integration/api_packages_rpm_test.go b/tests/integration/api_packages_rpm_test.go index ecde21cc708..493964ebbc3 100644 --- a/tests/integration/api_packages_rpm_test.go +++ b/tests/integration/api_packages_rpm_test.go @@ -32,14 +32,24 @@ import ( func TestPackageRpm(t *testing.T) { defer tests.PrepareTestEnv(t)() + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) packageName := "gitea-test" packageVersion := "1.0.2-1" packageArchitecture := "x86_64" - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) - - base64RpmPackageContent := `H4sICFayB2QCAGdpdGVhLXRlc3QtMS4wLjItMS14ODZfNjQucnBtAO2YV4gTQRjHJzl7wbNhhxVF + // To build an RPM package, it needs tools lik "cpio", it's not easy to do in Golang. + // So here we only use pre-built package contents. And to save space, the content is gzipped and base64 encoded. + rpmContentFromGzipBase64 := func(t testing.TB, s string) []byte { + b, err := base64.StdEncoding.DecodeString(s) + require.NoError(t, err) + zr, err := gzip.NewReader(bytes.NewReader(b)) + require.NoError(t, err) + content, err := io.ReadAll(zr) + require.NoError(t, err) + return content + } + packageRpmGzipBase64 := `H4sICFayB2QCAGdpdGVhLXRlc3QtMS4wLjItMS14ODZfNjQucnBtAO2YV4gTQRjHJzl7wbNhhxVF VNwk2zd2PdvZ9Sxnd3Z3NllNsmF3o6congVFsWFHRWwIImIXfRER0QcRfPBJEXvvBQvWSfZTT0VQ 8TF/MuU33zcz3+zOJGEe73lyuQBRBWKWRzDrEddjuVAkxLMc+lsFUOWfm5bvvReAalWECg/TsivU dyKa0U61aVnl6wj0Uxe4nc8F92hZiaYE8CO/P0r7/Quegr0c7M/AvoCaGZEIWNGUqMHrhhGROIUT @@ -67,14 +77,8 @@ Mu0UFYgZ/bYnuvn/vz4wtCz8qMwsHUvP0PX3tbYFUctAPdrY6tiiDtcCddDECahx7SuVNP5dpmb5 9tMDyaXb7OAlk5acuPn57ss9mw6Wym0m1Fq2cej7tUt2LL4/b8enXU2fndk+fvv57ndnt55/cQob 7tpp/pEjDS7cGPZ6BY430+7danDq6f42Nw49b9F7zp6BiKpJb9s5P0AYN2+L159cnrur636rx+v1 7ae1K28QbMMcqI8CqwIrgwg9nTOp8Oj9q81plUY7ZuwXN8Vvs8wbAAA=` - rpmPackageContent, err := base64.StdEncoding.DecodeString(base64RpmPackageContent) - assert.NoError(t, err) - zr, err := gzip.NewReader(bytes.NewReader(rpmPackageContent)) - assert.NoError(t, err) - - content, err := io.ReadAll(zr) - assert.NoError(t, err) + packageRpmContent := rpmContentFromGzipBase64(t, packageRpmGzipBase64) decodeGzipXML := func(t testing.TB, resp *httptest.ResponseRecorder, v any) { t.Helper() @@ -130,10 +134,10 @@ gpgkey=%sapi/packages/%s/rpm/repository.key`, t.Run("Upload", func(t *testing.T) { url := groupURL + "/upload" - req := NewRequestWithBody(t, "PUT", url, bytes.NewReader(content)) + req := NewRequestWithBody(t, "PUT", url, bytes.NewReader(packageRpmContent)) MakeRequest(t, req, http.StatusUnauthorized) - req = NewRequestWithBody(t, "PUT", url, bytes.NewReader(content)). + req = NewRequestWithBody(t, "PUT", url, bytes.NewReader(packageRpmContent)). AddBasicAuth(user.Name) MakeRequest(t, req, http.StatusCreated) @@ -156,9 +160,9 @@ gpgkey=%sapi/packages/%s/rpm/repository.key`, pb, err := packages.GetBlobByID(t.Context(), pfs[0].BlobID) assert.NoError(t, err) - assert.Equal(t, int64(len(content)), pb.Size) + assert.Equal(t, int64(len(packageRpmContent)), pb.Size) - req = NewRequestWithBody(t, "PUT", url, bytes.NewReader(content)). + req = NewRequestWithBody(t, "PUT", url, bytes.NewReader(packageRpmContent)). AddBasicAuth(user.Name) MakeRequest(t, req, http.StatusConflict) }) @@ -169,12 +173,12 @@ gpgkey=%sapi/packages/%s/rpm/repository.key`, // download the package without the file name req := NewRequest(t, "GET", fmt.Sprintf("%s/package/%s/%s/%s", groupURL, packageName, packageVersion, packageArchitecture)) resp := MakeRequest(t, req, http.StatusOK) - assert.Equal(t, content, resp.Body.Bytes()) + assert.Equal(t, packageRpmContent, resp.Body.Bytes()) // download the package with a file name (it can be anything) req = NewRequest(t, "GET", fmt.Sprintf("%s/package/%s/%s/%s/any-file-name", groupURL, packageName, packageVersion, packageArchitecture)) resp = MakeRequest(t, req, http.StatusOK) - assert.Equal(t, content, resp.Body.Bytes()) + assert.Equal(t, packageRpmContent, resp.Body.Bytes()) }) t.Run("Repository", func(t *testing.T) { @@ -332,7 +336,7 @@ gpgkey=%sapi/packages/%s/rpm/repository.key`, assert.Equal(t, "sha256", p.Checksum.Type) assert.Equal(t, "f1d5d2ffcbe4a7568e98b864f40d923ecca084e9b9bcd5977ed6521c46d3fa4c", p.Checksum.Checksum) assert.Equal(t, "https://gitea.io", p.URL) - assert.EqualValues(t, len(content), p.Size.Package) + assert.EqualValues(t, len(packageRpmContent), p.Size.Package) assert.EqualValues(t, 13, p.Size.Installed) assert.EqualValues(t, 272, p.Size.Archive) assert.Equal(t, fmt.Sprintf("package/%s/%s/%s/%s", packageName, packageVersion, packageArchitecture, fmt.Sprintf("%s-%s.%s.rpm", packageName, packageVersion, packageArchitecture)), p.Location.Href) @@ -744,6 +748,95 @@ gpgkey=%sapi/packages/%s/rpm/repository.key`, }) }) + t.Run("NoArch", func(t *testing.T) { + defer tests.PrintCurrentTest(t)() + + noarchPackageName := "gitea-noarch-test" + noarchPackageVersion := "1.0.0-1" + noarchPackageGzipBase64 := `H4sICKC05mkAA2dpdGVhLW5vYXJjaC10ZXN0LTEuMC4wLTEubm9hcmNoLnJwbQDtmLtrFEEcx+dy` + + `p0ZROYliFMUTLJJiz53HPgbBBwZR0Jgiglo5sztzLt6Lu0uIYmEhFhFUsBUJahd8gHZWKvgnpLES` + + `VIwYo43a6Dm7+zvfhbXsF+ZmP/N7zM5y03wXZt89yyOjbiXqKGHVG6IVnLQ6qt2xcNku2xZG/6wc` + + `WvL70qXbr3PwuAyh4gMz74TnW2YumqJVZl76vQPKrQEeTjn/2swFM6rAb9N61Ezr84sQPwfx9xA/` + + `b8Il6nEpWSgwVz7lrqOZ9oWjqKZSShIQT/k4cHWIAtcJHNsR1OGKSp8w5QcMM+4SiSV1OSY293wi` + + `TAMmmBauL1XoeJ7mXAqhafL6BXzzSd+N2eFP9x8/nHt25u7CBbN49t8/YKZMmTJlypQpU6ZMmTJl` + + `ypTpP1biiXS73Sso8TR+8U1KCOU+mHkXSnyN3HPICc3oh5yeTxL7Jn3A88Brgd8Ab0Q/fJTlZmwC` + + `XgC2gd+h1FfZDbwI9SPAHyB+EPgjxMeAP0O/ceAvED8B/BVYp1xYC1wDXg/nuww8CPvFvlHePG6A` + + `+D3gjcBd4KG0X24d1B9N63Nw3sKxND9XApaQPwQcAm8HVsAMWANz4CrwjpQHrsJ+8D0GnkIcvsfA` + + `C9j/OPBLyL8GPA/xmZj3oj/8OZT4cwij0WStFK+VmiI4JSoKjf8EZdMgevVgRjbqqg1/mEMHxtGR` + + `erupgkhHKkTVqD4xhdLuf27VswLL7VZQbjVrf3mZ9KVX9IZJqkZyaG+j1mypdluF+6KqGhU11R5G` + + `EItXRqKKKf6xNiZOVxsiSW7vF5NqrKV0NDWMqNmfWRixsptYkgx+iV1O/Mn+nldpHSYlq4KCZtRA` + + `lTNRE3E4lDWp6mGjZaUHTWomOtrykdCUKxxgLjTzfKG0J2wqFfeVFjyMzT1CfC255lRRn5HQDT2J` + + `mcDMdQRzeNqL0NBmhEimlTDpnoeV7xGPYSmpZ3vcljQIbYf6SmjJXEwoVT6xpc+k4wkS/7fSC97t` + + `xvcCFbdcTO92X57apoHNSquLs6s3b3s0uHXPpes77+yZnp5eaa7m3PxbJ3YYvwFme3wbyRUAAA==` + noarchRpmPackageContent := rpmContentFromGzipBase64(t, noarchPackageGzipBase64) + // Upload the noarch RPM + req := NewRequestWithBody(t, "PUT", groupURL+"/upload", bytes.NewReader(noarchRpmPackageContent)).AddBasicAuth(user.Name) + MakeRequest(t, req, http.StatusCreated) + + // The noarch package should appear in primary.xml when any arch is requested. + // At this point the group contains the existing x86_64 package + this noarch one. + req = NewRequest(t, "GET", groupURL+"/repodata/primary.xml.gz") + resp := MakeRequest(t, req, http.StatusOK) + + type PackageSummary struct { + Name string `xml:"name"` + Architecture string `xml:"arch"` + } + type PrimaryMetadata struct { + XMLName xml.Name `xml:"metadata"` + PackageCount int `xml:"packages,attr"` + Packages []PackageSummary `xml:"package"` + } + + var primary PrimaryMetadata + decodeGzipXML(t, resp, &primary) + + // Both the arch-specific package uploaded earlier and the noarch one must be present. + assert.Equal(t, 2, primary.PackageCount) + assert.Len(t, primary.Packages, 2) + + archNames := make([]string, 0, len(primary.Packages)) + for _, p := range primary.Packages { + archNames = append(archNames, p.Architecture) + } + assert.Contains(t, archNames, packageArchitecture) // x86_64 from the Upload subtest + assert.Contains(t, archNames, "noarch") + + // noarch package must be downloadable regardless of the arch path used. + for _, arch := range []string{"noarch", "x86_64", "aarch64", "my_arch"} { + req = NewRequest(t, "GET", fmt.Sprintf( + "%s/package/%s/%s/%s", + groupURL, noarchPackageName, noarchPackageVersion, arch, + )) + MakeRequest(t, req, http.StatusOK) + } + + // Clean up: delete via the canonical noarch path. + req = NewRequest(t, "DELETE", fmt.Sprintf( + "%s/package/%s/%s/noarch", + groupURL, noarchPackageName, noarchPackageVersion, + )).AddBasicAuth(user.Name) + MakeRequest(t, req, http.StatusNoContent) + + // After deletion, the noarch package must no longer be reachable via any arch. + for _, arch := range []string{"noarch", "x86_64", "aarch64"} { + req = NewRequest(t, "GET", fmt.Sprintf( + "%s/package/%s/%s/%s", + groupURL, noarchPackageName, noarchPackageVersion, arch, + )) + MakeRequest(t, req, http.StatusNotFound) + } + + // The x86_64 package from the Upload subtest must still be present. + req = NewRequest(t, "GET", groupURL+"/repodata/primary.xml.gz") + resp = MakeRequest(t, req, http.StatusOK) + + var primaryAfter PrimaryMetadata + decodeGzipXML(t, resp, &primaryAfter) + assert.Equal(t, 1, primaryAfter.PackageCount) + assert.Equal(t, packageArchitecture, primaryAfter.Packages[0].Architecture) + }) + t.Run("Delete", func(t *testing.T) { defer tests.PrintCurrentTest(t)() @@ -765,7 +858,7 @@ gpgkey=%sapi/packages/%s/rpm/repository.key`, t.Run("UploadSign", func(t *testing.T) { defer tests.PrintCurrentTest(t)() url := groupURL + "/upload?sign=true" - req := NewRequestWithBody(t, "PUT", url, bytes.NewReader(content)). + req := NewRequestWithBody(t, "PUT", url, bytes.NewReader(packageRpmContent)). AddBasicAuth(user.Name) MakeRequest(t, req, http.StatusCreated) From aee6628bf527ba53ee812cb3328fc9c81ab7d51b Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Tue, 21 Apr 2026 23:58:32 +0800 Subject: [PATCH 17/66] Fix URL related escaping for oauth2 (#37334) Follow up #37327. See the comments. * Root problem: the design of OAuth2 providers is a mess, the display name is used as provider's name and used in the URL directly * The regressions: * When trying to fix https://github.com/go-gitea/gitea/issues/36409 , it introduced inconsistent URL escaping for the "path" part. * This fix: always use "path escaping" for the path part, add more tests to cover all escaping cases. Now, frontend "pathEscape" and "pathEscapeSegments" generate exactly the same result as backend. --- models/auth/oauth2.go | 2 +- modules/templates/helper_test.go | 19 ++++++-- modules/util/util_test.go | 7 +++ routers/web/auth/auth.go | 2 +- routers/web/auth/auth_test.go | 19 ++++---- routers/web/auth/oauth.go | 4 +- services/context/base_path.go | 8 ++-- services/context/context_response.go | 11 +++-- .../user/auth/external_auth_methods.tmpl | 3 +- .../user/settings/security/accountlinks.tmpl | 2 +- tests/integration/oauth_test.go | 46 +++++++++++++++---- web_src/js/features/admin/common.ts | 4 +- web_src/js/utils.test.ts | 7 --- web_src/js/utils.ts | 9 ---- web_src/js/utils/url.test.ts | 22 +++++++-- web_src/js/utils/url.ts | 30 +++++++++++- 16 files changed, 135 insertions(+), 60 deletions(-) diff --git a/models/auth/oauth2.go b/models/auth/oauth2.go index 846c386a20c..0bc2b517111 100644 --- a/models/auth/oauth2.go +++ b/models/auth/oauth2.go @@ -627,7 +627,7 @@ func GetActiveOAuth2SourceByAuthName(ctx context.Context, name string) (*Source, } if !has { - return nil, fmt.Errorf("oauth2 source not found, name: %q", name) + return nil, util.NewNotExistErrorf("oauth2 source not found, name: %q", name) } return authSource, nil diff --git a/modules/templates/helper_test.go b/modules/templates/helper_test.go index cf1db324768..c21c20efff9 100644 --- a/modules/templates/helper_test.go +++ b/modules/templates/helper_test.go @@ -5,6 +5,7 @@ package templates import ( "html/template" + "net/url" "strings" "testing" @@ -169,9 +170,21 @@ func TestQueryBuild(t *testing.T) { }) } +const queryNonASCII = " !\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~" // all non-letter & non-number chars + func TestQueryEscape(t *testing.T) { // this test is a reference for "urlQueryEscape" in JS - in := "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~" // all non-letter & non-number chars - expected := "%21%22%23%24%25%26%27%28%29%2A%2B%2C-.%2F%3A%3B%3C%3D%3E%3F%40%5B%5C%5D%5E_%60%7B%7C%7D~" - assert.Equal(t, expected, string(queryEscape(in))) + // Special case for space encoding: + // * RFC 3986: Uniform Resource Identifier (URI): %20 + // * WHATWG HTML: application/x-www-form-urlencoded: + + // * JavaScript: encodeURIComponent() uses "%20". URLSearchParams uses "+" + // * Golang: QueryEscape uses "+" + expected := "+%21%22%23%24%25%26%27%28%29%2A%2B%2C-.%2F%3A%3B%3C%3D%3E%3F%40%5B%5C%5D%5E_%60%7B%7C%7D~" + assert.Equal(t, expected, url.QueryEscape(queryNonASCII)) +} + +func TestPathEscape(t *testing.T) { + // this test is a reference for "pathEscape" in JS + expected := "%20%21%22%23$%25&%27%28%29%2A+%2C-.%2F:%3B%3C=%3E%3F@%5B%5C%5D%5E_%60%7B%7C%7D~" + assert.Equal(t, expected, url.PathEscape(queryNonASCII)) } diff --git a/modules/util/util_test.go b/modules/util/util_test.go index ec8b738e543..9decf90f676 100644 --- a/modules/util/util_test.go +++ b/modules/util/util_test.go @@ -184,3 +184,10 @@ func TestOptionalArg(t *testing.T) { assert.Equal(t, 42, bar(nil)) assert.Equal(t, 100, bar(nil, 100)) } + +func TestPathEscapeSegments(t *testing.T) { + assert.Equal(t, "a", PathEscapeSegments("a")) + assert.Equal(t, "a/b", PathEscapeSegments("a/b")) + assert.Equal(t, "a/b%20c", PathEscapeSegments("a/b c")) + assert.Equal(t, "a/b+c", PathEscapeSegments("a/b+c")) +} diff --git a/routers/web/auth/auth.go b/routers/web/auth/auth.go index eb2045781dd..1baa0225217 100644 --- a/routers/web/auth/auth.go +++ b/routers/web/auth/auth.go @@ -230,7 +230,7 @@ func performAutoLoginOAuth2(ctx *context.Context, data *preparedSignInData) bool return false } - skipToOAuthURL := setting.AppSubURL + "/user/oauth2/" + url.QueryEscape(data.oauth2Providers[0].DisplayName()) + skipToOAuthURL := setting.AppSubURL + "/user/oauth2/" + url.PathEscape(data.oauth2Providers[0].DisplayName()) if redirectTo := ctx.FormString("redirect_to"); redirectTo != "" { skipToOAuthURL += "?redirect_to=" + url.QueryEscape(redirectTo) } diff --git a/routers/web/auth/auth_test.go b/routers/web/auth/auth_test.go index 943085a9635..a06e209e4f4 100644 --- a/routers/web/auth/auth_test.go +++ b/routers/web/auth/auth_test.go @@ -4,6 +4,7 @@ package auth import ( + "html/template" "net/http" "net/http/httptest" "net/url" @@ -67,15 +68,15 @@ func TestWebAuthOAuth2(t *testing.T) { defer test.MockVariableValue(&setting.OAuth2Client.EnableAutoRegistration, true)() _ = oauth2.Init(t.Context()) - addOAuth2Source(t, "dummy-auth-source", oauth2.Source{}) + addOAuth2Source(t, "dummy+auth's source", oauth2.Source{}) t.Run("OAuth2MissingField", func(t *testing.T) { defer test.MockVariableValue(&gothic.CompleteUserAuth, func(res http.ResponseWriter, req *http.Request) (goth.User, error) { - return goth.User{Provider: "dummy-auth-source", UserID: "dummy-user"}, nil + return goth.User{Provider: "dummy+auth's source", UserID: "dummy-user"}, nil })() mockOpt := contexttest.MockContextOption{SessionStore: session.NewMockMemStore("dummy-sid")} - ctx, resp := contexttest.MockContext(t, "/user/oauth2/dummy-auth-source/callback?code=dummy-code", mockOpt) - ctx.SetPathParam("provider", "dummy-auth-source") + ctx, resp := contexttest.MockContext(t, "/user/oauth2/..../callback?code=dummy-code", mockOpt) + ctx.SetPathParamRaw("provider", "dummy+auth%27s%20source") SignInOAuthCallback(ctx) assert.Equal(t, http.StatusSeeOther, resp.Code) assert.Equal(t, "/user/link_account", test.RedirectURL(resp)) @@ -83,13 +84,13 @@ func TestWebAuthOAuth2(t *testing.T) { // then the user will be redirected to the link account page, and see a message about the missing fields ctx, _ = contexttest.MockContext(t, "/user/link_account", mockOpt) LinkAccount(ctx) - assert.EqualValues(t, "auth.oauth_callback_unable_auto_reg:dummy-auth-source,email", ctx.Data["AutoRegistrationFailedPrompt"]) + assert.Equal(t, template.HTML("auth.oauth_callback_unable_auto_reg:dummy+auth's source,email"), ctx.Data["AutoRegistrationFailedPrompt"]) }) t.Run("OAuth2CallbackError", func(t *testing.T) { mockOpt := contexttest.MockContextOption{SessionStore: session.NewMockMemStore("dummy-sid")} - ctx, resp := contexttest.MockContext(t, "/user/oauth2/dummy-auth-source/callback", mockOpt) - ctx.SetPathParam("provider", "dummy-auth-source") + ctx, resp := contexttest.MockContext(t, "/user/oauth2/...../callback", mockOpt) + ctx.SetPathParamRaw("provider", "dummy+auth%27s%20source") SignInOAuthCallback(ctx) assert.Equal(t, http.StatusSeeOther, resp.Code) assert.Equal(t, "/user/login", test.RedirectURL(resp)) @@ -112,8 +113,8 @@ func TestWebAuthOAuth2(t *testing.T) { assert.Equal(t, expectedRedirect, test.RedirectURL(resp)) } } - testSignIn(t, "/user/login", http.StatusSeeOther, "/user/oauth2/dummy-auth-source") - testSignIn(t, "/user/login?redirect_to=/", http.StatusSeeOther, "/user/oauth2/dummy-auth-source?redirect_to=%2F") + testSignIn(t, "/user/login", http.StatusSeeOther, "/user/oauth2/dummy+auth%27s%20source") + testSignIn(t, "/user/login?redirect_to=/", http.StatusSeeOther, "/user/oauth2/dummy+auth%27s%20source?redirect_to=%2F") *enablePassword, *enableOpenID, *enablePasskey = true, false, false testSignIn(t, "/user/login", http.StatusOK, "") diff --git a/routers/web/auth/oauth.go b/routers/web/auth/oauth.go index e3f7e382424..8645aedbdee 100644 --- a/routers/web/auth/oauth.go +++ b/routers/web/auth/oauth.go @@ -36,9 +36,7 @@ import ( // SignInOAuth handles the OAuth2 login buttons func SignInOAuth(ctx *context.Context) { - // the provider is escaped by backend QueryEscape and frontend urlQueryEscape - // so always use QueryUnescape to decode it - authName, _ := url.QueryUnescape(ctx.PathParamRaw("provider")) + authName := ctx.PathParam("provider") authSource, err := auth.GetActiveOAuth2SourceByAuthName(ctx, authName) if err != nil { ctx.ServerError("SignIn", err) diff --git a/services/context/base_path.go b/services/context/base_path.go index 63e60c8654e..8c353f7acaf 100644 --- a/services/context/base_path.go +++ b/services/context/base_path.go @@ -44,9 +44,9 @@ func (b *Base) PathParamInt(p string) int { // SetPathParam set request path params into routes func (b *Base) SetPathParam(name, value string) { - if strings.HasPrefix(name, ":") { - setting.PanicInDevOrTesting("path param should not start with ':'") - name = name[1:] - } chi.RouteContext(b).URLParams.Add(name, url.PathEscape(value)) } + +func (b *Base) SetPathParamRaw(name, value string) { + chi.RouteContext(b).URLParams.Add(name, value) +} diff --git a/services/context/context_response.go b/services/context/context_response.go index d057f8d41eb..1fd7a0b447f 100644 --- a/services/context/context_response.go +++ b/services/context/context_response.go @@ -22,6 +22,7 @@ import ( "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/templates" + "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web/middleware" ) @@ -143,11 +144,9 @@ func (ctx *Context) NotFound(logErr error) { } func (ctx *Context) notFoundInternal(logMsg string, logErr error) { + // TODO: it's safe to show the error message to end users if the error is fully controlled by our error system if logErr != nil { log.Log(2, log.DEBUG, "%s: %v", logMsg, logErr) - if !setting.IsProd { - ctx.Data["ErrorMsg"] = logErr - } } // response simple message if Accept isn't text/html @@ -166,11 +165,17 @@ func (ctx *Context) notFoundInternal(logMsg string, logErr error) { ctx.Data["IsRepo"] = ctx.Repo.Repository != nil ctx.Data["Title"] = "Page Not Found" + ctx.Data["ErrorMsg"] = "" // FIXME: the template never renders this message, need to fix in the future (and show safe messages to end users) ctx.HTML(http.StatusNotFound, "status/404") } // ServerError displays a 500 (Internal Server Error) page and prints the given error, if any. +// If the error is controlled by our error system, a related 404 page can be displayed instead. func (ctx *Context) ServerError(logMsg string, logErr error) { + if errors.Is(logErr, util.ErrNotExist) { + ctx.notFoundInternal(logMsg, logErr) + return + } ctx.serverErrorInternal(logMsg, logErr) } diff --git a/templates/user/auth/external_auth_methods.tmpl b/templates/user/auth/external_auth_methods.tmpl index c23cab65657..119be95d8bb 100644 --- a/templates/user/auth/external_auth_methods.tmpl +++ b/templates/user/auth/external_auth_methods.tmpl @@ -1,7 +1,6 @@
{{range $provider := .OAuth2Providers}} - {{/* use QueryEscape for consistent with frontend urlQueryEscape, it is right for a path component */}} - {{end}} diff --git a/templates/user/settings/security/accountlinks.tmpl b/templates/user/settings/security/accountlinks.tmpl index 89228e1ae80..2fb1784b415 100644 --- a/templates/user/settings/security/accountlinks.tmpl +++ b/templates/user/settings/security/accountlinks.tmpl @@ -9,7 +9,7 @@